nkeynes@841: /** nkeynes@1021: * $Id$ nkeynes@841: * nkeynes@841: * PMM (performance counter) module nkeynes@841: * nkeynes@841: * Copyright (c) 2005 Nathan Keynes. nkeynes@841: * nkeynes@841: * This program is free software; you can redistribute it and/or modify nkeynes@841: * it under the terms of the GNU General Public License as published by nkeynes@841: * the Free Software Foundation; either version 2 of the License, or nkeynes@841: * (at your option) any later version. nkeynes@841: * nkeynes@841: * This program is distributed in the hope that it will be useful, nkeynes@841: * but WITHOUT ANY WARRANTY; without even the implied warranty of nkeynes@841: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nkeynes@841: * GNU General Public License for more details. nkeynes@841: */ nkeynes@841: nkeynes@841: #include "sh4/sh4mmio.h" nkeynes@841: #include "sh4/sh4core.h" nkeynes@841: #include "clock.h" nkeynes@841: nkeynes@841: /* nkeynes@841: * Performance counter list from Paul Mundt's OProfile patch nkeynes@841: * Currently only 0x23 is actually supported, since it doesn't require any nkeynes@841: * actual instrumentation nkeynes@841: * nkeynes@841: * 0x01 Operand read access nkeynes@841: * 0x02 Operand write access nkeynes@841: * 0x03 UTLB miss nkeynes@841: * 0x04 Operand cache read miss nkeynes@841: * 0x05 Operand cache write miss nkeynes@841: * 0x06 Instruction fetch (w/ cache) nkeynes@841: * 0x07 Instruction TLB miss nkeynes@841: * 0x08 Instruction cache miss nkeynes@841: * 0x09 All operand accesses nkeynes@841: * 0x0a All instruction accesses nkeynes@841: * 0x0b OC RAM operand access nkeynes@841: * 0x0d On-chip I/O space access nkeynes@841: * 0x0e Operand access (r/w) nkeynes@841: * 0x0f Operand cache miss (r/w) nkeynes@841: * 0x10 Branch instruction nkeynes@841: * 0x11 Branch taken nkeynes@841: * 0x12 BSR/BSRF/JSR nkeynes@841: * 0x13 Instruction execution nkeynes@841: * 0x14 Instruction execution in parallel nkeynes@841: * 0x15 FPU Instruction execution nkeynes@841: * 0x16 Interrupt nkeynes@841: * 0x17 NMI nkeynes@841: * 0x18 trapa instruction execution nkeynes@841: * 0x19 UBCA match nkeynes@841: * 0x1a UBCB match nkeynes@841: * 0x21 Instruction cache fill nkeynes@841: * 0x22 Operand cache fill nkeynes@841: * 0x23 Elapsed time nkeynes@841: * 0x24 Pipeline freeze by I-cache miss nkeynes@841: * 0x25 Pipeline freeze by D-cache miss nkeynes@841: * 0x27 Pipeline freeze by branch instruction nkeynes@841: * 0x28 Pipeline freeze by CPU register nkeynes@841: * 0x29 Pipeline freeze by FPU nkeynes@841: */ nkeynes@841: struct PMM_counter_struct { nkeynes@841: uint64_t count; nkeynes@841: uint32_t mode; /* if running only, otherwise 0 */ nkeynes@841: uint32_t runfor; nkeynes@841: }; nkeynes@841: nkeynes@841: static struct PMM_counter_struct PMM_counter[2] = {{0,0},{0,0}}; nkeynes@841: nkeynes@841: void PMM_reset(void) nkeynes@841: { nkeynes@841: PMM_counter[0].count = 0; nkeynes@841: PMM_counter[0].mode = 0; nkeynes@841: PMM_counter[0].runfor = 0; nkeynes@841: PMM_counter[1].count = 0; nkeynes@841: PMM_counter[1].mode = 0; nkeynes@841: PMM_counter[1].runfor = 0; nkeynes@841: } nkeynes@841: nkeynes@841: void PMM_save_state( FILE *f ) { nkeynes@841: fwrite( &PMM_counter, sizeof(PMM_counter), 1, f ); nkeynes@841: } nkeynes@841: nkeynes@841: int PMM_load_state( FILE *f ) nkeynes@841: { nkeynes@841: fread( &PMM_counter, sizeof(PMM_counter), 1, f ); nkeynes@841: return 0; nkeynes@841: } nkeynes@841: nkeynes@841: void PMM_count( int ctr, uint32_t runfor ) nkeynes@841: { nkeynes@841: uint32_t delta = runfor - PMM_counter[ctr].runfor; nkeynes@841: nkeynes@841: switch( PMM_counter[ctr].mode ) { nkeynes@841: case 0x23: nkeynes@841: PMM_counter[ctr].count += (delta / (1000/SH4_BASE_RATE)); nkeynes@841: break; nkeynes@841: default: nkeynes@841: break; nkeynes@841: } nkeynes@841: nkeynes@841: PMM_counter[ctr].runfor = runfor; nkeynes@841: } nkeynes@841: nkeynes@841: uint32_t PMM_run_slice( uint32_t nanosecs ) nkeynes@841: { nkeynes@841: PMM_count( 0, nanosecs ); nkeynes@841: PMM_count( 1, nanosecs ); nkeynes@841: PMM_counter[0].runfor = 0; nkeynes@841: PMM_counter[1].runfor = 0; nkeynes@841: return nanosecs; nkeynes@841: } nkeynes@841: nkeynes@841: void PMM_write_control( int ctr, uint32_t val ) nkeynes@841: { nkeynes@841: int is_running = ((val & PMCR_RUNNING) == PMCR_RUNNING); nkeynes@841: nkeynes@841: PMM_count(ctr, sh4r.slice_cycle); nkeynes@841: if( PMM_counter[ctr].mode == 0 && (val & PMCR_PMCLR) != 0 ) { nkeynes@841: PMM_counter[ctr].count = 0; nkeynes@841: } nkeynes@841: if( is_running ) { nkeynes@841: int mode = val & 0x3F; nkeynes@841: if( mode != PMM_counter[ctr].mode ) { nkeynes@841: /* Instrumentation setup goes here */ nkeynes@841: PMM_counter[ctr].mode = mode; nkeynes@841: } nkeynes@841: } else if( PMM_counter[ctr].mode != 0 ) { nkeynes@841: /* Instrumentation removal goes here */ nkeynes@841: PMM_counter[ctr].mode = 0; nkeynes@841: } nkeynes@841: } nkeynes@841: nkeynes@929: MMIO_REGION_READ_FN( PMM, reg ) nkeynes@929: { nkeynes@841: switch( reg & 0x1F ) { nkeynes@841: case 0: return 0; /* not a register */ nkeynes@841: case PMCTR1H: nkeynes@841: PMM_count(0, sh4r.slice_cycle); nkeynes@841: return ((uint32_t)(PMM_counter[0].count >> 32)) & 0x0000FFFF; nkeynes@841: case PMCTR1L: nkeynes@841: PMM_count(0, sh4r.slice_cycle); nkeynes@841: return (uint32_t)PMM_counter[0].count; nkeynes@841: case PMCTR2H: nkeynes@841: PMM_count(1, sh4r.slice_cycle); nkeynes@841: return ((uint32_t)(PMM_counter[1].count >> 32)) & 0x0000FFFF; nkeynes@841: default: nkeynes@841: PMM_count(1, sh4r.slice_cycle); nkeynes@841: return (uint32_t)PMM_counter[1].count; nkeynes@841: } nkeynes@841: } nkeynes@841: nkeynes@929: MMIO_REGION_WRITE_FN( PMM, reg, val ) nkeynes@841: { nkeynes@841: /* Read-only */ nkeynes@841: } nkeynes@975: nkeynes@975: MMIO_REGION_READ_DEFSUBFNS(PMM)