aboutsummaryrefslogtreecommitdiffstats
path: root/techlibs/common/synth.cc
Commit message (Expand)AuthorAgeFilesLines
* Replace opt_rmdff with opt_dff.Marcelina Koƛcielnicka2020-08-071-3/+3
* Use C++11 final/override keywords.whitequark2020-06-181-4/+4
* synth: only techmap cmp2{lut,lcu} if -lutEddie Hung2020-04-031-1/+1
* synth: use +/cmp2lcu.v in generic 'synth' tooEddie Hung2020-04-031-2/+2
* Add -flowmap to synth and synth_ice40Dan Ravensloft2020-02-281-2/+17
* Missing newlineEddie Hung2019-08-201-1/+1
* Revert "Add "synth -keepdc" option"Eddie Hung2019-07-091-13/+2
* Add synth -keepdc optionEddie Hung2019-07-081-2/+13
* Make doc consistentEddie Hung2019-06-141-1/+4
* Merge remote-tracking branch 'origin/master' into xaigEddie Hung2019-06-121-0/+2
|\
| * Run "peepopt" in generic "synth" pass and "synth_ice40"Clifford Wolf2019-04-301-0/+2
* | synth to take -abc9 argumentEddie Hung2019-02-201-5/+13
|/
* Merge pull request #772 from whitequark/synth_lutClifford Wolf2019-01-021-6/+40
|\
| * synth: add k-LUT mode.whitequark2019-01-021-2/+36
| * synth: improve script documentation. NFC.whitequark2019-01-021-6/+6
* | Fix typographical and grammatical errors and inconsistencies.whitequark2019-01-021-1/+1
|/
* Consistent use of 'override' for virtual methods in derived classes.Henner Zeller2018-07-201-4/+4
* Add "synth -noshare"Clifford Wolf2018-03-041-2/+11
* Added "prep -auto-top" and "synth -auto-top"Clifford Wolf2016-07-111-3/+11
* Added "prep -flatten" and "synth -flatten"Clifford Wolf2016-04-241-4/+18
* Converted "prep" to ScriptPassClifford Wolf2016-04-241-1/+1
* Added "yosys -D" featureClifford Wolf2016-04-211-1/+1
* Added ScriptPass helper class for script-like passesClifford Wolf2016-03-311-89/+64
* Renamed opt_const to opt_exprClifford Wolf2016-03-311-2/+2
* Run opt_const before check in default scriptsClifford Wolf2015-12-221-0/+2
* Added "synth -nofsm"Clifford Wolf2015-07-021-1/+10
* Fixed trailing whitespacesClifford Wolf2015-07-021-3/+3
* Added "synth -nordff -noalumacc"Clifford Wolf2015-06-151-3/+20
* Added "stat" to "synth" and "synth_xilinx"Clifford Wolf2015-02-151-0/+2
* Added final checks to "synth" and "synth_xilinx"Clifford Wolf2015-02-151-7/+14
* Added "check" commandClifford Wolf2015-02-131-0/+4
* Added "make mklibyosys", some minor API changesClifford Wolf2015-02-011-1/+9
* Added "fsm -encfile"Clifford Wolf2015-01-301-2/+9
* Added "abc" label in synth scriptClifford Wolf2014-10-311-6/+12
* Added "opt -full" alias for all more aggressive optimizationsClifford Wolf2014-10-311-2/+6
* namespace YosysClifford Wolf2014-09-271-1/+5
* Improvements in "synth" scriptClifford Wolf2014-09-181-8/+12
* Added "synth" commandClifford Wolf2014-09-141-0/+152
'>445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
/******************************************************************************
 * keyhandler.c
 */

#include <asm/regs.h>
#include <xen/keyhandler.h> 
#include <xen/shutdown.h>
#include <xen/event.h>
#include <xen/console.h>
#include <xen/serial.h>
#include <xen/sched.h>
#include <xen/tasklet.h>
#include <xen/domain.h>
#include <xen/rangeset.h>
#include <xen/compat.h>
#include <xen/ctype.h>
#include <xen/perfc.h>
#include <asm/debugger.h>
#include <asm/div64.h>

static struct keyhandler *key_table[256];
static unsigned char keypress_key;
static bool_t alt_key_handling;

char keyhandler_scratch[1024];

static void keypress_action(unsigned long unused)
{
    handle_keypress(keypress_key, NULL);
}

static DECLARE_TASKLET(keypress_tasklet, keypress_action, 0);

void handle_keypress(unsigned char key, struct cpu_user_regs *regs)
{
    struct keyhandler *h;

    if ( (h = key_table[key]) == NULL )
        return;

    if ( !in_irq() || h->irq_callback )
    {
        console_start_log_everything();
        h->irq_callback ? (*h->u.irq_fn)(key, regs) : (*h->u.fn)(key);
        console_end_log_everything();
    }
    else
    {
        keypress_key = key;
        tasklet_schedule(&keypress_tasklet);
    }
}

void register_keyhandler(unsigned char key, struct keyhandler *handler)
{
    ASSERT(key_table[key] == NULL);
    key_table[key] = handler;
}

static void show_handlers(unsigned char key)
{
    int i;
    printk("'%c' pressed -> showing installed handlers\n", key);
    for ( i = 0; i < ARRAY_SIZE(key_table); i++ ) 
        if ( key_table[i] != NULL ) 
            printk(" key '%c' (ascii '%02x') => %s\n", 
                   isprint(i) ? i : ' ', i, key_table[i]->desc);
}

static struct keyhandler show_handlers_keyhandler = {
    .u.fn = show_handlers,
    .desc = "show this message"
};

static cpumask_t dump_execstate_mask;

void dump_execstate(struct cpu_user_regs *regs)
{
    unsigned int cpu = smp_processor_id();

    if ( !guest_mode(regs) )
    {
        printk("*** Dumping CPU%u host state: ***\n", cpu);
        show_execution_state(regs);
    }

    if ( !is_idle_vcpu(current) )
    {
        printk("*** Dumping CPU%u guest state (d%d:v%d): ***\n",
               smp_processor_id(), current->domain->domain_id,
               current->vcpu_id);
        show_execution_state(guest_cpu_user_regs());
        printk("\n");
    }

    cpumask_clear_cpu(cpu, &dump_execstate_mask);
    if ( !alt_key_handling )
        return;

    cpu = cpumask_cycle(cpu, &dump_execstate_mask);
    if ( cpu < nr_cpu_ids )
    {
        smp_send_state_dump(cpu);
        return;
    }

    console_end_sync();
    watchdog_enable();
}

static void dump_registers(unsigned char key, struct cpu_user_regs *regs)
{
    unsigned int cpu;

    /* We want to get everything out that we possibly can. */
    watchdog_disable();
    console_start_sync();

    printk("'%c' pressed -> dumping registers\n\n", key);

    cpumask_copy(&dump_execstate_mask, &cpu_online_map);

    /* Get local execution state out immediately, in case we get stuck. */
    dump_execstate(regs);

    /* Alt. handling: remaining CPUs are dumped asynchronously one-by-one. */
    if ( alt_key_handling )
        return;

    /* Normal handling: synchronously dump the remaining CPUs' states. */
    for_each_cpu ( cpu, &dump_execstate_mask )
    {
        smp_send_state_dump(cpu);
        while ( cpumask_test_cpu(cpu, &dump_execstate_mask) )
            cpu_relax();
    }

    console_end_sync();
    watchdog_enable();
}

static struct keyhandler dump_registers_keyhandler = {
    .irq_callback = 1,
    .diagnostic = 1,
    .u.irq_fn = dump_registers,
    .desc = "dump registers"
};

static DECLARE_TASKLET(dump_dom0_tasklet, NULL, 0);

static void dump_dom0_action(unsigned long arg)
{
    struct vcpu *v = (void *)arg;

    for ( ; ; )
    {
        vcpu_show_execution_state(v);
        if ( (v = v->next_in_list) == NULL )
            break;
        if ( softirq_pending(smp_processor_id()) )
        {
            dump_dom0_tasklet.data = (unsigned long)v;
            tasklet_schedule_on_cpu(&dump_dom0_tasklet, v->processor);
            break;
        }
    }
}

static void dump_dom0_registers(unsigned char key)
{
    struct vcpu *v;

    if ( dom0 == NULL )
        return;

    printk("'%c' pressed -> dumping Dom0's registers\n", key);

    for_each_vcpu ( dom0, v )
    {
        if ( alt_key_handling && softirq_pending(smp_processor_id()) )
        {
            tasklet_kill(&dump_dom0_tasklet);
            tasklet_init(&dump_dom0_tasklet, dump_dom0_action,
                         (unsigned long)v);
            tasklet_schedule_on_cpu(&dump_dom0_tasklet, v->processor);
            return;
        }
        vcpu_show_execution_state(v);
    }
}

static struct keyhandler dump_dom0_registers_keyhandler = {
    .diagnostic = 1,
    .u.fn = dump_dom0_registers,
    .desc = "dump Dom0 registers"
};

static void reboot_machine(unsigned char key, struct cpu_user_regs *regs)
{
    printk("'%c' pressed -> rebooting machine\n", key);
    machine_restart(0);
}

static struct keyhandler reboot_machine_keyhandler = {
    .irq_callback = 1,
    .u.irq_fn = reboot_machine,
    .desc = "reboot machine"
};

static void cpuset_print(char *set, int size, const cpumask_t *mask)
{
    *set++ = '{';
    set += cpulist_scnprintf(set, size-2, mask);
    *set++ = '}';
    *set++ = '\0';
}

static void periodic_timer_print(char *str, int size, uint64_t period)
{
    if ( period == 0 )
    {
        strlcpy(str, "No periodic timer", size);
        return;
    }

    snprintf(str, size,
             "%u Hz periodic timer (period %u ms)",
             1000000000/(int)period, (int)period/1000000);
}

static void dump_domains(unsigned char key)
{
    struct domain *d;
    struct vcpu   *v;
    s_time_t       now = NOW();
#define tmpstr keyhandler_scratch

    printk("'%c' pressed -> dumping domain info (now=0x%X:%08X)\n", key,
           (u32)(now>>32), (u32)now);

    rcu_read_lock(&domlist_read_lock);

    for_each_domain ( d )
    {
        unsigned int i;
        printk("General information for domain %u:\n", d->domain_id);
        cpuset_print(tmpstr, sizeof(tmpstr), d->domain_dirty_cpumask);
        printk("    refcnt=%d dying=%d pause_count=%d\n",
               atomic_read(&d->refcnt), d->is_dying,
               atomic_read(&d->pause_count));
        printk("    nr_pages=%d xenheap_pages=%d dirty_cpus=%s max_pages=%u\n",
               d->tot_pages, d->xenheap_pages, tmpstr, d->max_pages);
        printk("    handle=%02x%02x%02x%02x-%02x%02x-%02x%02x-"
               "%02x%02x-%02x%02x%02x%02x%02x%02x vm_assist=%08lx\n",
               d->handle[ 0], d->handle[ 1], d->handle[ 2], d->handle[ 3],
               d->handle[ 4], d->handle[ 5], d->handle[ 6], d->handle[ 7],
               d->handle[ 8], d->handle[ 9], d->handle[10], d->handle[11],
               d->handle[12], d->handle[13], d->handle[14], d->handle[15],
               d->vm_assist);
        for ( i = 0 ; i < NR_DOMAIN_WATCHDOG_TIMERS; i++ )
            if ( test_bit(i, &d->watchdog_inuse_map) )
                printk("    watchdog %d expires in %d seconds\n",
                       i, (u32)((d->watchdog_timer[i].expires - NOW()) >> 30));

        arch_dump_domain_info(d);

        rangeset_domain_printk(d);

        dump_pageframe_info(d);
               
        printk("VCPU information and callbacks for domain %u:\n",
               d->domain_id);
        for_each_vcpu ( d, v )
        {
            printk("    VCPU%d: CPU%d [has=%c] poll=%d "
                   "upcall_pend = %02x, upcall_mask = %02x ",
                   v->vcpu_id, v->processor,
                   v->is_running ? 'T':'F', v->poll_evtchn,
                   vcpu_info(v, evtchn_upcall_pending),
                   vcpu_info(v, evtchn_upcall_mask));
            cpuset_print(tmpstr, sizeof(tmpstr), v->vcpu_dirty_cpumask);
            printk("dirty_cpus=%s ", tmpstr);
            cpuset_print(tmpstr, sizeof(tmpstr), v->cpu_affinity);
            printk("cpu_affinity=%s\n", tmpstr);
            printk("    pause_count=%d pause_flags=%lx\n",
                   atomic_read(&v->pause_count), v->pause_flags);
            arch_dump_vcpu_info(v);
            periodic_timer_print(tmpstr, sizeof(tmpstr), v->periodic_period);
            printk("    %s\n", tmpstr);
        }
    }

    for_each_domain ( d )
    {
        for_each_vcpu ( d, v )
        {
            printk("Notifying guest %d:%d (virq %d, port %d, stat %d/%d/%d)\n",
                   d->domain_id, v->vcpu_id,
                   VIRQ_DEBUG, v->virq_to_evtchn[VIRQ_DEBUG],
                   test_bit(v->virq_to_evtchn[VIRQ_DEBUG], 
                            &shared_info(d, evtchn_pending)),
                   test_bit(v->virq_to_evtchn[VIRQ_DEBUG], 
                            &shared_info(d, evtchn_mask)),
                   test_bit(v->virq_to_evtchn[VIRQ_DEBUG] /
                            BITS_PER_EVTCHN_WORD(d),
                            &vcpu_info(v, evtchn_pending_sel)));
            send_guest_vcpu_virq(v, VIRQ_DEBUG);
        }
    }

    rcu_read_unlock(&domlist_read_lock);
#undef tmpstr
}

static struct keyhandler dump_domains_keyhandler = {
    .diagnostic = 1,
    .u.fn = dump_domains,
    .desc = "dump domain (and guest debug) info"
};

static cpumask_t read_clocks_cpumask;
static DEFINE_PER_CPU(s_time_t, read_clocks_time);
static DEFINE_PER_CPU(u64, read_cycles_time);

static void read_clocks_slave(void *unused)
{
    unsigned int cpu = smp_processor_id();
    local_irq_disable();
    while ( !cpumask_test_cpu(cpu, &read_clocks_cpumask) )
        cpu_relax();
    per_cpu(read_clocks_time, cpu) = NOW();
    per_cpu(read_cycles_time, cpu) = get_cycles();
    cpumask_clear_cpu(cpu, &read_clocks_cpumask);
    local_irq_enable();
}

static void read_clocks(unsigned char key)
{
    unsigned int cpu = smp_processor_id(), min_stime_cpu, max_stime_cpu;
    unsigned int min_cycles_cpu, max_cycles_cpu;
    u64 min_stime, max_stime, dif_stime;
    u64 min_cycles, max_cycles, dif_cycles;
    static u64 sumdif_stime = 0, maxdif_stime = 0;
    static u64 sumdif_cycles = 0, maxdif_cycles = 0;
    static u32 count = 0;
    static DEFINE_SPINLOCK(lock);

    spin_lock(&lock);

    smp_call_function(read_clocks_slave, NULL, 0);

    local_irq_disable();
    cpumask_andnot(&read_clocks_cpumask, &cpu_online_map, cpumask_of(cpu));
    per_cpu(read_clocks_time, cpu) = NOW();
    per_cpu(read_cycles_time, cpu) = get_cycles();
    local_irq_enable();

    while ( !cpumask_empty(&read_clocks_cpumask) )
        cpu_relax();

    min_stime_cpu = max_stime_cpu = min_cycles_cpu = max_cycles_cpu = cpu;
    for_each_online_cpu ( cpu )
    {
        if ( per_cpu(read_clocks_time, cpu) <
             per_cpu(read_clocks_time, min_stime_cpu) )
            min_stime_cpu = cpu;
        if ( per_cpu(read_clocks_time, cpu) >
             per_cpu(read_clocks_time, max_stime_cpu) )
            max_stime_cpu = cpu;
        if ( per_cpu(read_cycles_time, cpu) <
             per_cpu(read_cycles_time, min_cycles_cpu) )
            min_cycles_cpu = cpu;
        if ( per_cpu(read_cycles_time, cpu) >
             per_cpu(read_cycles_time, max_cycles_cpu) )
            max_cycles_cpu = cpu;
    }

    min_stime = per_cpu(read_clocks_time, min_stime_cpu);
    max_stime = per_cpu(read_clocks_time, max_stime_cpu);
    min_cycles = per_cpu(read_cycles_time, min_cycles_cpu);
    max_cycles = per_cpu(read_cycles_time, max_cycles_cpu);

    spin_unlock(&lock);

    dif_stime = max_stime - min_stime;
    if ( dif_stime > maxdif_stime )
        maxdif_stime = dif_stime;
    sumdif_stime += dif_stime;
    dif_cycles = max_cycles - min_cycles;
    if ( dif_cycles > maxdif_cycles )
        maxdif_cycles = dif_cycles;
    sumdif_cycles += dif_cycles;
    count++;
    printk("Synced stime skew: max=%"PRIu64"ns avg=%"PRIu64"ns "
           "samples=%"PRIu32" current=%"PRIu64"ns\n",
           maxdif_stime, sumdif_stime/count, count, dif_stime);
    printk("Synced cycles skew: max=%"PRIu64" avg=%"PRIu64" "
           "samples=%"PRIu32" current=%"PRIu64"\n",
           maxdif_cycles, sumdif_cycles/count, count, dif_cycles);
}

static struct keyhandler read_clocks_keyhandler = {
    .diagnostic = 1,
    .u.fn = read_clocks,
    .desc = "display multi-cpu clock info"
};

static struct keyhandler dump_runq_keyhandler = {
    .diagnostic = 1,
    .u.fn = dump_runq,
    .desc = "dump run queues"
};

#ifdef PERF_COUNTERS
static struct keyhandler perfc_printall_keyhandler = {
    .diagnostic = 1,
    .u.fn = perfc_printall,
    .desc = "print performance counters"
};
static struct keyhandler perfc_reset_keyhandler = {
    .u.fn = perfc_reset,
    .desc = "reset performance counters"
};
#endif

#ifdef LOCK_PROFILE
static struct keyhandler spinlock_printall_keyhandler = {
    .diagnostic = 1,
    .u.fn = spinlock_profile_printall,
    .desc = "print lock profile info"
};
static struct keyhandler spinlock_reset_keyhandler = {
    .u.fn = spinlock_profile_reset,
    .desc = "reset lock profile info"
};
#endif

static void run_all_nonirq_keyhandlers(unsigned long unused)
{
    /* Fire all the non-IRQ-context diagnostic keyhandlers */
    struct keyhandler *h;
    int k;

    console_start_log_everything();

    for ( k = 0; k < ARRAY_SIZE(key_table); k++ )
    {
        process_pending_softirqs();
        h = key_table[k];
        if ( (h == NULL) || !h->diagnostic || h->irq_callback )
            continue;
        printk("[%c: %s]\n", k, h->desc);
        (*h->u.fn)(k);
    }

    console_end_log_everything();
}

static DECLARE_TASKLET(run_all_keyhandlers_tasklet,
                       run_all_nonirq_keyhandlers, 0);

static void run_all_keyhandlers(unsigned char key, struct cpu_user_regs *regs)
{
    struct keyhandler *h;
    int k;

    watchdog_disable();

    printk("'%c' pressed -> firing all diagnostic keyhandlers\n", key);

    /* Fire all the IRQ-context diangostic keyhandlers now */
    for ( k = 0; k < ARRAY_SIZE(key_table); k++ )
    {
        h = key_table[k];
        if ( (h == NULL) || !h->diagnostic || !h->irq_callback )
            continue;
        printk("[%c: %s]\n", k, h->desc);
        (*h->u.irq_fn)(k, regs);
    }

    watchdog_enable();

    /* Trigger the others from a tasklet in non-IRQ context */
    tasklet_schedule(&run_all_keyhandlers_tasklet);
}

static struct keyhandler run_all_keyhandlers_keyhandler = {
    .irq_callback = 1,
    .u.irq_fn = run_all_keyhandlers,
    .desc = "print all diagnostics"
};

static void do_debug_key(unsigned char key, struct cpu_user_regs *regs)
{
    printk("'%c' pressed -> trapping into debugger\n", key);
    (void)debugger_trap_fatal(0xf001, regs);
    nop(); /* Prevent the compiler doing tail call
                             optimisation, as that confuses xendbg a
                             bit. */
}

static struct keyhandler do_debug_key_keyhandler = {
    .irq_callback = 1,
    .u.irq_fn = do_debug_key,
    .desc = "trap to xendbg"
};

static void do_toggle_alt_key(unsigned char key, struct cpu_user_regs *regs)
{
    alt_key_handling = !alt_key_handling;
    printk("'%c' pressed -> using %s key handling\n", key,
           alt_key_handling ? "alternative" : "normal");
}

static struct keyhandler toggle_alt_keyhandler = {
    .irq_callback = 1,
    .u.irq_fn = do_toggle_alt_key,
    .desc = "toggle alternative key handling"
};

void __init initialize_keytable(void)
{
    if ( num_present_cpus() > 16 )
    {
        alt_key_handling = 1;
        printk(XENLOG_INFO "Defaulting to alternative key handling; "
               "send 'A' to switch to normal mode.\n");
    }
    register_keyhandler('A', &toggle_alt_keyhandler);
    register_keyhandler('d', &dump_registers_keyhandler);
    register_keyhandler('h', &show_handlers_keyhandler);
    register_keyhandler('q', &dump_domains_keyhandler);
    register_keyhandler('r', &dump_runq_keyhandler);
    register_keyhandler('R', &reboot_machine_keyhandler);
    register_keyhandler('t', &read_clocks_keyhandler);
    register_keyhandler('0', &dump_dom0_registers_keyhandler);
    register_keyhandler('%', &do_debug_key_keyhandler);
    register_keyhandler('*', &run_all_keyhandlers_keyhandler);

#ifdef PERF_COUNTERS
    register_keyhandler('p', &perfc_printall_keyhandler);
    register_keyhandler('P', &perfc_reset_keyhandler);
#endif

#ifdef LOCK_PROFILE
    register_keyhandler('l', &spinlock_printall_keyhandler);
    register_keyhandler('L', &spinlock_reset_keyhandler);
#endif

}

/*
 * Local variables:
 * mode: C
 * c-set-style: "BSD"
 * c-basic-offset: 4
 * tab-width: 4
 * indent-tabs-mode: nil
 * End:
 */