filename | src/sh4/pmm.c |
changeset | 1021:848db285a184 |
prev | 975:007bf7eb944f |
author | nkeynes |
date | Sat Jun 13 07:12:51 2009 +0000 (14 years ago) |
permissions | -rw-r--r-- |
last change | Load plugins from the directory containing the executable first if they're there - simplifies development testing. Add dummy plugin for easy identification of the plugin directory |
file | annotate | diff | log | raw |
nkeynes@841 | 1 | /** |
nkeynes@1021 | 2 | * $Id$ |
nkeynes@841 | 3 | * |
nkeynes@841 | 4 | * PMM (performance counter) module |
nkeynes@841 | 5 | * |
nkeynes@841 | 6 | * Copyright (c) 2005 Nathan Keynes. |
nkeynes@841 | 7 | * |
nkeynes@841 | 8 | * This program is free software; you can redistribute it and/or modify |
nkeynes@841 | 9 | * it under the terms of the GNU General Public License as published by |
nkeynes@841 | 10 | * the Free Software Foundation; either version 2 of the License, or |
nkeynes@841 | 11 | * (at your option) any later version. |
nkeynes@841 | 12 | * |
nkeynes@841 | 13 | * This program is distributed in the hope that it will be useful, |
nkeynes@841 | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
nkeynes@841 | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
nkeynes@841 | 16 | * GNU General Public License for more details. |
nkeynes@841 | 17 | */ |
nkeynes@841 | 18 | |
nkeynes@841 | 19 | #include "sh4/sh4mmio.h" |
nkeynes@841 | 20 | #include "sh4/sh4core.h" |
nkeynes@841 | 21 | #include "clock.h" |
nkeynes@841 | 22 | |
nkeynes@841 | 23 | /* |
nkeynes@841 | 24 | * Performance counter list from Paul Mundt's OProfile patch |
nkeynes@841 | 25 | * Currently only 0x23 is actually supported, since it doesn't require any |
nkeynes@841 | 26 | * actual instrumentation |
nkeynes@841 | 27 | * |
nkeynes@841 | 28 | * 0x01 Operand read access |
nkeynes@841 | 29 | * 0x02 Operand write access |
nkeynes@841 | 30 | * 0x03 UTLB miss |
nkeynes@841 | 31 | * 0x04 Operand cache read miss |
nkeynes@841 | 32 | * 0x05 Operand cache write miss |
nkeynes@841 | 33 | * 0x06 Instruction fetch (w/ cache) |
nkeynes@841 | 34 | * 0x07 Instruction TLB miss |
nkeynes@841 | 35 | * 0x08 Instruction cache miss |
nkeynes@841 | 36 | * 0x09 All operand accesses |
nkeynes@841 | 37 | * 0x0a All instruction accesses |
nkeynes@841 | 38 | * 0x0b OC RAM operand access |
nkeynes@841 | 39 | * 0x0d On-chip I/O space access |
nkeynes@841 | 40 | * 0x0e Operand access (r/w) |
nkeynes@841 | 41 | * 0x0f Operand cache miss (r/w) |
nkeynes@841 | 42 | * 0x10 Branch instruction |
nkeynes@841 | 43 | * 0x11 Branch taken |
nkeynes@841 | 44 | * 0x12 BSR/BSRF/JSR |
nkeynes@841 | 45 | * 0x13 Instruction execution |
nkeynes@841 | 46 | * 0x14 Instruction execution in parallel |
nkeynes@841 | 47 | * 0x15 FPU Instruction execution |
nkeynes@841 | 48 | * 0x16 Interrupt |
nkeynes@841 | 49 | * 0x17 NMI |
nkeynes@841 | 50 | * 0x18 trapa instruction execution |
nkeynes@841 | 51 | * 0x19 UBCA match |
nkeynes@841 | 52 | * 0x1a UBCB match |
nkeynes@841 | 53 | * 0x21 Instruction cache fill |
nkeynes@841 | 54 | * 0x22 Operand cache fill |
nkeynes@841 | 55 | * 0x23 Elapsed time |
nkeynes@841 | 56 | * 0x24 Pipeline freeze by I-cache miss |
nkeynes@841 | 57 | * 0x25 Pipeline freeze by D-cache miss |
nkeynes@841 | 58 | * 0x27 Pipeline freeze by branch instruction |
nkeynes@841 | 59 | * 0x28 Pipeline freeze by CPU register |
nkeynes@841 | 60 | * 0x29 Pipeline freeze by FPU |
nkeynes@841 | 61 | */ |
nkeynes@841 | 62 | struct PMM_counter_struct { |
nkeynes@841 | 63 | uint64_t count; |
nkeynes@841 | 64 | uint32_t mode; /* if running only, otherwise 0 */ |
nkeynes@841 | 65 | uint32_t runfor; |
nkeynes@841 | 66 | }; |
nkeynes@841 | 67 | |
nkeynes@841 | 68 | static struct PMM_counter_struct PMM_counter[2] = {{0,0},{0,0}}; |
nkeynes@841 | 69 | |
nkeynes@841 | 70 | void PMM_reset(void) |
nkeynes@841 | 71 | { |
nkeynes@841 | 72 | PMM_counter[0].count = 0; |
nkeynes@841 | 73 | PMM_counter[0].mode = 0; |
nkeynes@841 | 74 | PMM_counter[0].runfor = 0; |
nkeynes@841 | 75 | PMM_counter[1].count = 0; |
nkeynes@841 | 76 | PMM_counter[1].mode = 0; |
nkeynes@841 | 77 | PMM_counter[1].runfor = 0; |
nkeynes@841 | 78 | } |
nkeynes@841 | 79 | |
nkeynes@841 | 80 | void PMM_save_state( FILE *f ) { |
nkeynes@841 | 81 | fwrite( &PMM_counter, sizeof(PMM_counter), 1, f ); |
nkeynes@841 | 82 | } |
nkeynes@841 | 83 | |
nkeynes@841 | 84 | int PMM_load_state( FILE *f ) |
nkeynes@841 | 85 | { |
nkeynes@841 | 86 | fread( &PMM_counter, sizeof(PMM_counter), 1, f ); |
nkeynes@841 | 87 | return 0; |
nkeynes@841 | 88 | } |
nkeynes@841 | 89 | |
nkeynes@841 | 90 | void PMM_count( int ctr, uint32_t runfor ) |
nkeynes@841 | 91 | { |
nkeynes@841 | 92 | uint32_t delta = runfor - PMM_counter[ctr].runfor; |
nkeynes@841 | 93 | |
nkeynes@841 | 94 | switch( PMM_counter[ctr].mode ) { |
nkeynes@841 | 95 | case 0x23: |
nkeynes@841 | 96 | PMM_counter[ctr].count += (delta / (1000/SH4_BASE_RATE)); |
nkeynes@841 | 97 | break; |
nkeynes@841 | 98 | default: |
nkeynes@841 | 99 | break; |
nkeynes@841 | 100 | } |
nkeynes@841 | 101 | |
nkeynes@841 | 102 | PMM_counter[ctr].runfor = runfor; |
nkeynes@841 | 103 | } |
nkeynes@841 | 104 | |
nkeynes@841 | 105 | uint32_t PMM_run_slice( uint32_t nanosecs ) |
nkeynes@841 | 106 | { |
nkeynes@841 | 107 | PMM_count( 0, nanosecs ); |
nkeynes@841 | 108 | PMM_count( 1, nanosecs ); |
nkeynes@841 | 109 | PMM_counter[0].runfor = 0; |
nkeynes@841 | 110 | PMM_counter[1].runfor = 0; |
nkeynes@841 | 111 | return nanosecs; |
nkeynes@841 | 112 | } |
nkeynes@841 | 113 | |
nkeynes@841 | 114 | void PMM_write_control( int ctr, uint32_t val ) |
nkeynes@841 | 115 | { |
nkeynes@841 | 116 | int is_running = ((val & PMCR_RUNNING) == PMCR_RUNNING); |
nkeynes@841 | 117 | |
nkeynes@841 | 118 | PMM_count(ctr, sh4r.slice_cycle); |
nkeynes@841 | 119 | if( PMM_counter[ctr].mode == 0 && (val & PMCR_PMCLR) != 0 ) { |
nkeynes@841 | 120 | PMM_counter[ctr].count = 0; |
nkeynes@841 | 121 | } |
nkeynes@841 | 122 | if( is_running ) { |
nkeynes@841 | 123 | int mode = val & 0x3F; |
nkeynes@841 | 124 | if( mode != PMM_counter[ctr].mode ) { |
nkeynes@841 | 125 | /* Instrumentation setup goes here */ |
nkeynes@841 | 126 | PMM_counter[ctr].mode = mode; |
nkeynes@841 | 127 | } |
nkeynes@841 | 128 | } else if( PMM_counter[ctr].mode != 0 ) { |
nkeynes@841 | 129 | /* Instrumentation removal goes here */ |
nkeynes@841 | 130 | PMM_counter[ctr].mode = 0; |
nkeynes@841 | 131 | } |
nkeynes@841 | 132 | } |
nkeynes@841 | 133 | |
nkeynes@929 | 134 | MMIO_REGION_READ_FN( PMM, reg ) |
nkeynes@929 | 135 | { |
nkeynes@841 | 136 | switch( reg & 0x1F ) { |
nkeynes@841 | 137 | case 0: return 0; /* not a register */ |
nkeynes@841 | 138 | case PMCTR1H: |
nkeynes@841 | 139 | PMM_count(0, sh4r.slice_cycle); |
nkeynes@841 | 140 | return ((uint32_t)(PMM_counter[0].count >> 32)) & 0x0000FFFF; |
nkeynes@841 | 141 | case PMCTR1L: |
nkeynes@841 | 142 | PMM_count(0, sh4r.slice_cycle); |
nkeynes@841 | 143 | return (uint32_t)PMM_counter[0].count; |
nkeynes@841 | 144 | case PMCTR2H: |
nkeynes@841 | 145 | PMM_count(1, sh4r.slice_cycle); |
nkeynes@841 | 146 | return ((uint32_t)(PMM_counter[1].count >> 32)) & 0x0000FFFF; |
nkeynes@841 | 147 | default: |
nkeynes@841 | 148 | PMM_count(1, sh4r.slice_cycle); |
nkeynes@841 | 149 | return (uint32_t)PMM_counter[1].count; |
nkeynes@841 | 150 | } |
nkeynes@841 | 151 | } |
nkeynes@841 | 152 | |
nkeynes@929 | 153 | MMIO_REGION_WRITE_FN( PMM, reg, val ) |
nkeynes@841 | 154 | { |
nkeynes@841 | 155 | /* Read-only */ |
nkeynes@841 | 156 | } |
nkeynes@975 | 157 | |
nkeynes@975 | 158 | MMIO_REGION_READ_DEFSUBFNS(PMM) |
.