// ========== Copyright Header Begin ==========================================
// OpenSPARC T2 Processor File: N2_Cpu.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 ============================================
/************************************************************************
** Copyright (C) 2006, Sun Microsystems, Inc.
** Sun considers its source code as an unpublished, proprietary
** trade secret and it is available only under strict license provisions.
** This copyright notice is placed here only to protect Sun in the event
** the source is deemed a published work. Disassembly, decompilation,
** or other means of reducing the object code to human readable form
** is prohibited by the license agreement under which this code is
** provided to the user or company in possession of this copy.
*************************************************************************/
N2_Cpu::N2_Cpu( SS_Model
& _model
, const char* _name
, uint_t strand_id_base
)/*{{{*/
mem_err_detector(&_model
)
for (uint_t c
=0; c
< N2_Model::NO_CORES_PER_CPU
; c
++)
core
[c
] = new N2_Core(*this,n
,strand_id_base
+ 8 * c
);
for (uint_t s
=0; s
< N2_Model::NO_STRANDS_PER_CORE
; s
++)
strand
[i
++] = core
[c
]->strand
[s
];
strand_count
= N2_Model::NO_STRANDS_PER_CPU
;
asi_map
[0x41].add(0x00,this,&strand_available
,
SS_SharedAsiCtrReg::ld64
,0,
SS_SharedAsiCtrReg::rd64
,set_strand_available
);
asi_map
[0x41].add(0x10,this,&strand_enable_status
,
SS_SharedAsiCtrReg::ld64
,0,
SS_SharedAsiCtrReg::rd64
,0);
asi_map
[0x41].add(0x20,this,&strand_enable
,
SS_SharedAsiCtrReg::ld64
,set_strand_enable
,
SS_SharedAsiCtrReg::rd64
,set_strand_enable
);
asi_map
[0x41].add(0x30,this,&xir_steering
,
SS_SharedAsiCtrReg::ld64
,set_xir_steering
,
SS_SharedAsiCtrReg::rd64
,set_xir_steering
);
asi_map
[0x41].add(0x38,this,&tick_enable
,
SS_SharedAsiCtrReg::ld64
,set_tick_enable
,
SS_SharedAsiCtrReg::rd64
,set_tick_enable
);
asi_map
[0x41].add(0x50,this,&strand_running
,
SS_SharedAsiCtrReg::ld64
,set_strand_running
,
SS_SharedAsiCtrReg::rd64
,set_strand_running
);
asi_map
[0x41].add(0x58,this,&strand_running_status
,
SS_SharedAsiCtrReg::ld64
,0,
SS_SharedAsiCtrReg::rd64
,0);
asi_map
[0x41].add(0x60,this,&strand_running
,
0,set_strand_running_w1s
,
0,set_strand_running_w1s
);
asi_map
[0x41].add(0x68,this,&strand_running
,
0,set_strand_running_w1c
,
0,set_strand_running_w1c
);
asi_map
[0x45].add(0x10,this,&overlap_mode
,
0,SS_SharedAsiCtrReg::st64
,
0,SS_SharedAsiCtrReg::wr64
);
asi_map
[0x45].add(0x18,this,&rst_vec_mask
,
SS_SharedAsiCtrReg::ld64
,rst_vec_st64
,
SS_SharedAsiCtrReg::rd64
,rst_vec_st64
);
asi_map
[0x73].add(0x0,this,0,
strand_enable_status
.set_unmasked(~uint64_t(0));
strand_running_status
.set_unmasked(1);
strand_available
= ~uint64_t(0);
strand_enable
= ~uint64_t(0);
xir_steering
= ~uint64_t(0);
change_running(strand_running_status());
for (uint_t s
=0; s
< N2_Model::NO_STRANDS_PER_CPU
; s
++)
strand
[s
]-> merge_asi_map();
void N2_Cpu::hard_reset()/*{{{*/
for (uint_t c
=0; c
<N2_Model::NO_CORES_PER_CPU
; c
++)
void N2_Cpu::warm_reset(bool intp
)/*{{{*/
for (uint_t c
=0; c
<N2_Model::NO_CORES_PER_CPU
; c
++)
core
[c
]->warm_reset(intp
);
void N2_Cpu::xtrn_reset()/*{{{*/
for (uint_t s
=0; s
<N2_Model::NO_STRANDS_PER_CPU
; s
++)
if (xir_steering() & (uint64_t(1) << s
))
void N2_Cpu::snapshot( SS_SnapShot
& ss
)/*{{{*/
// First deal with the common base for snaphot.
// Now handle the N2 specifics like CMP. Note we do not snapshot
// the strand_running_status, as it is restored by the call to
// strand_running_update on ss.do_load() below
strand_available
.snapshot(ss
,prefix
);
strand_enable
.snapshot(ss
,prefix
);
strand_enable_status
.snapshot(ss
,prefix
);
strand_running
.snapshot(ss
,prefix
);
// SS_Strand saves the running flags so we don;t have to call
// strand_running_update() here to propagate the running flags
xir_steering
.snapshot(ss
,prefix
);
tick_enable
.snapshot(ss
,prefix
);
tw_status
.snapshot(ss
,prefix
);
overlap_mode
.snapshot(ss
,prefix
);
intr_w
.snapshot(ss
,prefix
);
rst_vec_mask
.snapshot(ss
,prefix
);
for (int c
=0; c
<N2_Model::NO_CORES_PER_CPU
; c
++)
// Make sure that on snapshot load we propagate the strand running
// flags properly. E.g. the strands shoudl registers themselves
strand_running_update(0);
void N2_Cpu::ras_enable(char*)/*{{{*/
for (int c
=0; c
<N2_Model::NO_CORES_PER_CPU
; c
++)
core
[c
]->ras_enable(NULL
);
void N2_Cpu::strand_running_update( uint_t strand_id
, int cosim
, uint64_t data
)/*{{{*/
strand_enable_status
.lock();
strand_running_status
.lock();
chg
= strand_running_status();
// In non cosim mode (0) update the running status directly.
// In cosim mode (1) we ignore the running status update and
// when we get a status update from rtl (2) we update it with data.
// This is done through the pli CMP_WRITE command.
strand_running_status
.set_unmasked(strand_running() & strand_enable_status());
strand_running_status
.set_unmasked(data
);
run
= strand_running_status();
// The strand that wants to park every strand including itself will remain
// running. This is done to prevent the chip from stalling.
run
= uint64_t(1) << (strand_id
% BITS_PER_CMP_REGISTER
);
strand_running_status
.set_unmasked(run
);
change_running(strand_running_status());
strand_running_status
.unlock();
strand_enable_status
.unlock();
// Find out which strands switched from running to parked or visa versa.
// Notify those strands through our signalling mechanism.
for (int s
= 0; s
< 64; s
++)
SS_Signal
* sgn
= SS_Signal::alloc(SS_Signal::RUNNING
);
sgn
->running
= (run
>> s
) & 1;
strand
[s
]->post_signal(sgn
);
SS_AsiSpace::Error
N2_Cpu::set_strand_available( SS_Node
* _cpu
, void*, SS_Strand
* s
, SS_Vaddr
, uint64_t data
)/*{{{*/
N2_Cpu
* cpu
= (N2_Cpu
*)_cpu
;
cpu
->strand_available
.lock();
cpu
->strand_enable
.lock();
cpu
->strand_enable_status
.lock();
cpu
->xir_steering
.lock();
for (int i
=0; i
< 8; i
++)
if ((data
& byte
) != byte
)
cpu
->strand_available
.set_unmasked(data
);
cpu
->strand_enable_status
.set_unmasked(cpu
->strand_enable() & data
);
cpu
->xir_steering
= data
;
cpu
->xir_steering
.unlock();
cpu
->strand_enable_status
.unlock();
cpu
->strand_enable
.unlock();
cpu
->strand_available
.unlock();
cpu
->strand_running_update(s
->strand_id());
SS_AsiSpace::Error
N2_Cpu::set_strand_enable( SS_Node
* _cpu
, void*, SS_Strand
* s
, SS_Vaddr
, uint64_t data
)/*{{{*/
N2_Cpu
* cpu
= (N2_Cpu
*)_cpu
;
cpu
->strand_available
.lock();
cpu
->strand_enable
.lock();
cpu
->strand_enable_status
.lock();
for (int i
=0; i
< 8; i
++)
if ((data
& byte
) != byte
)
// Core 0 is the default enabled core if all are being disabled
cpu
->strand_enable
= data
;
cpu
->strand_enable_status
.set_unmasked(cpu
->strand_available() & data
);
cpu
->strand_enable
.unlock();
cpu
->strand_enable_status
.unlock();
cpu
->strand_available
.unlock();
cpu
->strand_running_update(s
->strand_id());
SS_AsiSpace::Error
N2_Cpu::set_strand_running( SS_Node
* _cpu
, void*, SS_Strand
* s
, SS_Vaddr
, uint64_t data
)/*{{{*/
N2_Cpu
* cpu
= (N2_Cpu
*)_cpu
;
// In cosim we get CMP_WRITE pli messages to take care of
// timing issues, so just ignore the data here, it gets updated
// by the pli CMP_WRITE command.
if (!s
->sim_state
.cosim())
cpu
->strand_running
.lock();
cpu
->strand_running
= data
;
cpu
->strand_running
.unlock();
cpu
->strand_running_update(s
->strand_id());
SS_AsiSpace::Error
N2_Cpu::set_strand_running_w1s( SS_Node
* _cpu
, void*, SS_Strand
* s
, SS_Vaddr
, uint64_t data
)/*{{{*/
N2_Cpu
* cpu
= (N2_Cpu
*)_cpu
;
// In cosim we get CMP_WRITE pli messages to take care of
// timing issues, so just ignore the data here, it gets updated
// by the pli CMP_WRITE command.
if (!s
->sim_state
.cosim())
cpu
->strand_running
.lock();
cpu
->strand_running
= cpu
->strand_running() | data
;
cpu
->strand_running
.unlock();
cpu
->strand_running_update(s
->strand_id());
SS_AsiSpace::Error
N2_Cpu::set_strand_running_w1c( SS_Node
* _cpu
, void*, SS_Strand
* s
, SS_Vaddr
, uint64_t data
)/*{{{*/
N2_Cpu
* cpu
= (N2_Cpu
*)_cpu
;
// In cosim we get CMP_WRITE pli messages to take care of
// timing issues, so just ignore the data here, it gets updated
// by the pli CMP_WRITE command.
if (!s
->sim_state
.cosim())
cpu
->strand_running
.lock();
cpu
->strand_running
= cpu
->strand_running() &~ data
;
cpu
->strand_running
.unlock();
cpu
->strand_running_update(s
->strand_id());
SS_AsiSpace::Error
N2_Cpu::set_xir_steering( SS_Node
* _cpu
, void*, SS_Strand
* s
, SS_Vaddr
, uint64_t data
)/*{{{*/
N2_Cpu
* cpu
= (N2_Cpu
*)_cpu
;
cpu
->xir_steering
.lock();
cpu
->xir_steering
= data
& cpu
->strand_enable_status();
cpu
->xir_steering
.unlock();
SS_AsiSpace::Error
N2_Cpu::set_tick_enable( SS_Node
* _cpu
, void*, SS_Strand
* s
, SS_Vaddr
, uint64_t data
)/*{{{*/
N2_Cpu
* cpu
= (N2_Cpu
*)_cpu
;
cpu
->tick_enable
.unlock();
void N2_Cpu::set_stepping( uint_t strand_id
)/*{{{*/
// set_strand_stepping() is called when a virtual cpu
// instance is created. This is so when Vonk is used in SAM.
// In that environment we adjust the strand_available flag
// accordingly; mimicing what the service processor should do.
SS_Cpu::set_stepping(strand_id
);
strand_enable_status
.lock();
// Note we don't round strand_available of to the nearest core set of bits.
strand_available
= strand_stepping
[0];
strand_enable_status
.set_unmasked(strand_enable() & strand_available());
strand_available
.unlock();
strand_enable_status
.unlock();
// Set the first strand_id from sam.rc as running; order of sysconf cpu
// lines in the sam.rc file does matter.
strand_running_update(strand_id
);
SS_AsiSpace::Error
N2_Cpu::intr_w_st64( SS_Node
* _cpu
, void*, SS_Strand
* s
, SS_Vaddr
, uint64_t data
)/*{{{*/
N2_Cpu
* cpu
= (N2_Cpu
*)_cpu
;
uint_t strand_id
= cpu
->intr_w
.strand();
// If the strand that is addressed by the cross call is
// enabled it will receive the cross calls. Otherwise
// the crosscall is dropped. In case the strand that is
// called is parked, we unpark it first.
// In cosim mode we drop the crosscall. For timing reasons
// we wait for the DUT to send the cross call INTP packet.
if (!s
->sim_state
.cosim() && (cpu
->strand_enable_status() & (1 << (strand_id
% BITS_PER_CMP_REGISTER
))))
cpu
->strand_running_status
.lock();
if ((cpu
->strand_running_status() & (1 << (strand_id
% BITS_PER_CMP_REGISTER
))) == 0)
cpu
->strand_running_status
.unlock();
cpu
->strand_running
.lock();
cpu
->strand_running
= cpu
->strand_running() | (1 << (strand_id
% BITS_PER_CMP_REGISTER
));
cpu
->strand_running
.unlock();
cpu
->strand_running_update(s
->strand_id());
cpu
->strand_running_status
.unlock();
SS_Signal
* sgn
= s
->msg
.make_signal(SS_Signal::EXTERNAL_INTERRUPT
);
sgn
->irq_type
= cpu
->intr_w
.vector();
cpu
->strand
[strand_id
]->post_signal(sgn
);
SS_AsiSpace::Error
N2_Cpu::rst_vec_st64( SS_Node
* _cpu
, void*, SS_Strand
*, SS_Vaddr va
, uint64_t data
)/*{{{*/
N2_Cpu
* cpu
= (N2_Cpu
*)_cpu
;
cpu
->rst_vec_mask
.lock();
cpu
->rst_vec_mask
.set(data
);
cpu
->rst_vec_mask
.unlock();
// Now set the reset vectors of all the strands ... do we need to place
// locks around this or can we get away with this?
for (int s
=0; s
< N2_Model::NO_STRANDS_PER_CPU
; s
++)
cpu
->strand
[s
]->rstv_addr
= data
? 0x0 : 0xfffffffff0000000;