1/* 2 * Copyright 2009-2012, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2011-2016, Rene Gollent, rene@gollent.com. 4 * Distributed under the terms of the MIT License. 5 */ 6 7#include "RegistersView.h" 8 9#include <stdio.h> 10 11#include <new> 12 13#include <ControlLook.h> 14#include <MenuItem.h> 15#include <PopUpMenu.h> 16#include <Window.h> 17 18#include "table/TableColumns.h" 19 20#include "AppMessageCodes.h" 21#include "Architecture.h" 22#include "AutoDeleter.h" 23#include "CpuState.h" 24#include "GuiSettingsUtils.h" 25#include "Register.h" 26#include "UiUtils.h" 27 28 29enum { 30 MSG_SIMD_RENDER_FORMAT_CHANGED = 'srfc' 31}; 32 33 34static const char* 35GetLabelForSIMDFormat(int format) 36{ 37 switch (format) { 38 case SIMD_RENDER_FORMAT_INT8: 39 return "8-bit integer"; 40 case SIMD_RENDER_FORMAT_INT16: 41 return "16-bit integer"; 42 case SIMD_RENDER_FORMAT_INT32: 43 return "32-bit integer"; 44 case SIMD_RENDER_FORMAT_INT64: 45 return "64-bit integer"; 46 case SIMD_RENDER_FORMAT_FLOAT: 47 return "Float"; 48 case SIMD_RENDER_FORMAT_DOUBLE: 49 return "Double"; 50 } 51 52 return "Unknown"; 53} 54 55 56// #pragma mark - RegisterValueColumn 57 58 59class RegistersView::RegisterValueColumn : public StringTableColumn { 60public: 61 RegisterValueColumn(int32 modelIndex, const char* title, float width, 62 float minWidth, float maxWidth, uint32 truncate = B_TRUNCATE_MIDDLE, 63 alignment align = B_ALIGN_RIGHT) 64 : 65 StringTableColumn(modelIndex, title, width, minWidth, maxWidth, 66 truncate, align) 67 { 68 } 69 70protected: 71 virtual BField* PrepareField(const BVariant& value) const 72 { 73 char buffer[64]; 74 return StringTableColumn::PrepareField( 75 BVariant(UiUtils::VariantToString(value, buffer, sizeof(buffer)), 76 B_VARIANT_DONT_COPY_DATA)); 77 } 78 79 virtual int CompareValues(const BVariant& a, const BVariant& b) 80 { 81 // If neither value is a number, compare the strings. If only one value 82 // is a number, it is considered to be greater. 83 if (!a.IsNumber()) { 84 if (b.IsNumber()) 85 return -1; 86 char bufferA[64]; 87 char bufferB[64]; 88 return StringTableColumn::CompareValues( 89 BVariant(UiUtils::VariantToString(a, bufferA, 90 sizeof(bufferA)), 91 B_VARIANT_DONT_COPY_DATA), 92 BVariant(UiUtils::VariantToString(b, bufferB, 93 sizeof(bufferB)), 94 B_VARIANT_DONT_COPY_DATA)); 95 } 96 97 if (!b.IsNumber()) 98 return 1; 99 100 // If either value is floating point, we compare floating point values. 101 if (a.IsFloat() || b.IsFloat()) { 102 double valueA = a.ToDouble(); 103 double valueB = b.ToDouble(); 104 return valueA < valueB ? -1 : (valueA == valueB ? 0 : 1); 105 } 106 107 uint64 valueA = a.ToUInt64(); 108 uint64 valueB = b.ToUInt64(); 109 return valueA < valueB ? -1 : (valueA == valueB ? 0 : 1); 110 } 111}; 112 113 114// #pragma mark - RegisterTableModel 115 116 117class RegistersView::RegisterTableModel : public TableModel { 118public: 119 RegisterTableModel(Architecture* architecture) 120 : 121 fArchitecture(architecture), 122 fCpuState(NULL), 123 fSIMDFormat(SIMD_RENDER_FORMAT_INT16) 124 { 125 } 126 127 ~RegisterTableModel() 128 { 129 } 130 131 void SetCpuState(CpuState* cpuState) 132 { 133 fCpuState = cpuState; 134 135 NotifyRowsChanged(0, CountRows()); 136 } 137 138 virtual int32 CountColumns() const 139 { 140 return 2; 141 } 142 143 virtual int32 CountRows() const 144 { 145 return fArchitecture->CountRegisters(); 146 } 147 148 inline int32 SIMDRenderFormat() const 149 { 150 return fSIMDFormat; 151 } 152 153 virtual bool GetValueAt(int32 rowIndex, int32 columnIndex, BVariant& value) 154 { 155 if (rowIndex < 0 || rowIndex >= fArchitecture->CountRegisters()) 156 return false; 157 158 const Register* reg = fArchitecture->Registers() + rowIndex; 159 160 switch (columnIndex) { 161 case 0: 162 value.SetTo(reg->Name(), B_VARIANT_DONT_COPY_DATA); 163 return true; 164 case 1: 165 if (fCpuState == NULL) 166 return false; 167 if (!fCpuState->GetRegisterValue(reg, value)) 168 value.SetTo("?", B_VARIANT_DONT_COPY_DATA); 169 else if (reg->Format() == REGISTER_FORMAT_SIMD) { 170 BString output; 171 value.SetTo(UiUtils::FormatSIMDValue(value, 172 reg->BitSize(),fSIMDFormat, output)); 173 } 174 return true; 175 default: 176 return false; 177 } 178 } 179 180 void SetSIMDFormat(int32 format) 181 { 182 if (fSIMDFormat != format) { 183 fSIMDFormat = format; 184 NotifyRowsChanged(0, CountRows()); 185 } 186 } 187 188private: 189private: 190 Architecture* fArchitecture; 191 CpuState* fCpuState; 192 int32 fSIMDFormat; 193}; 194 195 196// #pragma mark - RegistersView 197 198 199RegistersView::RegistersView(Architecture* architecture) 200 : 201 BGroupView(B_VERTICAL), 202 fArchitecture(architecture), 203 fCpuState(NULL), 204 fRegisterTable(NULL), 205 fRegisterTableModel(NULL) 206{ 207 SetName("Registers"); 208} 209 210 211RegistersView::~RegistersView() 212{ 213 SetCpuState(NULL); 214 fRegisterTable->SetTableModel(NULL); 215 delete fRegisterTableModel; 216} 217 218 219/*static*/ RegistersView* 220RegistersView::Create(Architecture* architecture) 221{ 222 RegistersView* self = new RegistersView(architecture); 223 224 try { 225 self->_Init(); 226 } catch (...) { 227 delete self; 228 throw; 229 } 230 231 return self; 232} 233 234 235void 236RegistersView::MessageReceived(BMessage* message) 237{ 238 switch (message->what) { 239 case MSG_SIMD_RENDER_FORMAT_CHANGED: 240 { 241 int32 format; 242 if (message->FindInt32("format", &format) != B_OK) 243 break; 244 245 fRegisterTableModel->SetSIMDFormat(format); 246 } 247 break; 248 249 default: 250 BGroupView::MessageReceived(message); 251 break; 252 } 253} 254 255 256void 257RegistersView::SetCpuState(CpuState* cpuState) 258{ 259 if (cpuState == fCpuState) 260 return; 261 262 if (fCpuState != NULL) 263 fCpuState->ReleaseReference(); 264 265 fCpuState = cpuState; 266 267 if (fCpuState != NULL) 268 fCpuState->AcquireReference(); 269 270 fRegisterTableModel->SetCpuState(fCpuState); 271} 272 273 274void 275RegistersView::LoadSettings(const BMessage& settings) 276{ 277 BMessage tableSettings; 278 if (settings.FindMessage("registerTable", &tableSettings) == B_OK) { 279 GuiSettingsUtils::UnarchiveTableSettings(tableSettings, 280 fRegisterTable); 281 } 282} 283 284 285status_t 286RegistersView::SaveSettings(BMessage& settings) 287{ 288 settings.MakeEmpty(); 289 290 BMessage tableSettings; 291 status_t result = GuiSettingsUtils::ArchiveTableSettings(tableSettings, 292 fRegisterTable); 293 if (result == B_OK) 294 result = settings.AddMessage("registerTable", &tableSettings); 295 296 return result; 297} 298 299 300void 301RegistersView::TableRowInvoked(Table* table, int32 rowIndex) 302{ 303} 304 305 306void 307RegistersView::TableCellMouseDown(Table* table, int32 rowIndex, 308 int32 columnIndex, BPoint screenWhere, uint32 buttons) 309{ 310 if (rowIndex < 0 || rowIndex >= fArchitecture->CountRegisters()) 311 return; 312 313 if ((buttons & B_SECONDARY_MOUSE_BUTTON) == 0) 314 return; 315 316 BVariant value; 317 if (!fRegisterTableModel->GetValueAt(rowIndex, 1, value)) 318 return; 319 320 const Register* reg = fArchitecture->Registers() + rowIndex; 321 if (reg->Format() == REGISTER_FORMAT_FLOAT) { 322 // for floating point registers, we currently have no 323 // context menu options to display. 324 return; 325 } 326 327 BPopUpMenu* menu = new(std::nothrow) BPopUpMenu("Options"); 328 if (menu == NULL) 329 return; 330 331 ObjectDeleter<BPopUpMenu> menuDeleter(menu); 332 333 if (reg->Format() == REGISTER_FORMAT_INTEGER) { 334 BMessage* message = new(std::nothrow) BMessage(MSG_SHOW_INSPECTOR_WINDOW); 335 if (message == NULL) 336 return; 337 338 message->AddUInt64("address", value.ToUInt64()); 339 340 ObjectDeleter<BMessage> messageDeleter(message); 341 BMenuItem* item = new(std::nothrow) BMenuItem("Inspect", message); 342 if (item == NULL) 343 return; 344 345 messageDeleter.Detach(); 346 ObjectDeleter<BMenuItem> itemDeleter(item); 347 if (!menu->AddItem(item)) 348 return; 349 350 itemDeleter.Detach(); 351 352 item->SetTarget(Window()); 353 } else if (reg->Format() == REGISTER_FORMAT_SIMD) { 354 BMenu* formatMenu = new(std::nothrow) BMenu("Format"); 355 if (formatMenu == NULL) 356 return; 357 358 ObjectDeleter<BMenu> formatMenuDeleter(formatMenu); 359 if (!menu->AddItem(formatMenu)) 360 return; 361 formatMenuDeleter.Detach(); 362 363 if (_AddFormatItem(formatMenu, SIMD_RENDER_FORMAT_INT8) != B_OK) 364 return; 365 if (_AddFormatItem(formatMenu, SIMD_RENDER_FORMAT_INT16) != B_OK) 366 return; 367 if (_AddFormatItem(formatMenu, SIMD_RENDER_FORMAT_INT32) != B_OK) 368 return; 369 if (_AddFormatItem(formatMenu, SIMD_RENDER_FORMAT_INT64) != B_OK) 370 return; 371 if (_AddFormatItem(formatMenu, SIMD_RENDER_FORMAT_FLOAT) != B_OK) 372 return; 373 if (_AddFormatItem(formatMenu, SIMD_RENDER_FORMAT_DOUBLE) != B_OK) 374 return; 375 376 formatMenu->SetTargetForItems(this); 377 } 378 379 menuDeleter.Detach(); 380 381 BRect mouseRect(screenWhere, screenWhere); 382 mouseRect.InsetBy(-4.0, -4.0); 383 menu->Go(screenWhere, true, false, mouseRect, true); 384} 385 386 387void 388RegistersView::_Init() 389{ 390 fRegisterTable = new Table("register list", 0, B_FANCY_BORDER); 391 fRegisterTable->SetFont(B_FONT_ROW, be_fixed_font); 392 AddChild(fRegisterTable->ToView()); 393 394 // columns 395 const float padding = be_control_look->DefaultLabelSpacing() * 2; 396 fRegisterTable->AddColumn(new StringTableColumn(0, "Register", 397 be_plain_font->StringWidth("Register") + padding, 40, 1000, 398 B_TRUNCATE_END, B_ALIGN_LEFT)); 399 fRegisterTable->AddColumn(new RegisterValueColumn(1, "Value", 400 be_fixed_font->StringWidth("0xffffffff00000000") + padding, 40, 1000, 401 B_TRUNCATE_END, B_ALIGN_RIGHT)); 402 403 fRegisterTableModel = new RegisterTableModel(fArchitecture); 404 fRegisterTable->SetTableModel(fRegisterTableModel); 405 406 fRegisterTable->AddTableListener(this); 407} 408 409 410status_t 411RegistersView::_AddFormatItem(BMenu* menu, int32 format) 412{ 413 BMessage* message = new(std::nothrow) BMessage( 414 MSG_SIMD_RENDER_FORMAT_CHANGED); 415 if (message == NULL) 416 return B_NO_MEMORY; 417 418 ObjectDeleter<BMessage> messageDeleter(message); 419 if (message->AddInt32("format", format) != B_OK) 420 return B_NO_MEMORY; 421 422 BMenuItem* item = new(std::nothrow) BMenuItem( 423 GetLabelForSIMDFormat(format), message); 424 if (item == NULL) 425 return B_NO_MEMORY; 426 427 messageDeleter.Detach(); 428 ObjectDeleter<BMenuItem> itemDeleter(item); 429 if (!menu->AddItem(item)) 430 return B_NO_MEMORY; 431 432 itemDeleter.Detach(); 433 434 if (format == fRegisterTableModel->SIMDRenderFormat()) 435 item->SetMarked(true); 436 437 return B_OK; 438} 439