2020-12-05 13:08:24 +01:00
# include "debugger_list.h"
2020-02-22 20:42:49 +01:00
# include "gui_settings.h"
2021-01-22 09:11:54 +01:00
# include "qt_utils.h"
2020-02-22 20:42:49 +01:00
# include "breakpoint_handler.h"
2018-03-02 22:40:29 +01:00
# include "Emu/Cell/SPUThread.h"
2020-02-22 20:42:49 +01:00
# include "Emu/Cell/PPUThread.h"
# include "Emu/CPU/CPUDisAsm.h"
# include "Emu/CPU/CPUThread.h"
2021-01-22 09:11:54 +01:00
# include "Emu/RSX/RSXDisAsm.h"
2018-03-02 22:40:29 +01:00
# include "Emu/System.h"
# include <QMouseEvent>
# include <QWheelEvent>
2021-01-22 09:11:54 +01:00
# include <QVBoxLayout>
# include <QLabel>
2018-03-02 22:40:29 +01:00
# include <memory>
constexpr auto qstr = QString : : fromStdString ;
2021-04-07 23:05:18 +02:00
debugger_list : : debugger_list ( QWidget * parent , std : : shared_ptr < gui_settings > gui_settings , breakpoint_handler * handler )
2020-02-21 13:20:10 +01:00
: QListWidget ( parent )
2021-04-07 23:05:18 +02:00
, m_gui_settings ( std : : move ( gui_settings ) )
2020-02-21 13:20:10 +01:00
, m_breakpoint_handler ( handler )
2018-03-02 22:40:29 +01:00
{
setWindowTitle ( tr ( " ASM " ) ) ;
for ( uint i = 0 ; i < m_item_count ; + + i )
{
insertItem ( i , new QListWidgetItem ( " " ) ) ;
}
setSizeAdjustPolicy ( QListWidget : : AdjustToContents ) ;
}
2021-01-22 09:11:54 +01:00
void debugger_list : : UpdateCPUData ( cpu_thread * cpu , CPUDisAsm * disasm )
2018-03-02 22:40:29 +01:00
{
2021-01-22 09:11:54 +01:00
m_cpu = cpu ;
2018-03-02 22:40:29 +01:00
m_disasm = disasm ;
}
u32 debugger_list : : GetCenteredAddress ( u32 address ) const
{
return address - ( ( m_item_count / 2 ) * 4 ) ;
}
2021-03-23 20:51:39 +01:00
void debugger_list : : ShowAddress ( u32 addr , bool select_addr , bool force )
2018-03-02 22:40:29 +01:00
{
auto IsBreakpoint = [ this ] ( u32 pc )
{
2021-01-22 09:11:54 +01:00
return m_cpu & & m_cpu - > id_type ( ) = = 1 & & m_breakpoint_handler - > HasBreakpoint ( pc ) ;
2018-03-02 22:40:29 +01:00
} ;
2021-03-23 20:39:39 +01:00
bool center_pc = m_gui_settings - > GetValue ( gui : : d_centerPC ) . toBool ( ) ;
2020-04-01 00:02:24 +02:00
// How many spaces addr can move down without us needing to move the entire view
const u32 addr_margin = ( m_item_count / ( center_pc ? 2 : 1 ) - 4 ) ; // 4 is just a buffer of 4 spaces at the bottom
2021-01-22 09:11:54 +01:00
if ( m_cpu & & m_cpu - > id_type ( ) = = 0x55 )
{
// RSX instructions' size is not consistent, this is the only valid mode for it
force = true ;
center_pc = false ;
}
2020-04-01 00:02:24 +02:00
if ( force | | addr - m_pc > addr_margin * 4 ) // 4 is the number of bytes in each instruction
2018-03-02 22:40:29 +01:00
{
2020-04-01 00:02:24 +02:00
if ( center_pc )
{
m_pc = GetCenteredAddress ( addr ) ;
}
else
{
m_pc = addr ;
}
2018-03-02 22:40:29 +01:00
}
2021-03-23 20:39:39 +01:00
const auto & default_foreground = palette ( ) . color ( foregroundRole ( ) ) ;
const auto & default_background = palette ( ) . color ( backgroundRole ( ) ) ;
2020-06-13 22:17:51 +02:00
2021-01-22 09:11:54 +01:00
if ( ! m_cpu | | ! m_disasm | | + m_cpu - > state + cpu_flag : : exit + cpu_flag : : wait = = + m_cpu - > state )
2018-03-02 22:40:29 +01:00
{
2020-06-13 22:37:56 +02:00
for ( uint i = 0 ; i < m_item_count ; + + i )
2018-03-02 22:40:29 +01:00
{
2021-03-23 20:39:39 +01:00
QListWidgetItem * list_item = item ( i ) ;
list_item - > setText ( qstr ( fmt : : format ( " [%08x] ?? ?? ?? ??: " , 0 ) ) ) ;
list_item - > setForeground ( default_foreground ) ;
list_item - > setBackground ( default_background ) ;
2018-03-02 22:40:29 +01:00
}
}
else
{
2021-01-22 09:11:54 +01:00
const bool is_spu = m_cpu - > id_type ( ) = = 2 ;
2020-03-19 06:11:59 +01:00
const u32 address_limits = ( is_spu ? 0x3fffc : ~ 3 ) ;
2018-03-02 22:40:29 +01:00
m_pc & = address_limits ;
2020-04-01 00:02:24 +02:00
u32 pc = m_pc ;
2021-03-23 20:39:39 +01:00
for ( uint i = 0 , count = 4 ; i < m_item_count ; + + i , pc = ( pc + count ) & address_limits )
2018-03-02 22:40:29 +01:00
{
2021-03-23 20:39:39 +01:00
QListWidgetItem * list_item = item ( i ) ;
2021-01-22 09:11:54 +01:00
if ( m_cpu - > is_paused ( ) & & pc = = m_cpu - > get_pc ( ) )
2020-06-13 22:17:51 +02:00
{
2021-03-23 20:39:39 +01:00
list_item - > setForeground ( m_text_color_pc ) ;
list_item - > setBackground ( m_color_pc ) ;
2020-06-13 22:17:51 +02:00
}
else if ( IsBreakpoint ( pc ) )
{
2021-03-23 20:39:39 +01:00
list_item - > setForeground ( m_text_color_bp ) ;
list_item - > setBackground ( m_color_bp ) ;
2020-06-13 22:17:51 +02:00
}
else
{
2021-03-23 20:39:39 +01:00
list_item - > setForeground ( default_foreground ) ;
list_item - > setBackground ( default_background ) ;
2020-06-13 22:17:51 +02:00
}
2021-03-23 20:51:39 +01:00
if ( select_addr & & pc = = addr )
{
list_item - > setSelected ( true ) ;
}
2021-03-23 11:33:07 +01:00
if ( m_cpu - > id_type ( ) = = 1 & & ! vm : : check_addr ( pc , 0 ) )
2018-03-02 22:40:29 +01:00
{
2021-03-23 20:39:39 +01:00
list_item - > setText ( ( IsBreakpoint ( pc ) ? " >> " : " " ) + qstr ( fmt : : format ( " [%08x] ?? ?? ?? ??: " , pc ) ) ) ;
2018-03-02 22:40:29 +01:00
count = 4 ;
continue ;
}
2021-01-22 09:11:54 +01:00
if ( m_cpu - > id_type ( ) = = 1 & & ! vm : : check_addr ( pc , vm : : page_executable ) )
2020-05-22 03:48:10 +02:00
{
2020-07-17 10:18:04 +02:00
const u32 data = * vm : : get_super_ptr < atomic_be_t < u32 > > ( pc ) ;
2021-03-23 20:39:39 +01:00
list_item - > setText ( ( IsBreakpoint ( pc ) ? " >> " : " " ) + qstr ( fmt : : format ( " [%08x] %02x %02x %02x %02x: " , pc ,
2020-05-22 03:48:10 +02:00
static_cast < u8 > ( data > > 24 ) ,
static_cast < u8 > ( data > > 16 ) ,
static_cast < u8 > ( data > > 8 ) ,
static_cast < u8 > ( data > > 0 ) ) ) ) ;
count = 4 ;
continue ;
}
2020-12-16 07:53:59 +01:00
count = m_disasm - > disasm ( pc ) ;
2018-03-02 22:40:29 +01:00
2021-01-22 09:11:54 +01:00
if ( ! count )
{
2021-03-23 20:39:39 +01:00
list_item - > setText ( ( IsBreakpoint ( pc ) ? " >> " : " " ) + qstr ( fmt : : format ( " [%08x] ??? ?? ?? " , pc ) ) ) ;
2021-01-22 09:11:54 +01:00
count = 4 ;
continue ;
}
2021-03-23 20:39:39 +01:00
list_item - > setText ( ( IsBreakpoint ( pc ) ? " >> " : " " ) + qstr ( m_disasm - > last_opcode ) ) ;
2018-03-02 22:40:29 +01:00
}
}
setLineWidth ( - 1 ) ;
}
2021-01-22 09:11:54 +01:00
void debugger_list : : scroll ( s32 steps )
{
while ( m_cpu & & m_cpu - > id_type ( ) = = 0x55 & & steps > 0 )
{
// If scrolling forwards (downwards), we can skip entire commands
// Backwards is impossible though
m_pc + = std : : max < u32 > ( m_disasm - > disasm ( m_pc ) , 4 ) ;
steps - - ;
}
2021-03-23 20:51:39 +01:00
ShowAddress ( m_pc + ( steps * 4 ) , false , true ) ;
2021-01-22 09:11:54 +01:00
}
2018-03-02 22:40:29 +01:00
void debugger_list : : keyPressEvent ( QKeyEvent * event )
{
2020-11-23 18:57:34 +01:00
if ( ! isActiveWindow ( ) )
2018-03-02 22:40:29 +01:00
{
return ;
}
switch ( event - > key ( ) )
{
2021-01-22 09:11:54 +01:00
case Qt : : Key_PageUp : scroll ( 0 - m_item_count ) ; return ;
case Qt : : Key_PageDown : scroll ( m_item_count ) ; return ;
case Qt : : Key_Up : scroll ( 1 ) ; return ;
case Qt : : Key_Down : scroll ( - 1 ) ; return ;
case Qt : : Key_I :
{
2021-06-12 15:04:33 +02:00
if ( event - > isAutoRepeat ( ) )
{
return ;
}
2021-01-22 09:11:54 +01:00
if ( m_cpu & & m_cpu - > id_type ( ) = = 0x55 )
{
create_rsx_command_detail ( m_pc , currentRow ( ) ) ;
return ;
}
return ;
}
2018-03-02 22:40:29 +01:00
default : break ;
}
}
2021-01-22 09:11:54 +01:00
void debugger_list : : showEvent ( QShowEvent * event )
{
if ( m_cmd_detail ) m_cmd_detail - > show ( ) ;
QListWidget : : showEvent ( event ) ;
}
void debugger_list : : hideEvent ( QHideEvent * event )
{
if ( m_cmd_detail ) m_cmd_detail - > hide ( ) ;
QListWidget : : hideEvent ( event ) ;
}
void debugger_list : : create_rsx_command_detail ( u32 pc , int row )
{
if ( row < 0 )
{
return ;
}
for ( ; row > 0 ; row - - )
{
// Skip methods
pc + = std : : max < u32 > ( m_disasm - > disasm ( pc ) , 4 ) ;
}
2021-10-12 22:12:30 +02:00
RSXDisAsm rsx_dis = * static_cast < RSXDisAsm * > ( m_disasm ) ;
rsx_dis . change_mode ( cpu_disasm_mode : : list ) ;
2021-01-22 09:11:54 +01:00
// Either invalid or not a method
if ( rsx_dis . disasm ( pc ) < = 4 ) return ;
if ( m_cmd_detail )
{
// Edit the existing dialog
m_detail_label - > setText ( QString : : fromStdString ( rsx_dis . last_opcode ) ) ;
m_cmd_detail - > setFixedSize ( m_cmd_detail - > sizeHint ( ) ) ;
return ;
}
m_cmd_detail = new QDialog ( this ) ;
m_cmd_detail - > setWindowTitle ( tr ( " RSX Command Detail " ) ) ;
m_detail_label = new QLabel ( QString : : fromStdString ( rsx_dis . last_opcode ) , this ) ;
m_detail_label - > setFont ( font ( ) ) ;
gui : : utils : : set_font_size ( * m_detail_label , 10 ) ;
m_detail_label - > setTextInteractionFlags ( Qt : : TextSelectableByMouse | Qt : : TextSelectableByKeyboard ) ;
QVBoxLayout * layout = new QVBoxLayout ( this ) ;
layout - > addWidget ( m_detail_label ) ;
m_cmd_detail - > setLayout ( layout ) ;
m_cmd_detail - > setFixedSize ( m_cmd_detail - > sizeHint ( ) ) ;
m_cmd_detail - > show ( ) ;
connect ( m_cmd_detail , & QDialog : : finished , [ this ] ( int )
{
// Cleanup
std : : exchange ( m_cmd_detail , nullptr ) - > deleteLater ( ) ;
} ) ;
}
2018-03-02 22:40:29 +01:00
void debugger_list : : mouseDoubleClickEvent ( QMouseEvent * event )
{
2020-12-16 15:44:41 +01:00
if ( event - > button ( ) = = Qt : : LeftButton )
2018-03-02 22:40:29 +01:00
{
2021-03-23 20:39:39 +01:00
const int i = currentRow ( ) ;
2018-03-02 22:40:29 +01:00
if ( i < 0 ) return ;
2020-04-01 00:02:24 +02:00
const u32 pc = m_pc + i * 4 ;
2018-03-02 22:40:29 +01:00
// Let debugger_frame know about breakpoint.
// Other option is to add to breakpoint manager directly and have a signal there instead.
// Either the flow goes from debugger_list->breakpoint_manager->debugger_frame, or it goes debugger_list->debugger_frame, and I felt this was easier to read for now.
Q_EMIT BreakpointRequested ( pc ) ;
}
}
void debugger_list : : wheelEvent ( QWheelEvent * event )
{
2021-03-23 20:39:39 +01:00
const QPoint numSteps = event - > angleDelta ( ) / 8 / 15 ; // http://doc.qt.io/qt-5/qwheelevent.html#pixelDelta
2018-03-02 22:40:29 +01:00
const int value = numSteps . y ( ) ;
2020-04-01 00:02:24 +02:00
const auto direction = ( event - > modifiers ( ) = = Qt : : ControlModifier ) ;
2018-03-02 22:40:29 +01:00
2021-01-22 09:11:54 +01:00
scroll ( direction ? value : - value ) ;
2018-03-02 22:40:29 +01:00
}
void debugger_list : : resizeEvent ( QResizeEvent * event )
{
2021-04-07 23:05:18 +02:00
Q_UNUSED ( event )
2018-03-02 22:40:29 +01:00
if ( count ( ) < 1 | | visualItemRect ( item ( 0 ) ) . height ( ) < 1 )
{
return ;
}
m_item_count = ( rect ( ) . height ( ) - frameWidth ( ) * 2 ) / visualItemRect ( item ( 0 ) ) . height ( ) ;
clear ( ) ;
for ( u32 i = 0 ; i < m_item_count ; + + i )
{
insertItem ( i , new QListWidgetItem ( " " ) ) ;
}
if ( horizontalScrollBar ( ) )
{
m_item_count - - ;
delete item ( m_item_count ) ;
}
2021-03-23 20:51:39 +01:00
ShowAddress ( m_pc , false ) ;
2018-03-02 22:40:29 +01:00
}