""" Modern UVM Testbench Generator UI Clean, Professional Dark Theme - Inspired by VS Code, GitHub, Modern React Dashboards """ import streamlit as st import logging import tempfile import os import zipfile import io from pathlib import Path from datetime import datetime import json import pandas as pd logging.basicConfig(level=logging.INFO) logger = logging.getLogger("uvmgen-modern") st.set_page_config( page_title="UVM Generator", page_icon="⚡", layout="wide", initial_sidebar_state="expanded" ) st.markdown(""" """, unsafe_allow_html=True) EXAMPLES = { "UART": """design_name: uart clock_reset: clock: clk reset: rst_n interfaces: - name: wb signals: - name: wb_cyc direction: input - name: wb_stb direction: input - name: wb_we direction: input - name: wb_addr direction: input width: 3 - name: wb_data_o direction: output width: 8 - name: wb_data_i direction: input width: 8 - name: wb_ack direction: output - name: uart signals: - name: uart_tx direction: output - name: uart_rx direction: input - name: cts_n direction: input - name: rts_n direction: output - name: uart_intr direction: output registers: - name: RBR_THR address: 0x0 fields: - name: data bits: 7:0 - name: IER address: 0x1 fields: - name: erbfi bits: '0' - name: etbei bits: '1' - name: LCR address: 0x3 fields: - name: wls bits: 1:0 - name: dlab bits: '7' - name: LSR address: 0x5 fields: - name: dr bits: '0' - name: thre bits: '5' protocol: uart""", "SPI": """design_name: spi_controller clock_reset: clock: clk reset: rst_n interfaces: - name: apb signals: - name: psel direction: input - name: penable direction: input - name: pwrite direction: input - name: paddr direction: input width: 8 - name: pwdata direction: input width: 32 - name: prdata direction: output width: 32 - name: pready direction: output - name: spi signals: - name: sclk direction: output - name: mosi direction: output - name: miso direction: input - name: cs_n direction: output width: 4 registers: - name: CTRL address: 0x0 - name: TXDATA address: 0x4 - name: RXDATA address: 0x8 - name: STATUS address: 0xC protocol: spi""", "I2C": """design_name: i2c_master clock_reset: clock: clk reset: rst_n interfaces: - name: axi4lite signals: - name: awvalid direction: input - name: awready direction: output - name: awaddr direction: input width: 16 - name: wvalid direction: input - name: wready direction: output - name: wdata direction: input width: 32 - name: rvalid direction: output - name: rready direction: input - name: rdata direction: output width: 32 - name: i2c signals: - name: scl direction: inout - name: sda direction: inout registers: - name: PRESCALE address: 0x0 - name: CTRL address: 0x4 - name: TX_RX address: 0x8 - name: CMD_STATUS address: 0xC protocol: i2c""" } MODEL_CONFIGS = { "v2": { "name": "ML-Driven (Recommended)", "desc": "Advanced RL with pattern recognition", "features": ["Reinforcement Learning", "Experience Replay", "Pattern Mining", "UVM Compliance"] }, "hybrid": { "name": "Hybrid Retrieval", "desc": "Similarity + templates", "features": ["Similarity Search", "Template Matching"] }, "template": { "name": "Template-Based", "desc": "Fast deterministic generation", "features": ["Fastest", "Deterministic"] } } RL_STRATEGIES = { "ucb": "Upper Confidence Bound", "softmax": "Softmax (Boltzmann)", "epsilon_greedy": "Epsilon-Greedy", "thompson": "Thompson Sampling" } if 'last_result' not in st.session_state: st.session_state.last_result = None if 'generated_files' not in st.session_state: st.session_state.generated_files = {} if 'log_output' not in st.session_state: st.session_state.log_output = [] if 'ml_stats' not in st.session_state: st.session_state.ml_stats = None if 'run_id' not in st.session_state: st.session_state.run_id = 0 with st.sidebar: st.markdown(""" """, unsafe_allow_html=True) with st.expander("Specification", expanded=True): st.markdown('', unsafe_allow_html=True) selected_protocol = st.selectbox( "Protocol", list(EXAMPLES.keys()), index=0, label_visibility="collapsed", key="p_sel" ) st.markdown('', unsafe_allow_html=True) design_name = st.text_input( "Design Name", value=f"{selected_protocol.lower()}_controller", label_visibility="collapsed", key="d_nm" ) st.markdown('
', unsafe_allow_html=True) st.markdown('', unsafe_allow_html=True) col_c1, col_c2 = st.columns(2) with col_c1: clk_freq = st.number_input("Clock (MHz)", value=100.0, min_value=1.0, step=10.0, key="clk_f") with col_c2: rst_polarity = st.selectbox("Reset", ["Active Low", "Active High"], index=0, key="rst_p") st.markdown('
', unsafe_allow_html=True) with st.expander("AI Configuration", expanded=True): st.markdown('', unsafe_allow_html=True) model_mode = st.radio( "Mode", list(MODEL_CONFIGS.keys()), index=0, format_func=lambda k: MODEL_CONFIGS[k]["name"], label_visibility="collapsed", key="m_mode" ) st.caption(MODEL_CONFIGS[model_mode]["desc"]) for feat in MODEL_CONFIGS[model_mode]["features"]: st.markdown(f'{feat}', unsafe_allow_html=True) if model_mode == "v2": st.markdown('
', unsafe_allow_html=True) st.markdown('', unsafe_allow_html=True) rl_strategy = st.selectbox( "Exploration Strategy", list(RL_STRATEGIES.keys()), index=0, format_func=lambda k: RL_STRATEGIES[k], key="rl_s" ) enable_learning = st.checkbox("Continuous Learning", value=True, key="l_en") strict_uvm = st.checkbox("Strict UVM Compliance", value=True, key="uvm_s") st.markdown('
', unsafe_allow_html=True) with st.expander("Execution", expanded=True): st.markdown('', unsafe_allow_html=True) max_iterations = st.slider( "Iterations", min_value=1, max_value=10, value=1, key="m_iter" ) enable_sim = st.checkbox("Run Simulation", value=False, key="s_en") enable_val = st.checkbox("Validate Output", value=True, key="v_en") st.markdown('
', unsafe_allow_html=True) generate_btn = st.button( "Generate Testbench", type="primary", use_container_width=True, key="r_btn" ) col_a, col_b = st.columns(2) with col_a: validate_btn = st.button("Validate", use_container_width=True, key="v_btn") with col_b: export_btn = st.button("Export", use_container_width=True, key="e_btn") st.markdown('
', unsafe_allow_html=True) with st.expander("Resources", expanded=False): st.markdown('', unsafe_allow_html=True) st.markdown("""
UVM Engine 65%
AI Credits 82%
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) st.markdown('', unsafe_allow_html=True) st.markdown("""
All Systems Operational
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) st.caption("Sai Kumar Taraka") st.markdown("""
Ready
""", unsafe_allow_html=True) tab_spec, tab_gen, tab_results, tab_analysis, tab_coverage, tab_logs = st.tabs([ "Specification", "Generation", "Results", "Analysis", "Coverage", "Logs" ]) with tab_spec: col_edit, col_summary = st.columns([2, 1]) with col_edit: st.markdown('
YAML Specification Editor
', unsafe_allow_html=True) spec_text = st.text_area( "Edit Specification", value=EXAMPLES[selected_protocol], height=520, key="s_edit", label_visibility="collapsed" ) cols = st.columns(4) with cols[0]: st.markdown(f"""
{selected_protocol}
Protocol
""", unsafe_allow_html=True) with cols[1]: st.markdown(f"""
{design_name}
Design
""", unsafe_allow_html=True) with cols[2]: st.markdown(f"""
{model_mode.upper()}
Engine
""", unsafe_allow_html=True) with cols[3]: st.markdown(f"""
READY
Status
""", unsafe_allow_html=True) with col_summary: st.markdown('
Specification Summary
', unsafe_allow_html=True) import yaml try: spec_dict = yaml.safe_load(spec_text) cols_s = st.columns(2) with cols_s[0]: st.metric("Interfaces", len(spec_dict.get('interfaces', []))) total_sigs = sum(len(i.get('signals', [])) for i in spec_dict.get('interfaces', [])) st.metric("Signals", total_sigs) with cols_s[1]: st.metric("Registers", len(spec_dict.get('registers', []))) total_fields = sum(len(r.get('fields', [])) for r in spec_dict.get('registers', [])) st.metric("Fields", total_fields) st.markdown('
', unsafe_allow_html=True) st.markdown('
Interface Configuration
', unsafe_allow_html=True) for iface in spec_dict.get('interfaces', []): with st.expander(f"🔌 {iface.get('name')}"): for sig in iface.get('signals', []): name = sig.get('name') direction = sig.get('direction') width = sig.get('width', 1) dir_color = "#3fb950" if direction == "input" else "#58a6ff" st.markdown(f"""
{name} {direction} [{width}]
""", unsafe_allow_html=True) except Exception as e: st.error(f"Parse Error: {e}") with tab_gen: st.markdown('
Generation Control
', unsafe_allow_html=True) cols_g = st.columns(4) with cols_g[0]: st.markdown(f"""
{model_mode.upper()}
Engine
""", unsafe_allow_html=True) with cols_g[1]: st.markdown(f"""
{max_iterations}
Iterations
""", unsafe_allow_html=True) with cols_g[2]: st.markdown(f"""
{'ON' if enable_learning else 'OFF'}
Learning
""", unsafe_allow_html=True) with cols_g[3]: st.markdown(f"""
{'ON' if strict_uvm else 'OFF'}
UVM Strict
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) st.markdown('
Verification Pipeline
', unsafe_allow_html=True) pipeline_cols = st.columns(6) pipeline_steps = [ ("Spec Parse", True, "success"), ("Feature Ext", True, "success"), ("ML Generation", False, "pending"), ("UVM Validation", False, "pending"), ("Coverage Analysis", False, "pending"), ("Export", False, "pending") ] for i, (step, is_done, status) in enumerate(pipeline_steps): with pipeline_cols[i]: dot_class = status bg_color = "#1c2128" if is_done else "#0d1117" border_color = "#3fb950" if is_done else "#21262d" text_color = "#3fb950" if is_done else "#8b949e" st.markdown(f"""
{step}
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) col_info1, col_info2 = st.columns(2) with col_info1: st.markdown("""
Coverage Strategy
Recommended: Add directed tests for reset values, bus protocols, and register access patterns.
""", unsafe_allow_html=True) with col_info2: st.markdown("""
Assertion Generator
AI can generate protocol-specific assertions for signal timing, handshakes, and data integrity.
""", unsafe_allow_html=True) with tab_results: if st.session_state.last_result: result = st.session_state.last_result eval_metrics = result.get('evaluation', {}) st.markdown('
Generation Metrics
', unsafe_allow_html=True) cols_m = st.columns(6) metrics_display = [ ("Completeness", eval_metrics.get('completeness', 0) * 100, "%"), ("Signal Cov", eval_metrics.get('interface_signal_coverage', 0) * 100, "%"), ("Register Cov", eval_metrics.get('register_coverage', 0) * 100, "%"), ("Files", len(st.session_state.generated_files), ""), ("Iterations", result.get('auto_train_iterations', 0), ""), ("Status", "PASS" if result.get('passed') else "DONE", "") ] for i, (label, value, suffix) in enumerate(metrics_display): with cols_m[i]: if isinstance(value, float): display_val = f"{value:.1f}{suffix}" else: display_val = f"{value}{suffix}" is_pass = (label == "Status" and value == "PASS") or (isinstance(value, (int, float)) and value >= 90) success_class = "metric-success" if is_pass else "" st.markdown(f"""
{display_val}
{label}
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) if st.session_state.generated_files: st.markdown('
Generated Files
', unsafe_allow_html=True) col_tree, col_code = st.columns([1, 3]) with col_tree: file_names = sorted(st.session_state.generated_files.keys()) if 'selected_file' not in st.session_state: st.session_state.selected_file = file_names[0] if file_names else None st.markdown('
', unsafe_allow_html=True) for fn in file_names: is_active = (fn == st.session_state.selected_file) active_class = "active" if is_active else "" if st.button(fn, key=f"f_{fn}", use_container_width=True): st.session_state.selected_file = fn st.markdown('
', unsafe_allow_html=True) with col_code: selected_file = st.session_state.selected_file if selected_file and selected_file in st.session_state.generated_files: file_path = st.session_state.generated_files[selected_file] if os.path.exists(file_path): try: with open(file_path, 'r', encoding='utf-8') as f: content = f.read() col_dl1, col_dl2, col_info = st.columns([1, 1, 3]) with col_dl1: st.download_button( "Download", data=content, file_name=selected_file, mime="text/plain", use_container_width=True ) with col_dl2: st.button("Copy", use_container_width=True, key="cp_btn") with col_info: st.caption(f"Lines: {len(content.splitlines())} | Size: {len(content)} bytes") st.markdown(f"""
{content}
""", unsafe_allow_html=True) except Exception as e: st.warning(f"Could not read file: {e}") st.markdown('
', unsafe_allow_html=True) st.markdown('
Export Package
', unsafe_allow_html=True) zip_buffer = io.BytesIO() with zipfile.ZipFile(zip_buffer, 'w', zipfile.ZIP_DEFLATED) as zipf: for name, path in st.session_state.generated_files.items(): if os.path.exists(path): zipf.write(path, arcname=name) zip_buffer.seek(0) col_e1, col_e2, col_e3 = st.columns([2, 2, 3]) with col_e1: st.download_button( "Download UVM Package", data=zip_buffer, file_name=f"{design_name}_uvm_testbench.zip", mime="application/zip", use_container_width=True, type="primary" ) with col_e2: st.button("Generate Simulation Script", use_container_width=True) with col_e3: st.button("Create Regression Suite", use_container_width=True) else: st.markdown("""
Ready to Generate
Configure your specification and click "Generate Testbench" in the sidebar.
""", unsafe_allow_html=True) with tab_analysis: if st.session_state.ml_stats: stats = st.session_state.ml_stats st.markdown('
ML Analysis Dashboard
', unsafe_allow_html=True) cols_a = st.columns(4) with cols_a[0]: st.markdown(f"""
{stats.get('total_generations', 0)}
Generations
""", unsafe_allow_html=True) with cols_a[1]: if 'rl_learner' in stats: rl = stats['rl_learner'] st.markdown(f"""
{rl.get('episode_count', 0)}
RL Episodes
""", unsafe_allow_html=True) with cols_a[2]: if 'rl_learner' in stats: rl = stats['rl_learner'] st.markdown(f"""
{rl.get('total_updates', 0)}
Updates
""", unsafe_allow_html=True) with cols_a[3]: if 'rl_learner' in stats: rl = stats['rl_learner'] st.markdown(f"""
{rl.get('learning_rate', 0.1):.3f}
Learning Rate
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) col_dist, col_weights = st.columns(2) with col_dist: st.markdown('
Source Distribution
', unsafe_allow_html=True) if 'source_distribution' in stats: dist = stats['source_distribution'] if dist: df = pd.DataFrame({ 'Source': list(dist.keys()), 'Count': list(dist.values()) }) st.bar_chart(df.set_index('Source'), color=["#58a6ff"]) else: st.info("No distribution data yet") with col_weights: st.markdown('
Strategy Weights
', unsafe_allow_html=True) if 'strategy_weights' in stats: weights = stats['strategy_weights'] for strategy, weight in weights.items(): percentage = weight * 100 st.markdown(f"""
{strategy} {percentage:.1f}%
""", unsafe_allow_html=True) else: st.info("No strategy weights yet") st.markdown('
', unsafe_allow_html=True) st.markdown('
RL State Performance
', unsafe_allow_html=True) if 'rl_learner' in stats and 'state_stats' in stats['rl_learner']: state_stats = stats['rl_learner']['state_stats'] if state_stats: cols_state = st.columns(min(4, len(state_stats))) for i, (state, info) in enumerate(list(state_stats.items())[:4]): with cols_state[i]: q_val = info.get('best_q_value', 0) best_action = info.get('best_action', 'N/A') visits = info.get('visit_count', 0) st.markdown(f"""
{state[:20]}
{q_val:.3f}
Q-Value
Best: {best_action}
Visits: {visits}
""", unsafe_allow_html=True) else: st.info("No RL state data yet - run a generation to collect statistics") else: st.markdown("""
🔬
ML Analysis
Run a generation with the ML-Driven engine to see:

• Reinforcement Learning metrics
• Strategy weight distributions
• Q-value tracking
• Source distribution analysis
""", unsafe_allow_html=True) with tab_coverage: st.markdown('
Coverage Analysis
', unsafe_allow_html=True) cols_c = st.columns(4) with cols_c[0]: st.markdown(f"""
95%
Target
""", unsafe_allow_html=True) with cols_c[1]: st.markdown(f"""
--
Functional
""", unsafe_allow_html=True) with cols_c[2]: st.markdown(f"""
--
Assertion
""", unsafe_allow_html=True) with cols_c[3]: st.markdown(f"""
--
Code
""", unsafe_allow_html=True) st.markdown('
', unsafe_allow_html=True) st.markdown('
Coverage Closure Assistant
', unsafe_allow_html=True) st.markdown("""
🎯 AI Coverage Recommendations
1
Add directed tests for edge cases (all 0s, all 1s, max values)
2
Verify reset values for all registers
3
Test protocol handshakes with back-to-back transactions
4
Add concurrent stimulus for protocol validation
""", unsafe_allow_html=True) with tab_logs: st.markdown('
Execution Logs
', unsafe_allow_html=True) if st.session_state.log_output: log_html = "\n".join([ f'{line}' for line in st.session_state.log_output ]) st.markdown(f"""
{log_html}
""", unsafe_allow_html=True) else: st.markdown(f"""
[{datetime.now().strftime('%H:%M:%S')}] System initialized
[{datetime.now().strftime('%H:%M:%S')}] Waiting for specification...
[{datetime.now().strftime('%H:%M:%S')}] AI engine ready
[{datetime.now().strftime('%H:%M:%S')}] UVM templates loaded
[{datetime.now().strftime('%H:%M:%S')}] All systems operational

# Click "Generate Testbench" to begin
""", unsafe_allow_html=True) col_clear, col_export = st.columns([1, 5]) with col_clear: st.button("Clear Logs", use_container_width=True) if generate_btn: st.session_state.run_id += 1 st.session_state.log_output = [] st.session_state.last_result = None st.session_state.generated_files = {} st.session_state.ml_stats = None try: from src.config import ConfigLoader, PipelineConfig, MLConfig, GenerationConfig, AutoTrainConfig from src.pipeline import TBPipeline with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False, encoding='utf-8') as f: f.write(spec_text) spec_path = f.name timestamp = datetime.now().strftime('%H:%M:%S') st.session_state.log_output.append(f"[{timestamp}] Starting generation: {design_name}") st.session_state.log_output.append(f"[{timestamp}] Engine: {model_mode}") if model_mode == "v2": st.session_state.log_output.append(f"[{timestamp}] RL Strategy: {rl_strategy}") ml_cfg = MLConfig( enabled=(model_mode != "template"), model_type=model_mode, use_llm=False, use_semantic_encoder=False, ) if model_mode == "v2": ml_cfg.exploration_strategy = rl_strategy ml_cfg.use_learning = enable_learning ml_cfg.strict_validation = strict_uvm pipeline_cfg = PipelineConfig( ml=ml_cfg, generation=GenerationConfig( templates_dir=os.path.join(os.getcwd(), "src", "generation", "templates"), output_dir=os.path.join(os.getcwd(), "output"), overwrite=True ), auto_train=AutoTrainConfig( enabled=(max_iterations > 1), max_iterations=max_iterations ) ) pipeline = TBPipeline(pipeline_cfg) st.session_state.log_output.append(f"[{timestamp}] Model: {type(pipeline.model).__name__}") st.session_state.log_output.append(f"[{timestamp}] Processing specification...") result = pipeline.run(spec_path) try: os.unlink(spec_path) except: pass st.session_state.last_result = result st.session_state.generated_files = result.get('generated_files', {}) try: if hasattr(pipeline.model, 'get_learning_stats'): st.session_state.ml_stats = pipeline.model.get_learning_stats() except Exception as e: logger.warning(f"Could not get ML stats: {e}") timestamp = datetime.now().strftime('%H:%M:%S') st.session_state.log_output.append(f"[{timestamp}] Generation complete") st.session_state.log_output.append(f"[{timestamp}] Files generated: {len(st.session_state.generated_files)}") if result.get('passed'): st.session_state.log_output.append(f"[{timestamp}] Status: PASS") else: st.session_state.log_output.append(f"[{timestamp}] Status: COMPLETED") st.rerun() except Exception as e: timestamp = datetime.now().strftime('%H:%M:%S') st.session_state.log_output.append(f"[{timestamp}] Error: {str(e)}") import traceback st.session_state.log_output.append(traceback.format_exc()) st.rerun()