<jupyter_start><jupyter_text>Parsing a FSM spec in a Python string  Reference * [SIS: A System for Sequential Circuit Synthesis, p.39](https://www2.eecs.berkeley.edu/Pubs/TechRpts/1992/ERL-92-41.pdf)  Extract describing the KISS syntax for specifying FSM >  Finite State Machine Descriptions>A sequential circuit can be specified in  Berkeley Logic Interchange Format (BLIF) logic form, as a finite state machine, or both. An fsm-description is used to insert a finite state machine description of the current model. It is intended to represent the same sequential circuit as the current model (which contains logic), but in FSM form. The format of an fsm-description is:>```.start-kiss.i .o [.p ][.s ][.r ]       .end-kiss```>* num-inputs is the number of inputs to the FSM, which should agree with the number of inputs in the .inputs construct for the current model.>* num-outputs is the number of outputs of the FSM, which should agree with the number of outputs in the .outputs construct for the current model.>* num-terms is the number of ```"   "``` 4-tuples that follow in the FSM description.>* num-states is the number of distinct states that appear in ```""``` and ```""``` columns.>* reset-state is the symbolic name for the reset state for the FSM; it should appear somewhere in the ```""``` column.>* input is a sequence of num-inputs members of (0, 1, -}.>* output is a sequence of num-outputs members of (0, 1, -}.>* current-state and next-state are symbolic names for the current state and next state transitions of the FSM.  To do  * Add handling of input wildcards `-` and state `*` wildcards to KISS processing* Possibly add `.i`, `.o`, `KISS` constructs* Generate `dot` file from `KISS` format to create `graphviz` diagram<jupyter_code>from collections import OrderedDict
from math import ceil, log

import numpy as np
import  pandas as pd<jupyter_output><empty_output><jupyter_text>FSM spec<jupyter_code>fsm_spec = """
.start-kiss
.i 2
.o 3
00    S0    S1    000
01    S0    S5    000
00    S1    S2    001
01    S1    S0    001
00    S2    S3    000
01    S2    S1    000
00    S3    S4    010
01    S3    S2    010
00    S4    S3    000
01    S4    S5    000
00    S5    S0    100
01    S5    S4    100
.end-kiss
"""

fsm_config = [i for i in fsm_spec.split('\n')[1:-1] if i.startswith(".")]
print(fsm_config)
assert fsm_config[0]=='.start-kiss'
assert fsm_config[-1]=='.end-kiss'
fsm_spec = [i for i in fsm_spec.split('\n')[1:-1] if not i.startswith(".")]
fsm_spec
fsm_spec = [line.split() for line in fsm_spec]
fsm_spec
# Get rid of any irregular spacing
fsm_spec_list = [[' '.join(entry for entry in line)] for line in fsm_spec]
fsm_spec_list<jupyter_output><empty_output><jupyter_text>Number of inputs and outputs<jupyter_code>nmbr_inputs = len(fsm_spec[0][0])
nmbr_outputs = len(fsm_spec[0][-1])
nmbr_inputs, nmbr_outputs<jupyter_output><empty_output><jupyter_text>List of states<jupyter_code>state_names = set([line[1] for line in fsm_spec])
state_names<jupyter_output><empty_output><jupyter_text>Number of unique states<jupyter_code>nmbr_states = len(state_names)
nmbr_states<jupyter_output><empty_output><jupyter_text>Number of state encoding bits14<jupyter_code>state_bits = ceil(log(len(state_names), 2))
state_bits<jupyter_output><empty_output><jupyter_text>Check for duplicate transitions in fsm_spec<jupyter_code>unique_transitions = set([line[0] for line in fsm_spec_list])
unique_transitions
nmbr_transitions = len(fsm_spec)
repeated_transitions = nmbr_transitions - len(unique_transitions)
nmbr_transitions, repeated_transitions<jupyter_output><empty_output><jupyter_text>----  State transition ordered dict and table<jupyter_code>from collections import OrderedDict

state_transition = OrderedDict()
state_transition['inputs'] = [line[0] for line in fsm_spec]
state_transition['present_state'] = [line[1] for line in fsm_spec]
state_transition['next_state'] = [line[2] for line in fsm_spec]
state_transition['outputs'] = [line[3] for line in fsm_spec]

### State transition table
std_df = pd.DataFrame(state_transition)
std_df
state_codes = {state_name:format(i, '0{}b'.format(state_bits))
                  for i, state_name in enumerate(sorted(state_names))}
state_codes
std_df['present_state'][0], state_codes[std_df['present_state'][0]]
ordered_state_names = {str(i):state for i,state in enumerate(sorted(state_names))}
ordered_state_names
std_df['next_state_code'] = std_df['next_state'].map(state_codes)
std_df = std_df.sort_values('inputs')

std_df.reset_index(std_df.index, drop=True, inplace=True)
std_df<jupyter_output><empty_output><jupyter_text>Add reset to all states<jupyter_code>resets = {'10', '11'}
for reset in resets:
    reset_transitions = [{'inputs': reset,
                          'present_state': std_df['present_state'][i], 
                          'next_state': 'S0',
                          'outputs': '000',
                          'next_state_code': '000'}
                         for i in range(nmbr_states)]
    std_df = std_df.append(reset_transitions, ignore_index=True)
std_df
std_df['next_state_code'][0]
std_df['present_state_code'] = std_df['present_state'].map(state_codes)
std_df
with open('fsm.dot','w') as f:
    f.write("digraph {\n" +
            "    graph [fontsize=10 splines=true overlap=false]\n" +
            "    edge  [fontsize=10 fontname=\"helvetica\"]\n" +
            "    node  [fontsize=10 fontname=\"helvetica\" nodesep=2.0]\n" +
            "    ratio=auto\n")
    for i in state_codes:
        f.write(('    \"' + i + ' &#8260; ' + state_codes[i]) + '\"\n')
    for index in range(len(std_df)):
        f.write('    \"' + std_df['present_state'][index] + ' &#8260; ' +
                std_df['present_state_code'][index] + '\" -> \"' + 
                std_df['next_state'][index] + ' &#8260; ' +
                std_df['next_state_code'][index] +"\" [label=\"" +
                std_df['inputs'][index] + " &#8260; " + 
                std_df['outputs'][index] + "\" arrowhead = \"vee\"]\n")
    f.write("}")

with open('fsm.dot','r') as f:
    s = f.read()
print(s)
import os
import pygraphviz as pgv
from IPython.display import Image, display
B=pgv.AGraph('fsm.dot')
B.layout(prog='dot')
B.draw('fsm.png')
display(Image(filename='fsm.png'))
os.system("rm -rf fsm.png fsm.dot")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12802658648520335, 'fraction_numerical': 0.025320462098433295, 'mean_word_length': 3.945226917057903, 'pattern_counts': {'":': 0, '<': 37, '<?xml version=': 0, '>': 49, 'https://': 1, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '9', 'dir': 'jupyter-structured-clean-dedup', 'id': '559886', 'license': 'MIT', 'n_tokens_mistral': 2274, 'n_tokens_neox': 2186, 'n_words': 590, 'path': 'debug/.ipynb_checkpoints/fsm_kiss_parser-checkpoint.ipynb', 'repo_name': 'yunqu/PYNQ-Debug-Notebooks', 'size': '6319'}