Initial commit of OpenSPARC T2 architecture model.
[OpenSPARC-T2-SAM] / sam-t2 / sam / cpus / vonk / ss / lib / cpu / src / SS_Interrupt.cc
// ========== Copyright Header Begin ==========================================
//
// OpenSPARC T2 Processor File: SS_Interrupt.cc
// Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
//
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
//
// The above named program is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
//
// ========== Copyright Header End ============================================
#include "SS_Interrupt.h"
#include "SS_Strand.h"
SS_Interrupt::SS_Interrupt()/*{{{*/
:
pending(0),
auto_retract_mask(~uint64_t(0)),
delivered(0),
edge_triggered_mask(0),
disabled(false)
{
manual_retract(BIT_CPU_MONDO_TRAP);
manual_retract(BIT_DEV_MONDO_TRAP);
manual_retract(BIT_RESUMABLE_ERROR);
}
/*}}}*/
void SS_Interrupt::update_softint( SS_Strand* strand )/*{{{*/
{
uint64_t v = strand->softint.level();
// Bit reverse the softint.level() bits to put the highest
// priority bit at the lowest bit iso the highest bit.
v = ((v >> 8) & 0x00ffull) | ((v << 8) & 0xff00ull);
v = ((v >> 4) & 0x0f0full) | ((v << 4) & 0xf0f0ull);
v = ((v >> 2) & 0x3333ull) | ((v << 2) & 0xccccull);
v = ((v >> 1) & 0x5555ull) | ((v << 1) & 0xaaaaull);
v >>= 1;
// Clear out old softint flags and or in new.
pending &= (~0 << (BIT_INTERRUPT_LEVEL_1 + 1)) | ((1 << BIT_INTERRUPT_LEVEL_15) - 1);
pending |= v << BIT_INTERRUPT_LEVEL_15;
// tick and stick match share softint level 14.
pending |= (strand->softint.sm() | strand->softint.tm()) << BIT_INTERRUPT_LEVEL_14;
_check(strand);
}
/*}}}*/
void SS_Interrupt::_check( SS_Strand* strand )/*{{{*/
{
// HPRV_NM_EVER are traps that are never ever maskable.
static const uint64_t HPRV_NM_EVER = (1 << BIT_STORE_ERROR);
// HPRV_IE_MASK is the set of traps that can be taken when in
// hyperpriv mode and when pstate.ie is set (ie).
static const uint64_t HPRV_IE_MASK = HPRV_NM_EVER
| (1 << BIT_HSTICK_MATCH)
| (1 << BIT_NO_RETIRE)
| (1 << BIT_SIU_INBOUND_EXCEPTION)
| (1 << BIT_PERFORMANCE_EVENT)
| (1 << BIT_INTERRUPT_VECTOR)
| (1 << BIT_MODULAR_ARITH_INT)
| (1 << BIT_CTRL_WORD_QUEUE_INT)
| (1 << BIT_HYPERPRIV_QUEUE_0)
| (1 << BIT_HYPERPRIV_QUEUE_1)
| (1 << BIT_SW_RECOVERABLE_ERROR)
| (1 << BIT_HW_CORRECTED_ERROR);
// PRIV_NM_MASK is the set of traps that will always be taken when
// in user or priviledge mode. These are non maskable traps (nm).
static const uint64_t PRIV_NM_MASK = HPRV_IE_MASK
| (1 << BIT_TRAP_LEVEL_ZERO);
uint64_t set; // Which traps we can take
// Figure out which traps can be taken. In hyperpriv mode we look at the
// traps that are maskable: pstate.ie == 1 at that level. In priv or user
// mode all interrupts are allowed when pstate.ie == 1. If pstate.ie == 0
// then only non maskable interrupts are allowed. Interrupts maskable at
// hyperpriviledge are non maskable at user or priv level.
if (strand->sim_state.irq_pending())
{
return; // Only one interrupt per step please.
}
else if (strand->hpstate.hpriv())
{
if (strand->pstate.ie())
set = pending & HPRV_IE_MASK;
else
set = pending & HPRV_NM_EVER;
}
else if (strand->pstate.ie())
{
// Take PIL into account when looking at the softint generated
// interrupt levels. PIL >= 15 blocks all softints.
uint_t mask = ((1 << (15 - strand->pil() + BIT_INTERRUPT_LEVEL_15)) - 1)
| (~0 << (BIT_INTERRUPT_LEVEL_1 + 1));
set = pending & mask;
}
else
set = pending & PRIV_NM_MASK;
set &= ~delivered;
// OK, if all traps got masked out then we're done
// or when the unit is disabled in a hard way ...
if (set == 0)
return;
if (disabled)
return;
// Get the highest priority trap that can be taken,
// which is the least significant set bit in set.
// For edge triggered it should not have been delivered yet.
uint64_t bit = get_lsb(set);
// For some disrupting traps we handle both raise() and retract()
// For the ones where we don't have the retract() code we need to
// clear the pending bit. The ones() for which we do have the retract()
// code and that are edge triggered we mark as delivered.
pending &= ~(bit & auto_retract_mask);
delivered |= bit & edge_triggered_mask;
uint_t idx = bit2idx(bit);
assert(idx < BIT_ASSERT_INDEX);
SS_Trap::Type trap_type = irq_trap_type[idx];
if (strand->irq_store)
{
// In cosim more we have an irq store which holds interrupts until
// the DUT is telling us to take the irq.
(strand->irq_store)(strand->irq_sync,trap_type,true);
}
else
{
// Mark interrupt pending so that we don't launch two interrupt per step
strand->sim_state.irq_pending(1);
strand->msg.set_handle_trap(trap_type);
}
}
/*}}}*/
SS_Trap::Type SS_Interrupt::irq_trap_type[] = /*{{{*/
{
SS_Trap::STORE_ERROR,
SS_Trap::TRAP_LEVEL_ZERO,
SS_Trap::NO_RETIRE,
SS_Trap::SIU_INBOUND_EXCEPTION,
SS_Trap::PERFORMANCE_EVENT,
SS_Trap::HSTICK_MATCH,
SS_Trap::INTERRUPT_VECTOR,
SS_Trap::MODULAR_ARITH_INT,
SS_Trap::CTRL_WORD_QUEUE_INT,
SS_Trap::HYPERPRIV_QUEUE_0,
SS_Trap::CPU_MONDO_TRAP,
SS_Trap::HYPERPRIV_QUEUE_1,
SS_Trap::DEV_MONDO_TRAP,
SS_Trap::INTERRUPT_LEVEL_15,
SS_Trap::INTERRUPT_LEVEL_14,
SS_Trap::INTERRUPT_LEVEL_13,
SS_Trap::INTERRUPT_LEVEL_12,
SS_Trap::INTERRUPT_LEVEL_11,
SS_Trap::INTERRUPT_LEVEL_10,
SS_Trap::INTERRUPT_LEVEL_9,
SS_Trap::INTERRUPT_LEVEL_8,
SS_Trap::INTERRUPT_LEVEL_7,
SS_Trap::INTERRUPT_LEVEL_6,
SS_Trap::INTERRUPT_LEVEL_5,
SS_Trap::INTERRUPT_LEVEL_4,
SS_Trap::INTERRUPT_LEVEL_3,
SS_Trap::INTERRUPT_LEVEL_2,
SS_Trap::INTERRUPT_LEVEL_1,
SS_Trap::SW_RECOVERABLE_ERROR,
SS_Trap::DATA_ACCESS_SIU_ERROR,
SS_Trap::HW_CORRECTED_ERROR,
SS_Trap::RESUMABLE_ERROR,
SS_Trap::NONRESUMABLE_ERROR
};
/*}}}*/
void SS_Interrupt::snapshot( SS_SnapShot& ss, const char* prefix )/*{{{*/
{
char flg[65];
char* ptr = flg;
// Do save/load of the pending flags in a flexible format.
// The characters assigned to the interrupts can not change.
// The enumeration however can change. This makes the snapshot
// extensible without version control.
if (ss.do_save())
{
if (is_pending(BIT_TRAP_LEVEL_ZERO)) *ptr++ = 'A';
if (is_pending(BIT_NO_RETIRE)) *ptr++ = 'B';
if (is_pending(BIT_SIU_INBOUND_EXCEPTION)) *ptr++ = 'C';
if (is_pending(BIT_PERFORMANCE_EVENT)) *ptr++ = 'D';
if (is_pending(BIT_HSTICK_MATCH)) *ptr++ = 'E';
if (is_pending(BIT_INTERRUPT_VECTOR)) *ptr++ = 'F';
if (is_pending(BIT_MODULAR_ARITH_INT)) *ptr++ = 'G';
if (is_pending(BIT_CTRL_WORD_QUEUE_INT)) *ptr++ = 'H';
if (is_pending(BIT_HYPERPRIV_QUEUE_0)) *ptr++ = 'I';
if (is_pending(BIT_CPU_MONDO_TRAP)) *ptr++ = 'J';
if (is_pending(BIT_HYPERPRIV_QUEUE_1)) *ptr++ = 'K';
if (is_pending(BIT_DEV_MONDO_TRAP)) *ptr++ = 'L';
if (is_pending(BIT_INTERRUPT_LEVEL_15)) *ptr++ = 'M';
if (is_pending(BIT_INTERRUPT_LEVEL_14)) *ptr++ = 'N';
if (is_pending(BIT_INTERRUPT_LEVEL_13)) *ptr++ = 'O';
if (is_pending(BIT_INTERRUPT_LEVEL_12)) *ptr++ = 'P';
if (is_pending(BIT_INTERRUPT_LEVEL_11)) *ptr++ = 'Q';
if (is_pending(BIT_INTERRUPT_LEVEL_10)) *ptr++ = 'R';
if (is_pending(BIT_INTERRUPT_LEVEL_9)) *ptr++ = 'S';
if (is_pending(BIT_INTERRUPT_LEVEL_8)) *ptr++ = 'T';
if (is_pending(BIT_INTERRUPT_LEVEL_7)) *ptr++ = 'U';
if (is_pending(BIT_INTERRUPT_LEVEL_6)) *ptr++ = 'V';
if (is_pending(BIT_INTERRUPT_LEVEL_5)) *ptr++ = 'W';
if (is_pending(BIT_INTERRUPT_LEVEL_4)) *ptr++ = 'X';
if (is_pending(BIT_INTERRUPT_LEVEL_3)) *ptr++ = 'Y';
if (is_pending(BIT_INTERRUPT_LEVEL_2)) *ptr++ = 'Z';
if (is_pending(BIT_INTERRUPT_LEVEL_1)) *ptr++ = 'a';
if (is_pending(BIT_SW_RECOVERABLE_ERROR)) *ptr++ = 'b';
if (is_pending(BIT_DATA_ACCESS_SIU_ERROR)) *ptr++ = 'c';
if (is_pending(BIT_HW_CORRECTED_ERROR)) *ptr++ = 'd';
if (is_pending(BIT_RESUMABLE_ERROR)) *ptr++ = 'e';
if (is_pending(BIT_NONRESUMABLE_ERROR)) *ptr++ = 'f';
if (is_pending(BIT_STORE_ERROR)) *ptr++ = 'g';
if (ptr == flg) *ptr++ = '-';
*ptr++ = 0;
}
sprintf(ss.tag,"%s.irq.pending",prefix); ss.val(flg);
if (ss.do_load())
{
pending = 0;
while (*ptr)
{
switch (*ptr++)
{
case '-': break;
case 'A': mark_pending(BIT_TRAP_LEVEL_ZERO); break;
case 'B': mark_pending(BIT_NO_RETIRE); break;
case 'C': mark_pending(BIT_SIU_INBOUND_EXCEPTION); break;
case 'D': mark_pending(BIT_PERFORMANCE_EVENT); break;
case 'E': mark_pending(BIT_HSTICK_MATCH); break;
case 'F': mark_pending(BIT_INTERRUPT_VECTOR); break;
case 'G': mark_pending(BIT_MODULAR_ARITH_INT); break;
case 'H': mark_pending(BIT_CTRL_WORD_QUEUE_INT); break;
case 'I': mark_pending(BIT_HYPERPRIV_QUEUE_0); break;
case 'J': mark_pending(BIT_CPU_MONDO_TRAP); break;
case 'K': mark_pending(BIT_HYPERPRIV_QUEUE_1); break;
case 'L': mark_pending(BIT_DEV_MONDO_TRAP); break;
case 'M': mark_pending(BIT_INTERRUPT_LEVEL_15); break;
case 'N': mark_pending(BIT_INTERRUPT_LEVEL_14); break;
case 'O': mark_pending(BIT_INTERRUPT_LEVEL_13); break;
case 'P': mark_pending(BIT_INTERRUPT_LEVEL_12); break;
case 'Q': mark_pending(BIT_INTERRUPT_LEVEL_11); break;
case 'R': mark_pending(BIT_INTERRUPT_LEVEL_10); break;
case 'S': mark_pending(BIT_INTERRUPT_LEVEL_9); break;
case 'T': mark_pending(BIT_INTERRUPT_LEVEL_8); break;
case 'U': mark_pending(BIT_INTERRUPT_LEVEL_7); break;
case 'V': mark_pending(BIT_INTERRUPT_LEVEL_6); break;
case 'W': mark_pending(BIT_INTERRUPT_LEVEL_5); break;
case 'X': mark_pending(BIT_INTERRUPT_LEVEL_4); break;
case 'Y': mark_pending(BIT_INTERRUPT_LEVEL_3); break;
case 'Z': mark_pending(BIT_INTERRUPT_LEVEL_2); break;
case 'a': mark_pending(BIT_INTERRUPT_LEVEL_1); break;
case 'b': mark_pending(BIT_SW_RECOVERABLE_ERROR); break;
case 'c': mark_pending(BIT_DATA_ACCESS_SIU_ERROR); break;
case 'd': mark_pending(BIT_HW_CORRECTED_ERROR); break;
case 'e': mark_pending(BIT_RESUMABLE_ERROR); break;
case 'f': mark_pending(BIT_NONRESUMABLE_ERROR); break;
case 'g': mark_pending(BIT_STORE_ERROR); break;
default:
fprintf(stderr,"Warning: Unknown character in "
"irq_pending snapshot %s\n",flg);
}
}
}
}
/*}}}*/