From 6462ceef24f5c0c878695489aab4bfd0ed2ae2d7 Mon Sep 17 00:00:00 2001 From: joevt Date: Wed, 20 Mar 2024 04:56:11 -0700 Subject: [PATCH 01/17] atimach64gx: Add offset to cursor X position. CUR_HORZ_OFF becomes non-zero when the cursor needs to be drawn to the left of the left edge of the frame buffer. CUR_VERT_OFF is handled differently. When CUR_VERT_OFF is non-zero, CUR_OFFSET is changed to point to the first line of the cursor that will be drawn, so CUR_VERT_OFF is the number of lines to remove from the total height of the cursor. Alternatively, we could handle CUR_VERT_OFF the same way as CUR_HORZ_OFF by leaving the cursor height constant, drawing the cursor starting from the CUR_VERT_OFF line, and adjusting cursor Y position by negative CUR_VERT_OFF. --- devices/video/atimach64gx.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devices/video/atimach64gx.cpp b/devices/video/atimach64gx.cpp index 3e818d3..4c2196e 100644 --- a/devices/video/atimach64gx.cpp +++ b/devices/video/atimach64gx.cpp @@ -726,7 +726,8 @@ void AtiMach64Gx::draw_hw_cursor(uint8_t *dst_buf, int dst_pitch) { } void AtiMach64Gx::get_cursor_position(int& x, int& y) { - x = extract_bits(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_HORZ_POSN, ATI_CUR_HORZ_POSN_size); + x = extract_bits(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_HORZ_POSN, ATI_CUR_HORZ_POSN_size) - + extract_bits(this->regs[ATI_CUR_HORZ_VERT_OFF ], ATI_CUR_HORZ_OFF , ATI_CUR_HORZ_OFF_size ); y = extract_bits(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_VERT_POSN, ATI_CUR_VERT_POSN_size); } From ad6d5e9ec90cf89ee19557ef7b6c6a596678bedc Mon Sep 17 00:00:00 2001 From: joevt Date: Wed, 20 Mar 2024 05:00:21 -0700 Subject: [PATCH 02/17] atimach64gx: Improve draw_hw_cursor loops. - Read 8 bytes at a time instead of just 1. - Remove multiply operations from loop. We just need increments or additions. - Change compares with int to compares with zero. --- devices/video/atimach64gx.cpp | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/devices/video/atimach64gx.cpp b/devices/video/atimach64gx.cpp index 4c2196e..078881c 100644 --- a/devices/video/atimach64gx.cpp +++ b/devices/video/atimach64gx.cpp @@ -686,28 +686,21 @@ void AtiMach64Gx::crtc_update() this->crtc_on = true; } -void AtiMach64Gx::draw_hw_cursor(uint8_t *dst_buf, int dst_pitch) { - uint8_t *src_buf, *src_row, *dst_row, px4; - +void AtiMach64Gx::draw_hw_cursor(uint8_t *dst_row, int dst_pitch) { int vert_offset = extract_bits(this->regs[ATI_CUR_HORZ_VERT_OFF], ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size); - //int horz_offset = extract_bits(this->regs[ATI_CUR_HORZ_VERT_OFF], ATI_CUR_HORZ_OFF, ATI_CUR_HORZ_OFF_size); - - src_buf = &this->vram_ptr[this->regs[ATI_CUR_OFFSET] * 8]; - int cur_height = 64 - vert_offset; uint32_t color0 = this->regs[ATI_CUR_CLR0] | 0x000000FFUL; uint32_t color1 = this->regs[ATI_CUR_CLR1] | 0x000000FFUL; - for (int h = 0; h < cur_height; h++) { - dst_row = &dst_buf[h * dst_pitch]; - src_row = &src_buf[h * 16]; + uint64_t *src_row = (uint64_t *)&this->vram_ptr[this->regs[ATI_CUR_OFFSET] * 8]; + dst_pitch -= 64 * 4; - for (int x = 0; x < 16; x++) { - px4 = src_row[x]; - - for (int p = 0; p < 4; p++, px4 >>= 2, dst_row += 4) { - switch(px4 & 3) { + for (int h = cur_height; h > 0; h--) { + for (int x = 2; x > 0; x--) { + uint64_t px = *src_row++; + for (int p = 32; p > 0; p--, px >>= 2, dst_row += 4) { + switch(px & 3) { case 0: // cursor color 0 WRITE_DWORD_BE_A(dst_row, color0); break; @@ -718,10 +711,12 @@ void AtiMach64Gx::draw_hw_cursor(uint8_t *dst_buf, int dst_pitch) { WRITE_DWORD_BE_A(dst_row, 0); break; case 3: // 1's complement of display pixel + WRITE_DWORD_BE_A(dst_row, 0x0000007F); break; } } } + dst_row += dst_pitch; } } From 9d0bae2d03e0c42ee52fe19dc02a7447638ab1c4 Mon Sep 17 00:00:00 2001 From: joevt Date: Wed, 20 Mar 2024 04:54:03 -0700 Subject: [PATCH 03/17] atirage: Add offset to cursor X position. CUR_HORZ_OFF becomes non-zero when the cursor needs to be drawn to the left of the left edge of the frame buffer. CUR_VERT_OFF is handled differently. When CUR_VERT_OFF is non-zero, CUR_OFFSET is changed to point to the first line of the cursor that will be drawn, so CUR_VERT_OFF is the number of lines to remove from the total height of the cursor. Alternatively, we could handle CUR_VERT_OFF the same way as CUR_HORZ_OFF by leaving the cursor height constant, drawing the cursor starting from the CUR_VERT_OFF line, and adjusting cursor Y position by negative CUR_VERT_OFF. --- devices/video/atirage.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devices/video/atirage.cpp b/devices/video/atirage.cpp index 52afd6c..9f79e54 100644 --- a/devices/video/atirage.cpp +++ b/devices/video/atirage.cpp @@ -797,7 +797,8 @@ void ATIRage::draw_hw_cursor(uint8_t *dst_buf, int dst_pitch) { } void ATIRage::get_cursor_position(int& x, int& y) { - x = extract_bits(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_HORZ_POSN, ATI_CUR_HORZ_POSN_size); + x = extract_bits(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_HORZ_POSN, ATI_CUR_HORZ_POSN_size) - + extract_bits(this->regs[ATI_CUR_HORZ_VERT_OFF ], ATI_CUR_HORZ_OFF , ATI_CUR_HORZ_OFF_size ); y = extract_bits(this->regs[ATI_CUR_HORZ_VERT_POSN], ATI_CUR_VERT_POSN, ATI_CUR_VERT_POSN_size); } From 72b257e5d156acad6ec90c550fdfbf5ed6ba221a Mon Sep 17 00:00:00 2001 From: joevt Date: Wed, 20 Mar 2024 05:12:32 -0700 Subject: [PATCH 04/17] atirage: Improve draw_hw_cursor loops. - Read 8 bytes at a time instead of just 1. - Remove multiply operations from loop. We just need increments or additions. - Change compares with int to compares with zero. --- devices/video/atirage.cpp | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/devices/video/atirage.cpp b/devices/video/atirage.cpp index 9f79e54..ca36a95 100644 --- a/devices/video/atirage.cpp +++ b/devices/video/atirage.cpp @@ -757,42 +757,38 @@ void ATIRage::crtc_update() { this->crtc_on = true; } -void ATIRage::draw_hw_cursor(uint8_t *dst_buf, int dst_pitch) { - uint8_t *src_buf, *src_row, *dst_row, px4; - - int vert_offset = extract_bits(this->regs[ATI_CUR_HORZ_VERT_OFF], ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size); - - src_buf = &this->vram_ptr[this->regs[ATI_CUR_OFFSET] * 8]; - +void ATIRage::draw_hw_cursor(uint8_t* dst_row, int dst_pitch) { + int vert_offset = extract_bits( + this->regs[ATI_CUR_HORZ_VERT_OFF], ATI_CUR_VERT_OFF, ATI_CUR_VERT_OFF_size); int cur_height = 64 - vert_offset; uint32_t color0 = this->regs[ATI_CUR_CLR0] | 0x000000FFUL; uint32_t color1 = this->regs[ATI_CUR_CLR1] | 0x000000FFUL; - for (int h = 0; h < cur_height; h++) { - dst_row = &dst_buf[h * dst_pitch]; - src_row = &src_buf[h * 16]; + uint64_t* src_row = (uint64_t*)&this->vram_ptr[this->regs[ATI_CUR_OFFSET] * 8]; + dst_pitch -= 64 * 4; - for (int x = 0; x < 16; x++) { - px4 = src_row[x]; - - for (int p = 0; p < 4; p++, px4 >>= 2, dst_row += 4) { - switch(px4 & 3) { - case 0: // cursor color 0 + for (int h = cur_height; h > 0; h--) { + for (int x = 2; x > 0; x--) { + uint64_t px = *src_row++; + for (int p = 32; p > 0; p--, px >>= 2, dst_row += 4) { + switch (px & 3) { + case 0: // cursor color 0 WRITE_DWORD_BE_A(dst_row, color0); break; - case 1: // cursor color 1 + case 1: // cursor color 1 WRITE_DWORD_BE_A(dst_row, color1); break; - case 2: // transparent + case 2: // transparent WRITE_DWORD_BE_A(dst_row, 0); break; - case 3: // 1's complement of display pixel + case 3: // 1's complement of display pixel WRITE_DWORD_BE_A(dst_row, 0x0000007F); break; } } } + dst_row += dst_pitch; } } From 5de1c23aba92db6100dfcba0e49fe0b5b4b3ddd1 Mon Sep 17 00:00:00 2001 From: joevt Date: Fri, 15 Mar 2024 00:53:58 -0700 Subject: [PATCH 05/17] adbbus: Don't abort. --- devices/common/adb/adbbus.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devices/common/adb/adbbus.cpp b/devices/common/adb/adbbus.cpp index be94dfa..225e6ee 100644 --- a/devices/common/adb/adbbus.cpp +++ b/devices/common/adb/adbbus.cpp @@ -96,7 +96,7 @@ uint8_t AdbBus::process_command(const uint8_t* in_data, int data_size) { if (!this->got_answer) return ADB_STAT_TIMEOUT; } else { - ABORT_F("%s: unsupported ADB command 0x%X", this->name.c_str(), cmd_byte); + LOG_F(ERROR, "%s: unsupported ADB command 0x%X", this->name.c_str(), cmd_byte); } return ADB_STAT_OK; From d134107aba6f9d5d995f2d36be888de8a155cd70 Mon Sep 17 00:00:00 2001 From: joevt Date: Thu, 25 Jan 2024 23:41:34 -0800 Subject: [PATCH 06/17] atirage: Draw frame buffer only when it changes. --- devices/video/atirage.cpp | 20 ++++++++++++++++++++ devices/video/videoctrl.cpp | 8 +++++--- devices/video/videoctrl.h | 1 + 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/devices/video/atirage.cpp b/devices/video/atirage.cpp index ca36a95..aa462e8 100644 --- a/devices/video/atirage.cpp +++ b/devices/video/atirage.cpp @@ -385,6 +385,16 @@ void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) { } } break; + case ATI_CUR_CLR0: + case ATI_CUR_CLR1: + this->setup_hw_cursor(); + // fallthrough + case ATI_CUR_OFFSET: + case ATI_CUR_HORZ_VERT_POSN: + case ATI_CUR_HORZ_VERT_OFF: + new_value = value; + draw_fb = true; + break; case ATI_GP_IO: new_value = value; if (offset <= 1 && offset + size > 1) { @@ -446,6 +456,7 @@ void ATIRage::write_reg(uint32_t reg_offset, uint32_t value, uint32_t size) { this->setup_hw_cursor(); else this->cursor_on = false; + draw_fb = true; } if (bit_changed(old_value, new_value, ATI_GEN_GUI_RESETB)) { if (!bit_set(new_value, ATI_GEN_GUI_RESETB)) @@ -549,9 +560,11 @@ void ATIRage::write(uint32_t rgn_start, uint32_t offset, uint32_t value, int siz { if (rgn_start == this->aperture_base[0] && offset < this->aperture_size[0]) { if (offset < this->vram_size) { // little-endian VRAM region + draw_fb = true; return write_mem(&this->vram_ptr[offset], value, size); } if (offset >= BE_FB_OFFSET) { // big-endian VRAM region + draw_fb = true; return write_mem(&this->vram_ptr[offset & (BE_FB_OFFSET - 1)], value, size); } //if (!bit_set(this->regs[ATI_BUS_CNTL], ATI_BUS_APER_REG_DIS)) { @@ -695,38 +708,45 @@ void ATIRage::crtc_update() { switch (this->pixel_format) { case 1: this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) { + draw_fb = false; this->convert_frame_4bpp_indexed(dst_buf, dst_pitch); }; break; case 2: if (bit_set(this->regs[ATI_DAC_CNTL], ATI_DAC_DIRECT)) { this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) { + draw_fb = false; this->convert_frame_8bpp(dst_buf, dst_pitch); }; } else { this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) { + draw_fb = false; this->convert_frame_8bpp_indexed(dst_buf, dst_pitch); }; } break; case 3: this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) { + draw_fb = false; this->convert_frame_15bpp_BE(dst_buf, dst_pitch); }; break; case 4: this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) { + draw_fb = false; this->convert_frame_16bpp(dst_buf, dst_pitch); }; break; case 5: this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) { + draw_fb = false; this->convert_frame_24bpp(dst_buf, dst_pitch); }; break; case 6: this->convert_fb_cb = [this](uint8_t *dst_buf, int dst_pitch) { + draw_fb = false; this->convert_frame_32bpp_BE(dst_buf, dst_pitch); }; break; diff --git a/devices/video/videoctrl.cpp b/devices/video/videoctrl.cpp index 79d2d6f..71151f1 100644 --- a/devices/video/videoctrl.cpp +++ b/devices/video/videoctrl.cpp @@ -74,9 +74,11 @@ void VideoCtrlBase::update_screen() this->get_cursor_position(cursor_x, cursor_y); } - this->display.update( - this->convert_fb_cb, this->cursor_ovl_cb, - this->cursor_on, cursor_x, cursor_y); + if (draw_fb) { + this->display.update( + this->convert_fb_cb, this->cursor_ovl_cb, + this->cursor_on, cursor_x, cursor_y); + } } void VideoCtrlBase::start_refresh_task() { diff --git a/devices/video/videoctrl.h b/devices/video/videoctrl.h index f6cf3cf..855d6de 100644 --- a/devices/video/videoctrl.h +++ b/devices/video/videoctrl.h @@ -85,6 +85,7 @@ protected: int pixel_format; float pixel_clock; float refresh_rate; + bool draw_fb = true; uint32_t palette[256]; // internal DAC palette in RGBA format From e3411670cb7ba7c44d1ab6e27a69fa61fd46b2f2 Mon Sep 17 00:00:00 2001 From: joevt Date: Wed, 20 Mar 2024 04:38:01 -0700 Subject: [PATCH 07/17] videoctrl: Add cursor_dirty flag. If the flag is set when it comes time to draw the cursor again, then call setup_hw_cursor to update the cursor before drawing the cursor. --- devices/video/videoctrl.cpp | 4 ++++ devices/video/videoctrl.h | 1 + 2 files changed, 5 insertions(+) diff --git a/devices/video/videoctrl.cpp b/devices/video/videoctrl.cpp index 71151f1..988d20f 100644 --- a/devices/video/videoctrl.cpp +++ b/devices/video/videoctrl.cpp @@ -75,6 +75,10 @@ void VideoCtrlBase::update_screen() } if (draw_fb) { + if (this->cursor_dirty) { + this->setup_hw_cursor(); + this->cursor_dirty = false; + } this->display.update( this->convert_fb_cb, this->cursor_ovl_cb, this->cursor_on, cursor_x, cursor_y); diff --git a/devices/video/videoctrl.h b/devices/video/videoctrl.h index 855d6de..05f8458 100644 --- a/devices/video/videoctrl.h +++ b/devices/video/videoctrl.h @@ -75,6 +75,7 @@ protected: bool crtc_on = false; bool blank_on = true; bool cursor_on = false; + bool cursor_dirty = false; int active_width; // width of the visible display area int active_height; // height of the visible display area int hori_total = 0; From fd961f9ff979d4d5bd15b04011b266d043379cec Mon Sep 17 00:00:00 2001 From: joevt Date: Tue, 15 Aug 2023 15:25:36 -0700 Subject: [PATCH 08/17] Fix Analyzer warnings. In Xcode, type Command-Shift-B to analyze every source file or Command-Shift-Control-B to analyze the current source file. For pseudo_dma_read report FIFO underrun and init data_word in that case. --- devices/common/scsi/sc53c94.cpp | 4 ++++ devices/common/scsi/scsicdrom.cpp | 3 +-- devices/sound/awacs.cpp | 3 ++- devices/sound/burgundy.cpp | 6 ++++-- machines/machinefactory.cpp | 4 ++-- 5 files changed, 13 insertions(+), 7 deletions(-) diff --git a/devices/common/scsi/sc53c94.cpp b/devices/common/scsi/sc53c94.cpp index 769fa99..02e8e2c 100644 --- a/devices/common/scsi/sc53c94.cpp +++ b/devices/common/scsi/sc53c94.cpp @@ -185,6 +185,10 @@ uint16_t Sc53C94::pseudo_dma_read() } } } + else { + LOG_F(ERROR, "SC53C94: FIFO underrun %d", data_fifo_pos); + data_word = 0; + } // see if we need to refill FIFO if (!this->data_fifo_pos && !is_done) { diff --git a/devices/common/scsi/scsicdrom.cpp b/devices/common/scsi/scsicdrom.cpp index 635c12c..1b7474a 100644 --- a/devices/common/scsi/scsicdrom.cpp +++ b/devices/common/scsi/scsicdrom.cpp @@ -28,7 +28,6 @@ along with this program. If not, see . #include #include -#include #include using namespace std; @@ -239,7 +238,7 @@ static char Apple_Copyright_Page_Data[] = "APPLE COMPUTER, INC "; void ScsiCdrom::mode_sense() { uint8_t page_code = this->cmd_buf[2] & 0x3F; - uint8_t alloc_len = this->cmd_buf[4]; + //uint8_t alloc_len = this->cmd_buf[4]; int num_blocks = this->size_blocks; diff --git a/devices/sound/awacs.cpp b/devices/sound/awacs.cpp index f169d2e..aba3113 100644 --- a/devices/sound/awacs.cpp +++ b/devices/sound/awacs.cpp @@ -82,7 +82,8 @@ void AwacsBase::dma_out_start() { if (!this->out_stream_running) { if ((err = snd_server->start_out_stream())) { - LOG_F(ERROR, "%s: could not start sound output stream", this->name.c_str()); + LOG_F(ERROR, "%s: could not start sound output stream: %d", + this->name.c_str(), err); } } } diff --git a/devices/sound/burgundy.cpp b/devices/sound/burgundy.cpp index 97be2d8..c2d8cd1 100644 --- a/devices/sound/burgundy.cpp +++ b/devices/sound/burgundy.cpp @@ -62,7 +62,9 @@ uint32_t BurgundyCodec::snd_ctrl_read(uint32_t offset, int size) { } void BurgundyCodec::snd_ctrl_write(uint32_t offset, uint32_t value, int size) { - uint8_t reg_addr, cur_byte, last_byte; + uint8_t reg_addr; + uint8_t cur_byte; + //uint8_t last_byte; value = BYTESWAP_32(value); @@ -71,7 +73,7 @@ void BurgundyCodec::snd_ctrl_write(uint32_t offset, uint32_t value, int size) { this->last_ctrl_data = value; reg_addr = (value >> 12) & 0xFF; cur_byte = (value >> 8) & 3; - last_byte = (value >> 10) & 3; + //last_byte = (value >> 10) & 3; if (value & BURGUNDY_REG_WR) { uint32_t mask = 0xFFU << (cur_byte * 8); this->reg_array[reg_addr] = (this->reg_array[reg_addr] & ~mask) | diff --git a/machines/machinefactory.cpp b/machines/machinefactory.cpp index 5c49fff..e59414e 100644 --- a/machines/machinefactory.cpp +++ b/machines/machinefactory.cpp @@ -342,7 +342,7 @@ int MachineFactory::load_boot_rom(string& rom_filepath) { size_t file_size; int result = 0; uint32_t rom_load_addr; - AddressMapEntry *rom_reg; + //AddressMapEntry *rom_reg; rom_file.open(rom_filepath, ios::in | ios::binary); if (rom_file.fail()) { @@ -373,7 +373,7 @@ int MachineFactory::load_boot_rom(string& rom_filepath) { MemCtrlBase* mem_ctrl = dynamic_cast( gMachineObj->get_comp_by_type(HWCompType::MEM_CTRL)); - if ((rom_reg = mem_ctrl->find_rom_region())) { + if ((/*rom_reg = */mem_ctrl->find_rom_region())) { mem_ctrl->set_data(rom_load_addr, sysrom_mem, (uint32_t)file_size); } else { LOG_F(ERROR, "Could not locate physical ROM region!"); From 503556196a417f66016fbf252cb45dc81158acab Mon Sep 17 00:00:00 2001 From: joevt Date: Thu, 27 Jul 2023 11:39:19 -0700 Subject: [PATCH 09/17] dbdma: Add missing flags, fields, comments. --- devices/common/dbdma.cpp | 8 +++++--- devices/common/dbdma.h | 38 +++++++++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/devices/common/dbdma.cpp b/devices/common/dbdma.cpp index d2adcc3..dd741c0 100644 --- a/devices/common/dbdma.cpp +++ b/devices/common/dbdma.cpp @@ -130,7 +130,7 @@ void DMAChannel::finish_cmd() { this->cur_cmd = cmd_desc[3] >> 4; // all commands except STOP update cmd.xferStatus and - // perform actions under control of "i", "b" and "w" bits + // perform actions under control of "i" interrupt, "b" branch, and "w" wait bits if (this->cur_cmd < DBDMA_Cmd::STOP) { // react to cmd.w (wait) bits if (cmd_desc[2] & 3) { @@ -344,8 +344,10 @@ void DMAChannel::reg_write(uint32_t offset, uint32_t value, int size) { break; case DMAReg::CH_STAT: break; // ingore writes to ChannelStatus - case DMAReg::CMD_PTR_HI: // Mac OS X writes this optional register with zero - LOG_F(9, "CommandPtrHi set to 0x%X", value); + case DMAReg::CMD_PTR_HI: + if (value != 0) { + LOG_F(WARNING, "%s: Unsupported DMA channel register write @%02x.%c = %0*x", this->get_name().c_str(), offset, SIZE_ARG(size), size * 2, value); + } break; case DMAReg::CMD_PTR_LO: if (!(this->ch_stat & CH_STAT_RUN) && !(this->ch_stat & CH_STAT_ACTIVE)) { diff --git a/devices/common/dbdma.h b/devices/common/dbdma.h index 02ac9cd..cb40ca1 100644 --- a/devices/common/dbdma.h +++ b/devices/common/dbdma.h @@ -40,28 +40,48 @@ class InterruptCtrl; enum DMAReg : uint32_t { CH_CTRL = 0, CH_STAT = 4, - CMD_PTR_HI = 8, + CMD_PTR_HI = 8, // not implemented CMD_PTR_LO = 12, INT_SELECT = 16, BRANCH_SELECT = 20, WAIT_SELECT = 24, +// TANSFER_MODES = 28, +// DATA_2_PTR_HI = 32, // not implemented +// DATA_2_PTR_LO = 36, +// RESERVED_1 = 40, +// ADDRESS_HI = 44, +// RESERVED_2_0 = 48, +// RESERVED_2_1 = 52, +// RESERVED_2_2 = 56, +// RESERVED_2_3 = 60, +// UNIMPLEMENTED = 64, +// UNDEFINED = 128, }; /** Channel Status bits (DBDMA spec, 5.5.3) */ enum : uint16_t { - CH_STAT_ACTIVE = 0x400, - CH_STAT_DEAD = 0x800, - CH_STAT_WAKE = 0x1000, - CH_STAT_FLUSH = 0x2000, - CH_STAT_PAUSE = 0x4000, - CH_STAT_RUN = 0x8000 + CH_STAT_S0 = 0x0001, // general purpose status and control + CH_STAT_S1 = 0x0002, // general purpose status and control + CH_STAT_S2 = 0x0004, // general purpose status and control + CH_STAT_S3 = 0x0008, // general purpose status and control + CH_STAT_S4 = 0x0010, // general purpose status and control + CH_STAT_S5 = 0x0020, // general purpose status and control + CH_STAT_S6 = 0x0040, // general purpose status and control + CH_STAT_S7 = 0x0080, // general purpose status and control + CH_STAT_BT = 0x0100, // hardware status bit + CH_STAT_ACTIVE = 0x0400, // hardware status bit + CH_STAT_DEAD = 0x0800, // hardware status bit + CH_STAT_WAKE = 0x1000, // command bit set by software and cleared by hardware once the action has been performed + CH_STAT_FLUSH = 0x2000, // command bit set by software and cleared by hardware once the action has been performed + CH_STAT_PAUSE = 0x4000, // control bit set and cleared by software + CH_STAT_RUN = 0x8000 // control bit set and cleared by software }; /** DBDMA command (DBDMA spec, 5.6.1) - all fields are little-endian! */ typedef struct DMACmd { uint16_t req_count; - uint8_t cmd_bits; - uint8_t cmd_key; + uint8_t cmd_bits; // wait: & 3, branch: & 0xC, interrupt: & 0x30, reserved: & 0xc0 + uint8_t cmd_key; // key: & 7, reserved: & 8, cmd: >> 4 uint32_t address; uint32_t cmd_arg; uint16_t res_count; From df0044a110c999e3264744d48b99c6edc16d8ea1 Mon Sep 17 00:00:00 2001 From: joevt Date: Tue, 17 Oct 2023 20:32:46 -0700 Subject: [PATCH 10/17] dbdma: Make sure interrupt controller is set. --- devices/common/dbdma.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/devices/common/dbdma.cpp b/devices/common/dbdma.cpp index dd741c0..2e8e424 100644 --- a/devices/common/dbdma.cpp +++ b/devices/common/dbdma.cpp @@ -258,7 +258,10 @@ void DMAChannel::update_irq() { } } if (cond) { - this->int_ctrl->ack_dma_int(this->irq_id, 1); + if (int_ctrl) + this->int_ctrl->ack_dma_int(this->irq_id, 1); + else + LOG_F(ERROR, "%s Interrupt ignored", this->get_name().c_str()); } } } From bc582e64cce0781eb2c9d28e6c1db40bf56ff07f Mon Sep 17 00:00:00 2001 From: joevt Date: Mon, 30 Oct 2023 19:06:03 -0700 Subject: [PATCH 11/17] dbdma: Clear cmd_in_progress before callback. Because the callback might start DMA commands. --- devices/common/dbdma.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devices/common/dbdma.cpp b/devices/common/dbdma.cpp index 2e8e424..3f2f4e7 100644 --- a/devices/common/dbdma.cpp +++ b/devices/common/dbdma.cpp @@ -467,11 +467,11 @@ void DMAChannel::start() { this->queue_len = 0; + this->cmd_in_progress = false; + if (this->start_cb) this->start_cb(); - this->cmd_in_progress = false; - // some DBDMA programs contain commands that don't transfer data // between a device and memory (LOAD_QUAD, STORE_QUAD, NOP and STOP). // We thus interprete the DBDMA program until a data transfer between From fafbd9a04f2a225ca27f7b8689e7cad6dfd0f664 Mon Sep 17 00:00:00 2001 From: joevt Date: Fri, 8 Mar 2024 00:17:27 -0800 Subject: [PATCH 12/17] mmiodevice: Move SIZE_ARG macro from pcibase. --- devices/common/mmiodevice.h | 3 +++ devices/common/pci/pcibase.h | 3 --- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/devices/common/mmiodevice.h b/devices/common/mmiodevice.h index 41b86a0..730e79e 100644 --- a/devices/common/mmiodevice.h +++ b/devices/common/mmiodevice.h @@ -36,4 +36,7 @@ public: virtual ~MMIODevice() = default; }; +#define SIZE_ARG(size) (size == 4 ? 'l' : size == 2 ? 'w' : \ + size == 1 ? 'b' : '0' + size) + #endif /* MMIO_DEVICE_H */ diff --git a/devices/common/pci/pcibase.h b/devices/common/pci/pcibase.h index 4a3f88c..4553157 100644 --- a/devices/common/pci/pcibase.h +++ b/devices/common/pci/pcibase.h @@ -197,9 +197,6 @@ inline uint32_t pci_cfg_log(uint32_t value, AccessDetails &details) { } } -#define SIZE_ARG(size) (size == 4 ? 'l' : size == 2 ? 'w' : \ - size == 1 ? 'b' : '0' + size) - #define LOG_READ_UNIMPLEMENTED_CONFIG_REGISTER() \ do { if ((details.flags & PCI_CONFIG_DIRECTION) == PCI_CONFIG_READ) { \ VLOG_F( \ From 505b5e64682843ce4c1a7741f79ace69177d7505 Mon Sep 17 00:00:00 2001 From: dingusdev <52434309+dingusdev@users.noreply.github.com> Date: Sun, 24 Mar 2024 15:35:11 -0700 Subject: [PATCH 13/17] Slight tweak to PPC Macros --- cpu/ppc/ppcfpopcodes.cpp | 4 ---- cpu/ppc/ppcmacros.h | 2 ++ 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cpu/ppc/ppcfpopcodes.cpp b/cpu/ppc/ppcfpopcodes.cpp index 4a221a1..72faae3 100644 --- a/cpu/ppc/ppcfpopcodes.cpp +++ b/cpu/ppc/ppcfpopcodes.cpp @@ -30,12 +30,8 @@ along with this program. If not, see . #include #include -// Used for FP calcs - // Storage and register retrieval functions for the floating point functions. -#define GET_FPR(reg) ppc_state.fpr[(reg)].dbl64_r - double fp_return_double(uint32_t reg) { return ppc_state.fpr[reg].dbl64_r; } diff --git a/cpu/ppc/ppcmacros.h b/cpu/ppc/ppcmacros.h index 1630f95..4f40f95 100644 --- a/cpu/ppc/ppcmacros.h +++ b/cpu/ppc/ppcmacros.h @@ -112,6 +112,8 @@ along with this program. If not, see . int reg_d = (opcode >> 21) & 31; \ int reg_b = (opcode >> 11) & 31; +#define GET_FPR(reg) ppc_state.fpr[(reg)].dbl64_r + #define ppc_grab_regsfpdiab(opcode) \ int reg_d = (opcode >> 21) & 31; \ int reg_a = (opcode >> 16) & 31; \ From eab021a5cb6c4e9e8855ef7b1b7c53212038b5fb Mon Sep 17 00:00:00 2001 From: dingusdev <52434309+dingusdev@users.noreply.github.com> Date: Sun, 24 Mar 2024 16:34:42 -0700 Subject: [PATCH 14/17] Regression fixes --- cpu/ppc/ppcmacros.h | 2 +- cpu/ppc/ppcopcodes.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cpu/ppc/ppcmacros.h b/cpu/ppc/ppcmacros.h index 4f40f95..2b8f059 100644 --- a/cpu/ppc/ppcmacros.h +++ b/cpu/ppc/ppcmacros.h @@ -94,7 +94,7 @@ along with this program. If not, see . uint32_t ppc_result_b = ppc_state.gpr[reg_b]; #define ppc_store_iresult_reg(reg, ppc_result)\ - ppc_state.gpr[(reg)] = ppc_result; + ppc_state.gpr[reg] = ppc_result; #define ppc_store_sfpresult_int(reg, ppc_result64_d)\ ppc_state.fpr[(reg)].int64_r = ppc_result64_d; diff --git a/cpu/ppc/ppcopcodes.cpp b/cpu/ppc/ppcopcodes.cpp index e96dfdd..294a07d 100644 --- a/cpu/ppc/ppcopcodes.cpp +++ b/cpu/ppc/ppcopcodes.cpp @@ -512,7 +512,7 @@ void dppc_interpreter::ppc_mulli() { } void dppc_interpreter::ppc_divw() { - uint32_t ppc_result_d; + uint32_t ppc_result_d = 0; ppc_grab_regsdab(ppc_cur_instruction); if (!ppc_result_b) { /* handle the "anything / 0" case */ @@ -542,7 +542,7 @@ void dppc_interpreter::ppc_divw() { } void dppc_interpreter::ppc_divwu() { - uint32_t ppc_result_d; + uint32_t ppc_result_d = 0; ppc_grab_regsdab(ppc_cur_instruction); if (!ppc_result_b) { /* division by zero */ @@ -604,7 +604,7 @@ void dppc_interpreter::ppc_sraw() { if (ppc_result_b & 0x20) { // fill rA with the sign bit of rS - uint32_t ppc_result_a = int32_t(ppc_result_d) >> 31; + ppc_result_a = int32_t(ppc_result_d) >> 31; if (ppc_result_a) // if rA is negative ppc_state.spr[SPR::XER] |= XER::CA; } else { From bc5fd441724fc32e1fa8e39737ebd4f4cf12918b Mon Sep 17 00:00:00 2001 From: joevt Date: Wed, 20 Mar 2024 01:30:49 -0700 Subject: [PATCH 15/17] ppcmmu: Don't log mmu_mode 1. --- cpu/ppc/ppcmmu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu/ppc/ppcmmu.cpp b/cpu/ppc/ppcmmu.cpp index 5a43b83..f252f4c 100644 --- a/cpu/ppc/ppcmmu.cpp +++ b/cpu/ppc/ppcmmu.cpp @@ -391,7 +391,7 @@ void mmu_change_mode() break; case 1: // user mode can't disable translations - LOG_F(ERROR, "instruction mmu mode 1 is invalid!"); + //LOG_F(ERROR, "instruction mmu mode 1 is invalid!"); // this happens alot. Maybe it's not invalid? mmu_mode = 3; case 3: // user mode with instruction translation enabled pCurITLB1 = &itlb1_mode3[0]; From cd77e361ab9296eae933ab8f40874170d6e1282c Mon Sep 17 00:00:00 2001 From: joevt Date: Wed, 20 Mar 2024 01:29:44 -0700 Subject: [PATCH 16/17] ppcexceptions: Use MSR enums. --- cpu/ppc/ppcexceptions.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpu/ppc/ppcexceptions.cpp b/cpu/ppc/ppcexceptions.cpp index 5e7a588..b5c5e3f 100644 --- a/cpu/ppc/ppcexceptions.cpp +++ b/cpu/ppc/ppcexceptions.cpp @@ -115,7 +115,7 @@ void ppc_exception_handler(Except_Type exception_type, uint32_t srr1_bits) { ppc_state.spr[SPR::SRR1] = (ppc_state.msr & 0x0000FF73) | srr1_bits; ppc_state.msr &= 0xFFFB1041; /* copy MSR[ILE] to MSR[LE] */ - ppc_state.msr = (ppc_state.msr & 0xFFFFFFFE) | ((ppc_state.msr >> 16) & 1); + ppc_state.msr = (ppc_state.msr & ~MSR::LE) | !!(ppc_state.msr & MSR::ILE); if (ppc_state.msr & MSR::IP) { ppc_next_instruction_address |= 0xFFF00000; From c5ac862cef2b7df3757a2a59e8e10428b82662ce Mon Sep 17 00:00:00 2001 From: joevt Date: Mon, 7 Aug 2023 12:41:29 -0700 Subject: [PATCH 17/17] debugger: Add list of input and output registers. So the debugger can show them during stepping. The fmt_* functions now take a PPCDisasmContext instead of just the ctx->instr_str so that they can alter the context. Some fmt_* functions have an alternate (e.g. fmt_twoop_in for fmt_twoop) to indicate a difference in input/output registers. The mtsrin and mfsrin instructions use a register to indicate which sr register to use. The string instructions may affect multiple registers but only the first is included in the list. Removed some extra blank lines. Fixes: lscbx: Add r0 check. mftb: Do simplified if the spr is illegal. Maybe should do illegal opcode instead? --- cpu/ppc/ppcdisasm.cpp | 935 +++++++++++++++++++++++++++++++++--------- cpu/ppc/ppcdisasm.h | 3 + 2 files changed, 734 insertions(+), 204 deletions(-) diff --git a/cpu/ppc/ppcdisasm.cpp b/cpu/ppc/ppcdisasm.cpp index 0e170c5..70347d6 100644 --- a/cpu/ppc/ppcdisasm.cpp +++ b/cpu/ppc/ppcdisasm.cpp @@ -1,6 +1,6 @@ /* DingusPPC - The Experimental PowerPC Macintosh emulator -Copyright (C) 2018-21 divingkatae and maximum +Copyright (C) 2018-24 divingkatae and maximum (theweirdo) spatium (Contact divingkatae#1017 or powermax#2286 on Discord for more info) @@ -34,6 +34,9 @@ along with this program. If not, see . using namespace std; +/* debugging support API */ +uint64_t get_reg(std::string reg_name); /* get content of the register reg_name */ + template std::string my_sprintf(const char* format, Args... args) { char buf_small[32]; @@ -49,6 +52,30 @@ std::string my_sprintf(const char* format, Args... args) { return str; } +template +std::string add_reg(std::vector ®s, const char* format, Args... args) { + std::string str = my_sprintf(format, args...); + std::vector::iterator it; + it = std::find(regs.begin(), regs.end(), str); + if (it != regs.end()) { + return *it; + } + else { + regs.push_back(str); + return regs.back(); + } +} + +template +std::string add_reg_in(PPCDisasmContext *ctx, const char* format, Args... args) { + return add_reg(ctx->regs_in, format, args...); +} + +template +std::string add_reg_out(PPCDisasmContext *ctx, const char* format, Args... args) { + return add_reg(ctx->regs_out, format, args...); +} + const char* arith_im_mnem[9] = {"mulli", "subfic", "", "", "", "addic", "addic.", "addi", "addis"}; const char* bx_mnem[4] = {"b", "bl", "ba", "bla"}; @@ -258,59 +285,110 @@ const char* spr_index31[32] = { }; /** various formatting helpers. */ -void fmt_oneop(string& buf, const char* opc, int src) { - buf = my_sprintf("%-8sr%d", opc, src); +void fmt_oneop(PPCDisasmContext* ctx, const char* opc, int src) { + ctx->instr_str = my_sprintf("%-8sr%d", opc, src); + add_reg_in(ctx, "r%d", src); } -void fmt_twoop(string& buf, const char* opc, int dst, int src) { - buf = my_sprintf("%-8sr%d, r%d", opc, dst, src); +void fmt_oneop_out(PPCDisasmContext* ctx, const char* opc, int dst) { + ctx->instr_str = my_sprintf("%-8sr%d", opc, dst); + add_reg_out(ctx, "r%d", dst); } -void fmt_twoop_simm(string& buf, const char* opc, int dst, int imm) { - buf = my_sprintf("%-8sr%d, %s0x%X", opc, dst, (imm < 0) ? "-" : "", abs(imm)); +void fmt_twoop(PPCDisasmContext* ctx, const char* opc, int dst, int src) { + ctx->instr_str = my_sprintf("%-8sr%d, r%d", opc, dst, src); + add_reg_in(ctx, "r%d", src); + add_reg_out(ctx, "r%d", dst); } -void fmt_twoop_fromspr(string& buf, const char* opc, int dst, int src) { - buf = my_sprintf("%-8sr%d, spr%d", opc, dst, src); +void fmt_twoop_in(PPCDisasmContext* ctx, const char* opc, int dst, int src) { + ctx->instr_str = my_sprintf("%-8sr%d, r%d", opc, dst, src); + add_reg_in(ctx, "r%d", src); + add_reg_in(ctx, "r%d", dst); } -void fmt_twoop_tospr(string& buf, const char* opc, int dst, int src) { - buf = my_sprintf("%-8sspr%d, r%d", opc, dst, src); +void fmt_twoop_simm(PPCDisasmContext* ctx, const char* opc, int dst, int imm) { + ctx->instr_str = my_sprintf("%-8sr%d, %s0x%X", opc, dst, (imm < 0) ? "-" : "", abs(imm)); + add_reg_out(ctx, "r%d", dst); } -void fmt_twoop_flt(string& buf, const char* opc, int dst, int src1) { - buf = my_sprintf("%-8sf%d, f%d", opc, dst, src1); +void fmt_twoop_fromspr(PPCDisasmContext* ctx, const char* opc, int dst, int src) { + ctx->instr_str = my_sprintf("%-8spr%d, spr%d", opc, dst, src); + add_reg_in(ctx, "spr%d", src); + add_reg_out(ctx, "r%d", dst); } -void fmt_threeop(string& buf, const char* opc, int dst, int src1, int src2) { - buf = my_sprintf("%-8sr%d, r%d, r%d", opc, dst, src1, src2); +void fmt_twoop_tospr(PPCDisasmContext* ctx, const char* opc, int dst, int src) { + ctx->instr_str = my_sprintf("%-8sspr%d, r%d", opc, dst, src); + add_reg_in(ctx, "r%d", src); + add_reg_out(ctx, "spr%d", dst); } -void fmt_threeop_crb(string& buf, const char* opc, int dst, int src1, int src2) { - buf = my_sprintf("%-8scrb%d, crb%d, crb%d", opc, dst, src1, src2); +void fmt_twoop_flt(PPCDisasmContext* ctx, const char* opc, int dst, int src1) { + ctx->instr_str = my_sprintf("%-8sf%d, f%d", opc, dst, src1); + add_reg_in(ctx, "f%d", src1); + add_reg_out(ctx, "f%d", dst); } -void fmt_threeop_uimm(string& buf, const char* opc, int dst, int src1, int imm) { - buf = my_sprintf("%-8sr%d, r%d, 0x%X", opc, dst, src1, imm); +void fmt_threeop(PPCDisasmContext* ctx, const char* opc, int dst, int src1, int src2) { + ctx->instr_str = my_sprintf("%-8sr%d, r%d, r%d", opc, dst, src1, src2); + add_reg_in(ctx, "r%d", src1); + add_reg_in(ctx, "r%d", src2); + add_reg_out(ctx, "r%d", dst); } -void fmt_threeop_simm(string& buf, const char* opc, int dst, int src1, int imm) { - buf = my_sprintf("%-8sr%d, r%d, %s0x%X", opc, dst, src1, (imm < 0) ? "-" : "", abs(imm)); +void fmt_threeop_store(PPCDisasmContext* ctx, const char* opc, int dst, int src1, int src2) { + ctx->instr_str = my_sprintf("%-7s r%d, r%d, r%d", opc, dst, src1, src2); + add_reg_in(ctx, "r%d", dst); + add_reg_in(ctx, "r%d", src1); + add_reg_in(ctx, "r%d", src2); } -void fmt_threeop_flt(string& buf, const char* opc, int dst, int src1, int src2) { - buf = my_sprintf("%-8sf%d, f%d, f%d", opc, dst, src1, src2); +void fmt_threeop_crb(PPCDisasmContext* ctx, const char* opc, int dst, int src1, int src2) { + ctx->instr_str = my_sprintf("%-8scrb%d, crb%d, crb%d", opc, dst, src1, src2); + add_reg_in(ctx, "cr"); + add_reg_out(ctx, "cr"); } -void fmt_fourop_flt(string& buf, const char* opc, int dst, int src1, int src2, int src3) { - buf = my_sprintf("%-8sf%d, f%d, f%d, f%d", opc, dst, src1, src2, src3); +void fmt_threeop_uimm(PPCDisasmContext* ctx, const char* opc, int dst, int src1, int imm) { + ctx->instr_str = my_sprintf("%-8sr%d, r%d, 0x%X", opc, dst, src1, imm); + add_reg_in(ctx, "r%d", src1); + add_reg_out(ctx, "r%d", dst); } -void fmt_rotateop(string& buf, const char* opc, int dst, int src, int sh, int mb, int me, bool imm) { - if (imm) - buf = my_sprintf("%-8sr%d, r%d, %d, %d, %d", opc, dst, src, sh, mb, me); - else - buf = my_sprintf("%-8sr%d, r%d, r%d, %d, %d", opc, dst, src, sh, mb, me); +void fmt_threeop_simm(PPCDisasmContext* ctx, const char* opc, int dst, int src1, int imm) { + ctx->instr_str = my_sprintf("%-8sr%d, r%d, %s0x%X", opc, dst, src1, (imm < 0) ? "-" : "", abs(imm)); + add_reg_in(ctx, "r%d", src1); + add_reg_out(ctx, "r%d", dst); +} + +void fmt_threeop_flt(PPCDisasmContext* ctx, const char* opc, int dst, int src1, int src2) { + ctx->instr_str = my_sprintf("%-8sf%d, f%d, f%d", opc, dst, src1, src2); + add_reg_in(ctx, "f%d", src1); + add_reg_in(ctx, "f%d", src2); + add_reg_out(ctx, "f%d", dst); +} + +void fmt_fourop_flt(PPCDisasmContext* ctx, const char* opc, int dst, int src1, int src2, int src3) { + ctx->instr_str = my_sprintf("%-8sf%d, f%d, f%d, f%d", opc, dst, src1, src2, src3); + add_reg_in(ctx, "f%d", src1); + add_reg_in(ctx, "f%d", src2); + add_reg_in(ctx, "f%d", src3); + add_reg_out(ctx, "f%d", dst); +} + +void fmt_rotateop(PPCDisasmContext* ctx, const char* opc, int dst, int src, int sh, int mb, int me, bool imm) { + if (imm) { + ctx->instr_str = my_sprintf("%-8sr%d, r%d, %d, %d, %d", opc, dst, src, sh, mb, me); + add_reg_in(ctx, "r%d", src); + add_reg_out(ctx, "r%d", dst); + } + else { + ctx->instr_str = my_sprintf("%-8sr%d, r%d, r%d, %d, %d", opc, dst, src, sh, mb, me); + add_reg_in(ctx, "r%d", src); + add_reg_in(ctx, "r%d", sh); + add_reg_out(ctx, "r%d", dst); + } } /* Opcodes */ @@ -332,10 +410,12 @@ void opc_twi(PPCDisasmContext* ctx) { if (strlen(opcode) > 0) { strcat(opcode, "i"); ctx->instr_str = my_sprintf("%-8sr%d, 0x%X", opcode, ra, imm); + add_reg_in(ctx, "r%d", ra); return; } } ctx->instr_str = my_sprintf("%-8s%d, r%d, 0x%X", "twi", to, ra, imm); + add_reg_in(ctx, "r%d", ra); } void opc_group4(PPCDisasmContext* ctx) { @@ -349,32 +429,36 @@ void opc_ar_im(PPCDisasmContext* ctx) { if (ctx->simplified) { if (((ctx->instr_code >> 26) == 0xE) && !ra) { - fmt_twoop_simm(ctx->instr_str, "li", rd, imm); + fmt_twoop_simm(ctx, "li", rd, imm); return; } else if (((ctx->instr_code >> 26) == 0xF) && !ra) { - fmt_twoop_simm(ctx->instr_str, "lis", rd, imm); + fmt_twoop_simm(ctx, "lis", rd, imm); return; } if (imm > 0x7FFF) { switch ((ctx->instr_code >> 26)) { case 0xC: - fmt_threeop_simm(ctx->instr_str, "subic", rd, ra, imm); + fmt_threeop_simm(ctx, "subic", rd, ra, imm); return; case 0xD: - fmt_threeop_simm(ctx->instr_str, "subic.", rd, ra, imm); + fmt_threeop_simm(ctx, "subic.", rd, ra, imm); + add_reg_out(ctx, "cr"); return; case 0xE: - fmt_threeop_simm(ctx->instr_str, "subi", rd, ra, imm); + fmt_threeop_simm(ctx, "subi", rd, ra, imm); return; case 0xF: - fmt_threeop_simm(ctx->instr_str, "subis", rd, ra, imm); + fmt_threeop_simm(ctx, "subis", rd, ra, imm); return; } } } - fmt_threeop_simm(ctx->instr_str, arith_im_mnem[(ctx->instr_code >> 26) - 7], rd, ra, imm); + fmt_threeop_simm(ctx, arith_im_mnem[(ctx->instr_code >> 26) - 7], rd, ra, imm); + if ((ctx->instr_code >> 26) == 13) { /* addic. */ + add_reg_out(ctx, "cr"); + } } void power_dozi(PPCDisasmContext* ctx) { @@ -382,27 +466,35 @@ void power_dozi(PPCDisasmContext* ctx) { auto rd = (ctx->instr_code >> 21) & 0x1F; auto imm = ctx->instr_code & 0xFFFF; - fmt_threeop_simm(ctx->instr_str, "dozi", rd, ra, imm); + fmt_threeop_simm(ctx, "dozi", rd, ra, imm); } void fmt_rot_imm(PPCDisasmContext* ctx, const char* opc, int ra, int rs, int n) { char opcode[10]; strcpy(opcode, opc); - if (ctx->instr_code & 1) + if (ctx->instr_code & 1) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } ctx->instr_str = my_sprintf("%-8sr%d, r%d, %d", opcode, ra, rs, n); + add_reg_in(ctx, "r%d", rs); + add_reg_out(ctx, "r%d", ra); } void fmt_rot_2imm(PPCDisasmContext* ctx, const char* opc, int ra, int rs, int n, int b) { char opcode[10]; strcpy(opcode, opc); - if (ctx->instr_code & 1) + if (ctx->instr_code & 1) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } ctx->instr_str = my_sprintf("%-8sr%d, r%d, %d, %d", opcode, ra, rs, n, b); + add_reg_in(ctx, "r%d", rs); + add_reg_out(ctx, "r%d", ra); } void opc_rlwimi(PPCDisasmContext* ctx) { @@ -424,10 +516,12 @@ void opc_rlwimi(PPCDisasmContext* ctx) { } strcpy(opcode, "rlwimi"); - if (ctx->instr_code & 1) + if (ctx->instr_code & 1) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_rotateop(ctx->instr_str, opcode, ra, rs, sh, mb, me, true); + fmt_rotateop(ctx, opcode, ra, rs, sh, mb, me, true); } void opc_rlwinm(PPCDisasmContext* ctx) { @@ -473,10 +567,12 @@ void opc_rlwinm(PPCDisasmContext* ctx) { } strcpy(opcode, "rlwinm"); - if (ctx->instr_code & 1) + if (ctx->instr_code & 1) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_rotateop(ctx->instr_str, opcode, ra, rs, sh, mb, me, true); + fmt_rotateop(ctx, opcode, ra, rs, sh, mb, me, true); } void opc_rlmi(PPCDisasmContext* ctx) { @@ -486,10 +582,12 @@ void opc_rlmi(PPCDisasmContext* ctx) { auto mb = (ctx->instr_code >> 6) & 0x1F; auto me = (ctx->instr_code >> 1) & 0x1F; - if (ctx->instr_code & 1) - fmt_rotateop(ctx->instr_str, "rlmi.", ra, rs, rb, mb, me, false); + if (ctx->instr_code & 1) { + fmt_rotateop(ctx, "rlmi.", ra, rs, rb, mb, me, false); + add_reg_out(ctx, "cr"); + } else - fmt_rotateop(ctx->instr_str, "rlmi", ra, rs, rb, mb, me, false); + fmt_rotateop(ctx, "rlmi", ra, rs, rb, mb, me, false); } void opc_rlwnm(PPCDisasmContext* ctx) { @@ -504,18 +602,22 @@ void opc_rlwnm(PPCDisasmContext* ctx) { if ((me == 31) && (mb == 0)) { strcpy(opcode, "rotlw"); - if (ctx->instr_code & 1) + if (ctx->instr_code & 1) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_threeop(ctx->instr_str, opcode, ra, rs, rb); + fmt_threeop(ctx, opcode, ra, rs, rb); return; } } strcpy(opcode, "rlwnm"); - if (ctx->instr_code & 1) + if (ctx->instr_code & 1) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_rotateop(ctx->instr_str, "rlwnm", ra, rs, rb, mb, me, false); + fmt_rotateop(ctx, "rlwnm", ra, rs, rb, mb, me, false); } void opc_cmp_i_li(PPCDisasmContext* ctx) { @@ -527,21 +629,32 @@ void opc_cmp_i_li(PPCDisasmContext* ctx) { if (ctx->simplified) { if (!ls) { - if ((ctx->instr_code >> 26) & 0x1) + if ((ctx->instr_code >> 26) & 0x1) { ctx->instr_str = my_sprintf("%-8scr%d, r%d, 0x%X", "cmpwi", crfd, ra, imm); - else + add_reg_in(ctx, "r%d", ra); + add_reg_out(ctx, "cr"); + } + else { ctx->instr_str = my_sprintf( "%-8scr%d, r%d, %s0x%X", "cmplwi", crfd, ra, (imm < 0) ? "-" : "", abs(imm)); - + add_reg_in(ctx, "r%d", ra); + add_reg_out(ctx, "cr"); + } return; } } - if ((ctx->instr_code >> 26) & 0x1) + if ((ctx->instr_code >> 26) & 0x1) { ctx->instr_str = my_sprintf("%-8scr%d, %d, r%d, 0x%X", "cmpi", crfd, ls, ra, imm); - else + add_reg_in(ctx, "r%d", ra); + add_reg_out(ctx, "cr"); + } + else { ctx->instr_str = my_sprintf( "%-8scr%d, %d, r%d, %s0x%X", "cmpli", crfd, ls, ra, (imm < 0) ? "-" : "", abs(imm)); + add_reg_in(ctx, "r%d", ra); + add_reg_out(ctx, "cr"); + } } void opc_bool_im(PPCDisasmContext* ctx) { @@ -562,14 +675,28 @@ void opc_bool_im(PPCDisasmContext* ctx) { } strcpy(opcode, opc_bim_str[index]); - fmt_threeop_uimm(ctx->instr_str, opcode, ra, rs, imm); + fmt_threeop_uimm(ctx, opcode, ra, rs, imm); + if (index >= 4) { /* andi. or andis. */ + add_reg_out(ctx, "cr"); + } } void generic_bcx(PPCDisasmContext* ctx, uint32_t bo, uint32_t bi, uint32_t dst) { char opcode[10] = "bc"; + uint32_t cr; + + if (!(bo & 4)) { + add_reg_in(ctx, "ctr"); + add_reg_out(ctx, "ctr"); + } + if (!(bo & 0x10)) { + add_reg_in(ctx, "cr"); + } + if (ctx->instr_code & 1) { strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */ + add_reg_out(ctx, "lr"); } if (ctx->instr_code & 2) { strcat(opcode, "a"); /* add suffix "a" if the AA bit is set */ @@ -580,8 +707,15 @@ void generic_bcx(PPCDisasmContext* ctx, uint32_t bo, uint32_t bi, uint32_t dst) void generic_bcctrx(PPCDisasmContext* ctx, uint32_t bo, uint32_t bi) { char opcode[10] = "bcctr"; + add_reg_in(ctx, "ctr"); + + if (!(bo & 0x10)) { + add_reg_in(ctx, "cr"); + } + if (ctx->instr_code & 1) { strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */ + add_reg_out(ctx, "lr"); } ctx->instr_str = my_sprintf("%-8s%d, %d, 0x%08X", opcode, bo, bi); @@ -590,8 +724,19 @@ void generic_bcctrx(PPCDisasmContext* ctx, uint32_t bo, uint32_t bi) { void generic_bclrx(PPCDisasmContext* ctx, uint32_t bo, uint32_t bi) { char opcode[10] = "bclr"; + add_reg_in(ctx, "lr"); + + if (!(bo & 4)) { + add_reg_in(ctx, "ctr"); + add_reg_out(ctx, "ctr"); + } + if (!(bo & 0x10)) { + add_reg_in(ctx, "cr"); + } + if (ctx->instr_code & 1) { strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */ + add_reg_out(ctx, "lr"); } ctx->instr_str = my_sprintf("%-8s%d, %d, 0x%08X", opcode, bo, bi); @@ -619,6 +764,7 @@ void opc_bcx(PPCDisasmContext* ctx) { if (!(bo & 4)) { strcat(opcode, "d"); + add_reg_in(ctx, "ctr"); strcat(opcode, (bo & 2) ? "z" : "nz"); if (!(bo & 0x10)) { strcat(opcode, (bo & 8) ? "t" : "f"); @@ -628,17 +774,23 @@ void opc_bcx(PPCDisasmContext* ctx) { } strcat(operands, br_cond[4 + (bi & 3)]); strcat(operands, ", "); + add_reg_in(ctx, "cr"); } + add_reg_out(ctx, "ctr"); } else { /* CTR ignored */ strcat(opcode, br_cond[((bo >> 1) & 4) | (bi & 3)]); if (cr) { strcat(operands, "cr0, "); operands[2] = cr + '0'; } + if (!(bo & 0x10)) { + add_reg_in(ctx, "cr"); + } } if (ctx->instr_code & 1) { strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */ + add_reg_out(ctx, "lr"); } if (ctx->instr_code & 2) { strcat(opcode, "a"); /* add suffix "a" if the AA bit is set */ @@ -670,6 +822,10 @@ void opc_bcctrx(PPCDisasmContext* ctx) { if ((bo & 0x14) == 0x14) { ctx->instr_str = my_sprintf("%-8s", bcctrx_mnem[ctx->instr_code & 1]); + add_reg_in(ctx, "ctr"); + if (ctx->instr_code & 1) { + add_reg_out(ctx, "lr"); + } return; } @@ -679,9 +835,15 @@ void opc_bcctrx(PPCDisasmContext* ctx) { strcat(operands, "cr0"); operands[2] = cr + '0'; } + add_reg_in(ctx, "ctr"); + + if (!(bo & 0x10)) { + add_reg_in(ctx, "cr"); + } if (ctx->instr_code & 1) { strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */ + add_reg_out(ctx, "lr"); } if (bo & 1) { /* incorporate prediction bit if set */ strcat(opcode, "+"); @@ -706,11 +868,16 @@ void opc_bclrx(PPCDisasmContext* ctx) { if ((bo & 0x14) == 0x14) { ctx->instr_str = my_sprintf("%-8s", bclrx_mnem[ctx->instr_code & 1]); + add_reg_in(ctx, "lr"); + if (ctx->instr_code & 1) { + add_reg_out(ctx, "lr"); + } return; } if (!(bo & 4)) { strcat(opcode, "d"); + add_reg_in(ctx, "ctr"); strcat(opcode, (bo & 2) ? "z" : "nz"); if (!(bo & 0x10)) { strcat(opcode, (bo & 8) ? "t" : "f"); @@ -720,6 +887,7 @@ void opc_bclrx(PPCDisasmContext* ctx) { } strcat(operands, br_cond[4 + (bi & 3)]); } + add_reg_out(ctx, "ctr"); } else { /* CTR ignored */ strcat(opcode, br_cond[((bo >> 1) & 4) | (bi & 3)]); if (cr) { @@ -728,10 +896,16 @@ void opc_bclrx(PPCDisasmContext* ctx) { } } + if (!(bo & 0x10)) { + add_reg_in(ctx, "cr"); + } + strcat(opcode, "lr"); + add_reg_in(ctx, "lr"); if (ctx->instr_code & 1) { strcat(opcode, "l"); /* add suffix "l" if the LK bit is set */ + add_reg_out(ctx, "lr"); } if (bo & 1) { /* incorporate prediction bit if set */ strcat(opcode, "+"); @@ -745,6 +919,9 @@ void opc_bx(PPCDisasmContext* ctx) { SIGNEXT(ctx->instr_code & 0x3FFFFFC, 25); ctx->instr_str = my_sprintf("%-8s0x%08X", bx_mnem[ctx->instr_code & 3], dst); + if (ctx->instr_code & 1) { + add_reg_in(ctx, "lr"); + } } void opc_sc(PPCDisasmContext* ctx) { @@ -767,14 +944,12 @@ void opc_group19(PPCDisasmContext* ctx) { } strcat(operand1, br_cond[((rs % 4) + 4)]); - if (ra > 3) { strcat(operand2, "4*cr0+"); operand2[4] = (ra >> 2) + '0'; } strcat(operand2, br_cond[((ra % 4) + 4)]); - if (rb > 3) { strcat(operand3, "4*cr0+"); operand3[4] = (rb >> 2) + '0'; @@ -784,6 +959,8 @@ void opc_group19(PPCDisasmContext* ctx) { switch (ext_opc) { case 0: ctx->instr_str = my_sprintf("%-8scr%d, cr%d", "mcrf", (rs >> 2), (ra >> 2)); + add_reg_in(ctx, "cr"); + add_reg_out(ctx, "cr"); return; case 16: opc_bclrx(ctx); @@ -791,18 +968,26 @@ void opc_group19(PPCDisasmContext* ctx) { case 33: if (ctx->simplified && (ra == rb)) { ctx->instr_str = my_sprintf("%-8s%s, %s, %s", "crnor", operand1, operand2, operand3); + add_reg_in(ctx, "cr"); + add_reg_out(ctx, "cr"); } else { - fmt_threeop_crb(ctx->instr_str, "crnor", rs, ra, rb); + fmt_threeop_crb(ctx, "crnor", rs, ra, rb); } return; case 50: ctx->instr_str = my_sprintf("%-8s", "rfi"); + add_reg_in(ctx, "msr"); + add_reg_in(ctx, "srr0"); + add_reg_in(ctx, "srr1"); + add_reg_out(ctx, "msr"); return; case 129: if (ctx->simplified) { ctx->instr_str = my_sprintf("%-8s%s, %s, %s", "crandc", operand1, operand2, operand3); + add_reg_in(ctx, "cr"); + add_reg_out(ctx, "cr"); } else { - fmt_threeop_crb(ctx->instr_str, "crandc", rs, ra, rb); + fmt_threeop_crb(ctx, "crandc", rs, ra, rb); } return; case 150: @@ -811,53 +996,69 @@ void opc_group19(PPCDisasmContext* ctx) { case 193: if (ctx->simplified && (rs == ra) && (rs == rb)) { ctx->instr_str = my_sprintf("%-8scrb%d", "crclr", rs); + add_reg_out(ctx, "cr"); return; } else if (ctx->simplified && ((rs != ra) || (rs != rb))) { ctx->instr_str = my_sprintf("%-8s%s, %s, %s", "crxor", operand1, operand2, operand3); + add_reg_in(ctx, "cr"); + add_reg_out(ctx, "cr"); return; } - fmt_threeop_crb(ctx->instr_str, "crxor", rs, ra, rb); + fmt_threeop_crb(ctx, "crxor", rs, ra, rb); return; case 225: if (ctx->simplified) { ctx->instr_str = my_sprintf("%-8s%s, %s, %s", "crnand", operand1, operand2, operand3); + add_reg_in(ctx, "cr"); + add_reg_out(ctx, "cr"); } else { - fmt_threeop_crb(ctx->instr_str, "crnand", rs, ra, rb); + fmt_threeop_crb(ctx, "crnand", rs, ra, rb); } return; case 257: if (ctx->simplified) { ctx->instr_str = my_sprintf("%-8s%s, %s, %s", "crand", operand1, operand2, operand3); + add_reg_in(ctx, "cr"); + add_reg_out(ctx, "cr"); } else { - fmt_threeop_crb(ctx->instr_str, "crand", rs, ra, rb); + fmt_threeop_crb(ctx, "crand", rs, ra, rb); } return; case 289: if (ctx->simplified && (rs == ra) && (rs == rb)) { ctx->instr_str = my_sprintf("%-8scrb%d", "crset", rs); + add_reg_out(ctx, "cr"); return; } else if (ctx->simplified && ((rs != ra) || (rs != rb))) { ctx->instr_str = my_sprintf("%-8s%s, %s, %s", "creqv", operand1, operand2, operand3); + add_reg_in(ctx, "cr"); + add_reg_out(ctx, "cr"); return; } - fmt_threeop_crb(ctx->instr_str, "creqv", rs, ra, rb); + fmt_threeop_crb(ctx, "creqv", rs, ra, rb); return; case 417: if (ctx->simplified) { ctx->instr_str = my_sprintf("%-8s%s, %s, %s", "crorc", operand1, operand2, operand3); + add_reg_in(ctx, "cr"); + add_reg_out(ctx, "cr"); } else { - fmt_threeop_crb(ctx->instr_str, "crorc", rs, ra, rb); + fmt_threeop_crb(ctx, "crorc", rs, ra, rb); } return; case 449: if (ctx->simplified && (ra == rb)) { ctx->instr_str = my_sprintf("%-8scrb%d, crb%d", "crmove", rs, ra); + add_reg_in(ctx, "cr"); + add_reg_out(ctx, "cr"); return; } else if (ctx->simplified && (ra != rb)) { ctx->instr_str = my_sprintf("%-8s%s, %s, %s", "cror", operand1, operand2, operand3); + add_reg_in(ctx, "cr"); + add_reg_out(ctx, "cr"); return; } - fmt_threeop_crb(ctx->instr_str, "cror", rs, ra, rb); + fmt_threeop_crb(ctx, "cror", rs, ra, rb); return; case 528: opc_bcctrx(ctx); @@ -865,7 +1066,6 @@ void opc_group19(PPCDisasmContext* ctx) { } } - void opc_group31(PPCDisasmContext* ctx) { char opcode[10] = ""; @@ -886,16 +1086,18 @@ void opc_group31(PPCDisasmContext* ctx) { strcpy(opcode, opc_subs[index]); if (ext_opc & 0x200) /* check OE bit */ strcat(opcode, "o"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if (index == 3 || index == 6 || index == 7 || index == 11 || index == 15) { /* ugly check for two-operands instructions */ if (rb != 0) opc_illegal(ctx); else - fmt_twoop(ctx->instr_str, opcode, rs, ra); + fmt_twoop(ctx, opcode, rs, ra); } else - fmt_threeop(ctx->instr_str, opcode, rs, ra, rb); + fmt_threeop(ctx, opcode, rs, ra, rb); } return; @@ -907,15 +1109,17 @@ void opc_group31(PPCDisasmContext* ctx) { strcpy(opcode, opc_adds[index]); if (ext_opc & 0x200) /* check OE bit */ strcat(opcode, "o"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if (index == 6 || index == 7) { if (rb != 0) opc_illegal(ctx); else - fmt_twoop(ctx->instr_str, opcode, rs, ra); + fmt_twoop(ctx, opcode, rs, ra); } else - fmt_threeop(ctx->instr_str, opcode, rs, ra, rb); + fmt_threeop(ctx, opcode, rs, ra, rb); } return; @@ -927,12 +1131,14 @@ void opc_group31(PPCDisasmContext* ctx) { strcpy(opcode, opc_muldivs[index]); if (ext_opc & 0x200) /* check OE bit */ strcat(opcode, "o"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if ((!index || index == 2) && (ext_opc & 0x200)) opc_illegal(ctx); else - fmt_threeop(ctx->instr_str, opcode, rs, ra, rb); + fmt_threeop(ctx, opcode, rs, ra, rb); } return; @@ -941,44 +1147,60 @@ void opc_group31(PPCDisasmContext* ctx) { if (index == 4) { /* mtmsr */ if ((ra != 0) || (rb != 0) || rc_set) opc_illegal(ctx); - else + else { ctx->instr_str = my_sprintf("%-8sr%d", "mtmsr", rs); + add_reg_in(ctx, "r%d", rs); + add_reg_out(ctx, "msr"); + } } else if (index == 6) { /* mtsr */ if (ra & 16) opc_illegal(ctx); - else + else { ctx->instr_str = my_sprintf("%-8s%d, r%d", "mtsr", ra, rs); + add_reg_in(ctx, "r%d", rs); + add_reg_out(ctx, "sr%d", ra); + } } else if (index == 7) { /* mtsrin */ ctx->instr_str = my_sprintf("%-8sr%d, r%d", "mtsrin", rs, rb); + add_reg_in(ctx, "r%d", rs); + std::string reg_name = add_reg_in(ctx, "r%d", rb); + uint64_t reg_val = get_reg(reg_name); + add_reg_out(ctx, "sr%d", reg_val >> 28); } else if (index == 9) { /* tlbie */ ctx->instr_str = my_sprintf("%-8sr%d", "tlbie", rb); + add_reg_in(ctx, "r%d", rb); } else if (index == 11) { /* tlbia */ ctx->instr_str = my_sprintf("%-8s", "tlbia"); } else if (index == 30) { /* tlbld - 603 only */ if (!rs && !ra) opc_illegal(ctx); - else + else { ctx->instr_str = my_sprintf("%-8sr%s", "tlbld", rb); + add_reg_in(ctx, "r%d", rb); + } } else if (index == 30) { /* tlbli - 603 only */ if (!rs && !ra) opc_illegal(ctx); - else + else { ctx->instr_str = my_sprintf("%-8sr%s", "tlbli", rb); + add_reg_in(ctx, "r%d", rb); + } } return; case 0x18: /* Shifting instructions */ strcpy(opcode, opc_shft_reg[index]); - if (rc_set) + if (rc_set) { strcat(opcode, "."); - + add_reg_out(ctx, "cr"); + } if ((index == 0) || (index == 4) || (index == 6) || (index == 16) || (index == 20) || (index == 22) || (index == 24) || (index == 28)) { - fmt_threeop(ctx->instr_str, opcode, ra, rs, rb); + fmt_threeop(ctx, opcode, ra, rs, rb); } else if ((index == 5) || (index == 7) || (index == 21) || (index == 23) || (index == 25) || (index == 29)) { - fmt_threeop_simm(ctx->instr_str, opcode, ra, rs, rb); + fmt_threeop_simm(ctx, opcode, ra, rs, rb); } else { opc_illegal(ctx); } @@ -988,12 +1210,14 @@ void opc_group31(PPCDisasmContext* ctx) { case 0x19: /* (Extended) Shifting instructions - 601 only*/ strcpy(opcode, opc_shft_ext[index]); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if ((index == 4) || (index == 6) || (index == 16) || (index == 20) || (index == 22) || (index == 28)) { - fmt_threeop(ctx->instr_str, opcode, ra, rs, rb); + fmt_threeop(ctx, opcode, ra, rs, rb); } else { opc_illegal(ctx); } @@ -1009,24 +1233,31 @@ void opc_group31(PPCDisasmContext* ctx) { else if (index == 29) strcpy(opcode, "extsb"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_twoop(ctx->instr_str, opcode, rs, ra); + fmt_twoop(ctx, opcode, rs, ra); return; case 0x1C: /* logical instructions */ if (index == 13 && rs == rb && ctx->simplified) { - fmt_twoop(ctx->instr_str, rc_set ? "mr." : "mr", ra, rs); + fmt_twoop(ctx, rc_set ? "mr." : "mr", ra, rs); + if (rc_set) { + add_reg_out(ctx, "cr"); + } } else { strcpy(opcode, opc_logic[index]); if (!strlen(opcode)) { opc_illegal(ctx); } else { - if (rc_set) + if (rc_set) { strcat(opcode, "."); - fmt_threeop(ctx->instr_str, opcode, ra, rs, rb); + add_reg_out(ctx, "cr"); + } + fmt_threeop(ctx, opcode, ra, rs, rb); } } return; @@ -1038,10 +1269,16 @@ void opc_group31(PPCDisasmContext* ctx) { opc_illegal(ctx); return; } else { - if (ra == 0) - ctx->instr_str = my_sprintf("%-8sf%d, 0, r%d", opc_idx_ldst[index], rs, rb); + if (ra == 0) { + ctx->instr_str = my_sprintf("%-7s f%d, 0, r%d", opc_idx_ldst[index], rs, rb); + add_reg_in(ctx, "f%d", rs); + add_reg_in(ctx, "r%d", rb); + } else { - ctx->instr_str = my_sprintf("%-8sf%d, r%d, r%d", opc_idx_ldst[index], rs, ra, rb); + ctx->instr_str = my_sprintf("%-7s f%d, r%d, r%d", opc_idx_ldst[index], rs, ra, rb); + add_reg_in(ctx, "f%d", rs); + add_reg_in(ctx, "r%d", ra); + add_reg_in(ctx, "r%d", rb); } return; } @@ -1051,14 +1288,27 @@ void opc_group31(PPCDisasmContext* ctx) { return; } if (index < 16) { - if (ra == 0) - ctx->instr_str = my_sprintf("%-8sr%d, 0, r%d", opc_idx_ldst[index], rs, rb); + if (ra == 0) { + ctx->instr_str = my_sprintf("%-7s r%d, 0, r%d", opc_idx_ldst[index], rs, rb); + if (opc_idx_ldst[index][0] == 'l') + add_reg_out(ctx, "r%d", rs); + else + add_reg_in(ctx, "r%d", rs); + add_reg_in(ctx, "r%d", ra); + add_reg_in(ctx, "r%d", rb); + } else - fmt_threeop(ctx->instr_str, opc_idx_ldst[index], rs, ra, rb); + fmt_threeop(ctx, opc_idx_ldst[index], rs, ra, rb); return; } else { - ctx->instr_str = my_sprintf("%-8sf%d, r%d, r%d", opc_idx_ldst[index], rs, ra, rb); + ctx->instr_str = my_sprintf("%-7s f%d, r%d, r%d", opc_idx_ldst[index], rs, ra, rb); + if (opc_idx_ldst[index][0] == 'l') + add_reg_out(ctx, "r%d", rs); + else + add_reg_in(ctx, "r%d", rs); + add_reg_in(ctx, "r%d", ra); + add_reg_in(ctx, "r%d", rb); } return; @@ -1070,23 +1320,46 @@ void opc_group31(PPCDisasmContext* ctx) { opc_illegal(ctx); return; } else { - if (ra == 0) + if (ra == 0) { ctx->instr_str = my_sprintf("%-8sr%d, 0, r%d", opcode, rs, rb); + add_reg_in(ctx, "r%d", rs); + add_reg_in(ctx, "r%d", rb); + } else - fmt_threeop(ctx->instr_str, opcode, rs, ra, rb); + fmt_threeop_store(ctx, opcode, rs, ra, rb); + add_reg_out(ctx, "cr"); return; } } - /* eciwx, ecowx, lhbrx, lwbrx, stwbrx, sthbrx */ - else if ((index == 9) || (index == 13) || (index == 16) || (index == 20) || (index == 24) || (index == 28)) { + /* eciwx, lhbrx, lwbrx */ + else if ((index == 9) || (index == 16) || (index == 24)) { if (rc_set) { opc_illegal(ctx); return; } else { - if (ra == 0) + if (ra == 0) { ctx->instr_str = my_sprintf("%-8sr%d, 0, r%d", opcode, rs, rb); + add_reg_in(ctx, "r%d", rb); + add_reg_out(ctx, "r%d", rs); + } else - fmt_threeop(ctx->instr_str, opcode, rs, ra, rb); + fmt_threeop(ctx, opcode, rs, ra, rb); + return; + } + } + /* ecowx, stwbrx, sthbrx */ + else if ((index == 13) || (index == 20) || (index == 28)) { + if (rc_set) { + opc_illegal(ctx); + return; + } else { + if (ra == 0) { + ctx->instr_str = my_sprintf("%-7s r%d, 0, r%d", opcode, rs, rb); + add_reg_in(ctx, "r%d", rs); + add_reg_in(ctx, "r%d", rb); + } + else + fmt_threeop_store(ctx, opcode, rs, ra, rb); return; } } else if ((index == 18) || (index == 26)) { /* sync, eieio */ @@ -1101,10 +1374,12 @@ void opc_group31(PPCDisasmContext* ctx) { opc_illegal(ctx); return; } else { - if (ra == 0) + if (ra == 0) { ctx->instr_str = my_sprintf("%-8s0, r%d", opcode, rb); + add_reg_in(ctx, "r%d", rb); + } else - fmt_twoop(ctx->instr_str, opcode, ra, rb); + fmt_twoop_in(ctx, opcode, ra, rb); return; } } else if (index == 17) { /* tlbsync */ @@ -1129,20 +1404,28 @@ void opc_group31(PPCDisasmContext* ctx) { return; } - if (ctx->simplified) { if (!(rs & 1)) { if ((rs >> 2) == 0) { ctx->instr_str = my_sprintf("%-8sr%d, r%d", "cmpw", ra, rb); + add_reg_in(ctx, "r%d", ra); + add_reg_in(ctx, "r%d", rb); + add_reg_out(ctx, "cr"); return; } else { ctx->instr_str = my_sprintf("%-8scr%d, r%d, r%d", "cmpw", (rs >> 2), ra, rb); + add_reg_in(ctx, "r%d", ra); + add_reg_in(ctx, "r%d", rb); + add_reg_out(ctx, "cr"); return; } } } ctx->instr_str = my_sprintf("%-8scr%d, r%d, r%d", "cmp", (rs >> 2), ra, rb); + add_reg_in(ctx, "r%d", ra); + add_reg_in(ctx, "r%d", rb); + add_reg_out(ctx, "cr"); break; case 4: /* tw */ if (rc_set) { @@ -1153,33 +1436,43 @@ void opc_group31(PPCDisasmContext* ctx) { if (strlen(opcode) != 0) { ctx->instr_str = my_sprintf("%-8sr%d, r%d", opcode, ra, rb); + add_reg_in(ctx, "r%d", ra); + add_reg_in(ctx, "r%d", rb); break; } } ctx->instr_str = my_sprintf("%-8s%d, r%d, r%d", "tw", rs, ra, rb); + add_reg_in(ctx, "r%d", ra); + add_reg_in(ctx, "r%d", rb); } break; case 19: /* mfcr */ - fmt_oneop(ctx->instr_str, "mfcr", rs); + fmt_oneop_out(ctx, "mfcr", rs); + add_reg_in(ctx, "cr"); break; case 20: /* lwarx */ if (rc_set) { opc_illegal(ctx); } else { - if (ra == 0) + if (ra == 0) { ctx->instr_str = my_sprintf("%-8sr%d, 0, r%d", "lwarx", rs, rb); + add_reg_in(ctx, "r%d", rb); + add_reg_out(ctx, "r%d", rs); + } else - fmt_threeop(ctx->instr_str, "lwarx", rs, ra, rb); + fmt_threeop(ctx, "lwarx", rs, ra, rb); } break; case 29: /* maskg */ strcpy(opcode, "maskg"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_threeop(ctx->instr_str, opcode, rs, ra, rb); + fmt_threeop(ctx, opcode, rs, ra, rb); break; case 32: /* cmpl */ if (rc_set) { @@ -1193,6 +1486,9 @@ void opc_group31(PPCDisasmContext* ctx) { ctx->instr_str = my_sprintf("%-8sr%d, r%d", "cmplw", ra, rb); else ctx->instr_str = my_sprintf("%-8scr%d, r%d, r%d", "cmplw", (rs >> 2), ra, rb); + add_reg_in(ctx, "r%d", ra); + add_reg_in(ctx, "r%d", rb); + add_reg_out(ctx, "cr"); return; } @@ -1201,10 +1497,15 @@ void opc_group31(PPCDisasmContext* ctx) { else { ctx->instr_str = my_sprintf( "%-8scr%d, %d, r%d, r%d", "cmpl", (rs >> 2), (rs & 1), ra, rb); + add_reg_in(ctx, "r%d", ra); + add_reg_in(ctx, "r%d", rb); + add_reg_out(ctx, "cr"); } break; case 83: /* mfmsr */ - ctx->instr_str = my_sprintf("%-8sr%d", "mfmsr", (ctx->instr_code >> 21) & 0x1F); + ctx->instr_str = my_sprintf("%-8sr%d", "mfmsr", rs); + add_reg_in(ctx, "msr"); + add_reg_out(ctx, "r%d", rs); break; case 144: /* mtcrf */ if (ctx->instr_code & 0x100801) @@ -1215,15 +1516,27 @@ void opc_group31(PPCDisasmContext* ctx) { else ctx->instr_str = my_sprintf( "%-8s0x%02X, r%d", "mtcrf", (ctx->instr_code >> 12) & 0xFF, rs); + add_reg_in(ctx, "r%d", rs); + add_reg_out(ctx, "cr"); } break; case 277: /* lscbx */ strcpy(opcode, "lscbx"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } + add_reg_in(ctx, "xer"); + add_reg_out(ctx, "xer"); - fmt_threeop(ctx->instr_str, opcode, rs, ra, rb); + if (ra == 0) { + ctx->instr_str = my_sprintf("%-8sr%d, 0, r%d", opcode, rs, rb); + add_reg_in(ctx, "r%d", rb); + add_reg_out(ctx, "r%d", rs); /* string operation: additional registers are affected */ + } + else + fmt_threeop(ctx, opcode, rs, ra, rb); break; case 339: /* mfspr */ if (ctx->simplified) { @@ -1232,46 +1545,70 @@ void opc_group31(PPCDisasmContext* ctx) { strcpy(opcode, "mf"); strcat(opcode, spr_index0[spr_low]); ctx->instr_str = my_sprintf("%-8sr%d", opcode, rs); + add_reg_in(ctx, "%s", spr_index0[spr_low]); + add_reg_out(ctx, "r%d", rs); return; case 8: strcpy(opcode, "mf"); strcat(opcode, spr_index8[spr_low]); ctx->instr_str = my_sprintf("%-8sr%d", opcode, rs); + add_reg_in(ctx, "%s", spr_index8[spr_low]); + add_reg_out(ctx, "r%d", rs); return; case 16: strcpy(opcode, "mf"); strcat(opcode, spr_index16[spr_low]); ctx->instr_str = my_sprintf("%-8sr%d", opcode, rs); + add_reg_in(ctx, "%s", spr_index16[spr_low]); + add_reg_out(ctx, "r%d", rs); return; case 29: strcpy(opcode, "mf"); strcat(opcode, spr_index29[spr_low]); ctx->instr_str = my_sprintf("%-8sr%d", opcode, rs); + add_reg_in(ctx, "%s", spr_index29[spr_low]); + add_reg_out(ctx, "r%d", rs); return; case 30: strcpy(opcode, "mf"); strcat(opcode, spr_index30[spr_low]); ctx->instr_str = my_sprintf("%-8sr%d", opcode, rs); + add_reg_in(ctx, "%s", spr_index30[spr_low]); + add_reg_out(ctx, "r%d", rs); return; case 31: strcpy(opcode, "mf"); strcat(opcode, spr_index31[spr_low]); ctx->instr_str = my_sprintf("%-8sr%d", opcode, rs); + add_reg_in(ctx, "%s", spr_index31[spr_low]); + add_reg_out(ctx, "r%d", rs); return; } } - fmt_twoop_fromspr(ctx->instr_str, "mfspr", rs, ref_spr); + fmt_twoop_fromspr(ctx, "mfspr", rs, ref_spr); break; case 371: /* mftb */ if (ctx->simplified) { if (ref_spr == 268) { - fmt_oneop(ctx->instr_str, "mftbl", rs); - } else if (ref_spr == 269) { - fmt_oneop(ctx->instr_str, "mftbu", rs); + fmt_oneop_out(ctx, "mftbl", rs); + add_reg_in(ctx, "tbl"); + return; + } + if (ref_spr == 269) { + fmt_oneop_out(ctx, "mftbu", rs); + add_reg_in(ctx, "tbu"); + return; } - return; } ctx->instr_str = my_sprintf("%-8sr%d, %d", "mftb", rs, ref_spr); + if (ref_spr == 268) { + add_reg_in(ctx, "tbl"); + } else if (ref_spr == 269) { + add_reg_in(ctx, "tbu"); + } else { + add_reg_in(ctx, "spr", ref_spr); + } + add_reg_out(ctx, "r%d", rs); break; case 467: /* mtspr */ if (ctx->simplified) { @@ -1280,70 +1617,98 @@ void opc_group31(PPCDisasmContext* ctx) { strcpy(opcode, "mt"); strcat(opcode, spr_index0[spr_low]); ctx->instr_str = my_sprintf("%-8sr%d", opcode, rs); + add_reg_in(ctx, "r%d", rs); + if (spr_low == 0x16) { /* decrementer */ + add_reg_in(ctx, "msr"); + } + add_reg_out(ctx, "%s", spr_index0[spr_low]); return; case 8: strcpy(opcode, "mt"); strcat(opcode, spr_index8[spr_low]); ctx->instr_str = my_sprintf("%-8sr%d", opcode, rs); + add_reg_in(ctx, "r%d", rs); + add_reg_out(ctx, "%s", spr_index8[spr_low]); return; case 16: strcpy(opcode, "mt"); strcat(opcode, spr_index16[spr_low]); ctx->instr_str = my_sprintf("%-8sr%d", opcode, rs); + add_reg_in(ctx, "r%d", rs); + add_reg_out(ctx, "%s", spr_index16[spr_low]); return; case 29: strcpy(opcode, "mt"); strcat(opcode, spr_index29[spr_low]); ctx->instr_str = my_sprintf("%-8sr%d", opcode, rs); + add_reg_in(ctx, "r%d", rs); + add_reg_out(ctx, "%s", spr_index29[spr_low]); return; case 30: strcpy(opcode, "mt"); strcat(opcode, spr_index30[spr_low]); ctx->instr_str = my_sprintf("%-8sr%d", opcode, rs); + add_reg_in(ctx, "r%d", rs); + add_reg_out(ctx, "%s", spr_index30[spr_low]); return; case 31: strcpy(opcode, "mt"); strcat(opcode, spr_index31[spr_low]); ctx->instr_str = my_sprintf("%-8sr%d", opcode, rs); + add_reg_in(ctx, "r%d", rs); + add_reg_out(ctx, "%s", spr_index31[spr_low]); return; } } - fmt_twoop_tospr(ctx->instr_str, "mtspr", ref_spr, rs); + fmt_twoop_tospr(ctx, "mtspr", ref_spr, rs); break; case 512: /* mcrxr */ ctx->instr_str = my_sprintf("%-8scr%d", "mcrxr", (rs >> 2)); + add_reg_in(ctx, "xer"); + add_reg_out(ctx, "cr"); + add_reg_out(ctx, "xer"); break; case 531: /* clcs */ strcpy(opcode, "clcs"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_twoop(ctx->instr_str, opcode, rs, ra); + fmt_twoop(ctx, opcode, rs, ra); break; case 533: /* lswx */ if (rc_set) { opc_illegal(ctx); } else { - if (ra == 0) + if (ra == 0) { ctx->instr_str = my_sprintf("%-8sr%d, 0, r%d", "lswx", rs, rb); + add_reg_in(ctx, "r%d", rb); + add_reg_out(ctx, "r%d", rs); /* string operation: additional registers are affected */ + } else - fmt_threeop(ctx->instr_str, "lswx", rs, ra, rb); + fmt_threeop(ctx, "lswx", rs, ra, rb); } break; case 541: /* maskir */ strcpy(opcode, "maskir"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_threeop(ctx->instr_str, opcode, ra, rs, rb); + fmt_threeop(ctx, opcode, ra, rs, rb); return; case 595: /* mfsr */ if (ra & 16) opc_illegal(ctx); - else + else { ctx->instr_str = my_sprintf("%-8sr%d, %d", "mfsr", rs, ra); + add_reg_in(ctx, "sr%d", ra); + add_reg_out(ctx, "r%d", rs); + } break; case 597: /* lswi */ if (rc_set) { @@ -1352,24 +1717,36 @@ void opc_group31(PPCDisasmContext* ctx) { if (rb == 0) rb = 32; - if (ra == 0) + if (ra == 0) { ctx->instr_str = my_sprintf("%-8sr%d, 0, %x", "lswi", rs, rb); + add_reg_in(ctx, "r%d", rb); + add_reg_out(ctx, "r%d", rs); /* string operation: additional registers are affected */ + } else - fmt_threeop_simm(ctx->instr_str, "lswi", rs, ra, rb); + fmt_threeop_simm(ctx, "lswi", rs, ra, rb); } break; case 659: /* mfsrin */ - ctx->instr_str = my_sprintf("%-8sr%d, r%d", "mtsrin", rs, rb); + { + ctx->instr_str = my_sprintf("%-8sr%d, r%d", "mfsrin", rs, rb); + add_reg_out(ctx, "r%d", rs); + std::string reg_name = add_reg_in(ctx, "r%d", rb); + uint64_t reg_val = get_reg(reg_name); + add_reg_in(ctx, "sr%d", reg_val >> 28); + } break; case 661: /* stswx */ if (rc_set) { opc_illegal(ctx); return; } else { - if (ra == 0) + if (ra == 0) { ctx->instr_str = my_sprintf("%-8sr%d, 0, r%d", "stswx", rs, rb); + add_reg_in(ctx, "r%d", rb); + add_reg_out(ctx, "r%d", rs); /* string operation: additional registers are affected */ + } else - fmt_threeop(ctx->instr_str, "stswx", rs, ra, rb); + fmt_threeop(ctx, "stswx", rs, ra, rb); return; } break; @@ -1381,10 +1758,13 @@ void opc_group31(PPCDisasmContext* ctx) { if (rb == 0) rb = 32; - if (ra == 0) + if (ra == 0) { ctx->instr_str = my_sprintf("%-8sr%d, 0, %d", "stswi", rs, rb); + add_reg_in(ctx, "r%d", rb); + add_reg_out(ctx, "r%d", rs); /* string operation: additional registers are affected */ + } else - fmt_threeop_simm(ctx->instr_str, "stswi", rs, ra, rb); + fmt_threeop_simm(ctx, "stswi", rs, ra, rb); return; } break; @@ -1408,65 +1788,85 @@ void opc_group59(PPCDisasmContext* ctx) { case 18: /* floating point division */ strcpy(opcode, "fdivs"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if (rc != 0) opc_illegal(ctx); - else - fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb); + else { + fmt_threeop_flt(ctx, opcode, rs, ra, rb); + add_reg_out(ctx, "fpscr"); + } return; case 20: /* floating point subtract */ strcpy(opcode, "fsubs"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if (rc != 0) opc_illegal(ctx); - else - fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb); + else { + fmt_threeop_flt(ctx, opcode, rs, ra, rb); + add_reg_out(ctx, "fpscr"); + } return; case 21: /* floating point addition */ strcpy(opcode, "fadds"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if (rc != 0) opc_illegal(ctx); - else - fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb); + else { + fmt_threeop_flt(ctx, opcode, rs, ra, rb); + add_reg_out(ctx, "fpscr"); + } return; case 22: /* floating point square root */ strcpy(opcode, "fsqrts"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if ((rc != 0) || (ra != 0)) opc_illegal(ctx); - else - fmt_twoop_flt(ctx->instr_str, "fsqrts", rs, rb); + else { + fmt_twoop_flt(ctx, "fsqrts", rs, rb); + add_reg_out(ctx, "fpscr"); + } return; case 24: /* fres */ strcpy(opcode, "fres"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if ((rc != 0) || (ra != 0)) opc_illegal(ctx); - else - fmt_twoop_flt(ctx->instr_str, opcode, rs, rb); + else { + fmt_twoop_flt(ctx, opcode, rs, rb); + add_reg_out(ctx, "fpscr"); + } return; @@ -1475,13 +1875,17 @@ void opc_group59(PPCDisasmContext* ctx) { strcpy(opcode, opc_flt_ext_arith[25]); strcat(opcode, "s"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if (rb != 0) opc_illegal(ctx); - else - fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rc); + else { + fmt_threeop_flt(ctx, opcode, rs, ra, rc); + add_reg_out(ctx, "fpscr"); + } return; @@ -1490,10 +1894,13 @@ void opc_group59(PPCDisasmContext* ctx) { strcpy(opcode, opc_flt_ext_arith[28]); strcat(opcode, "s"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb); + fmt_fourop_flt(ctx, opcode, rs, ra, rc, rb); + add_reg_out(ctx, "fpscr"); return; @@ -1502,10 +1909,13 @@ void opc_group59(PPCDisasmContext* ctx) { strcpy(opcode, opc_flt_ext_arith[29]); strcat(opcode, "s"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb); + fmt_fourop_flt(ctx, opcode, rs, ra, rc, rb); + add_reg_out(ctx, "fpscr"); return; @@ -1514,10 +1924,13 @@ void opc_group59(PPCDisasmContext* ctx) { strcpy(opcode, opc_flt_ext_arith[30]); strcat(opcode, "s"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb); + fmt_fourop_flt(ctx, opcode, rs, ra, rc, rb); + add_reg_out(ctx, "fpscr"); return; @@ -1526,10 +1939,13 @@ void opc_group59(PPCDisasmContext* ctx) { strcpy(opcode, opc_flt_ext_arith[31]); strcat(opcode, "s"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb); + fmt_fourop_flt(ctx, opcode, rs, ra, rc, rb); + add_reg_out(ctx, "fpscr"); return; } @@ -1550,61 +1966,79 @@ void opc_group63(PPCDisasmContext* ctx) { case 18: /* floating point division */ strcpy(opcode, "fdiv"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if (rc != 0) opc_illegal(ctx); - else - fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb); + else { + fmt_threeop_flt(ctx, opcode, rs, ra, rb); + add_reg_out(ctx, "fpscr"); + } return; case 20: /* floating point subtract */ strcpy(opcode, "fsub"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if (rc != 0) opc_illegal(ctx); - else - fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb); + else { + fmt_threeop_flt(ctx, opcode, rs, ra, rb); + add_reg_out(ctx, "fpscr"); + } return; case 21: /* floating point addition */ strcpy(opcode, "fadd"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if (rc != 0) opc_illegal(ctx); - else - fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb); + else { + fmt_threeop_flt(ctx, opcode, rs, ra, rb); + add_reg_out(ctx, "fpscr"); + } return; case 22: /* floating point square root */ strcpy(opcode, "fsqrt"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if ((rc != 0) || (ra != 0)) opc_illegal(ctx); - else - fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rb); + else { + fmt_threeop_flt(ctx, opcode, rs, ra, rb); + add_reg_out(ctx, "fpscr"); + } return; case 23: /* fsel */ strcpy(opcode, opc_flt_ext_arith[23]); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb); + fmt_fourop_flt(ctx, opcode, rs, ra, rc, rb); return; @@ -1612,66 +2046,87 @@ void opc_group63(PPCDisasmContext* ctx) { strcpy(opcode, opc_flt_ext_arith[25]); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if (rb != 0) opc_illegal(ctx); - else - fmt_threeop_flt(ctx->instr_str, opcode, rs, ra, rc); + else { + fmt_threeop_flt(ctx, opcode, rs, ra, rc); + add_reg_out(ctx, "fpscr"); + } return; case 26: /* frsqrte */ strcpy(opcode, "frsqrte"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if ((rc != 0) || (ra != 0)) opc_illegal(ctx); - else + else { ctx->instr_str = my_sprintf("%-8sf%d, f%d", opcode, rs, rb); + add_reg_in(ctx, "f%d", rb); + add_reg_out(ctx, "f%d", rs); + add_reg_out(ctx, "fpscr"); + } return; case 28: /* fmsub */ strcpy(opcode, opc_flt_ext_arith[28]); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb); + fmt_fourop_flt(ctx, opcode, rs, ra, rc, rb); return; case 29: /* fmadd */ strcpy(opcode, opc_flt_ext_arith[29]); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb); + fmt_fourop_flt(ctx, opcode, rs, ra, rc, rb); + add_reg_out(ctx, "fpscr"); return; case 30: /* fnmsub */ strcpy(opcode, opc_flt_ext_arith[30]); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb); + fmt_fourop_flt(ctx, opcode, rs, ra, rc, rb); + add_reg_out(ctx, "fpscr"); return; case 31: /* fnmadd */ strcpy(opcode, opc_flt_ext_arith[31]); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } - fmt_fourop_flt(ctx->instr_str, opcode, rs, ra, rc, rb); + fmt_fourop_flt(ctx, opcode, rs, ra, rc, rb); + add_reg_out(ctx, "fpscr"); return; } @@ -1682,17 +2137,26 @@ void opc_group63(PPCDisasmContext* ctx) { case 0: /* fcmpu */ if (rs & 3) opc_illegal(ctx); - else + else { ctx->instr_str = my_sprintf("%-8scr%d, f%d, f%d", "fcmpu", (rs >> 2), ra, rb); + add_reg_in(ctx, "f%d", ra); + add_reg_in(ctx, "f%d", rb); + add_reg_out(ctx, "cr"); + } break; case 12: /* frsp */ if (ra != 0) opc_illegal(ctx); else { strcpy(opcode, "frsp"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } ctx->instr_str = my_sprintf("%-8sf%d, f%d", opcode, rs, rb); + add_reg_in(ctx, "f%d", rb); + add_reg_out(ctx, "f%d", rs); + add_reg_out(ctx, "fpscr"); } break; case 14: /* fctiw */ @@ -1700,9 +2164,14 @@ void opc_group63(PPCDisasmContext* ctx) { opc_illegal(ctx); else { strcpy(opcode, "fctiw"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } ctx->instr_str = my_sprintf("%-8sf%d, f%d", opcode, rs, rb); + add_reg_in(ctx, "f%d", rb); + add_reg_out(ctx, "f%d", rs); + add_reg_out(ctx, "fpscr"); } break; case 15: /* fctiwz */ @@ -1710,48 +2179,70 @@ void opc_group63(PPCDisasmContext* ctx) { opc_illegal(ctx); else { strcpy(opcode, "fctiwz"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } ctx->instr_str = my_sprintf("%-8sf%d, f%d", opcode, rs, rb); + add_reg_in(ctx, "f%d", rb); + add_reg_out(ctx, "f%d", rs); + add_reg_out(ctx, "fpscr"); } break; case 32: /* fcmpo */ if (rs & 3) opc_illegal(ctx); - else + else { ctx->instr_str = my_sprintf("%-8scr%d, f%d, f%d", "fcmpo", (rs >> 2), ra, rb); + add_reg_in(ctx, "f%d", rb); + add_reg_in(ctx, "f%d", rs); + add_reg_out(ctx, "cr"); + } break; case 38: /* mtfsb1 */ strcpy(opcode, "mtfsb1"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } ctx->instr_str = my_sprintf("%-8s%d", opcode, rs); + add_reg_out(ctx, "fpscr"); break; case 40: /* fneg */ strcpy(opcode, "fneg"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if (ra != 0) opc_illegal(ctx); - else + else { ctx->instr_str = my_sprintf("%-8sf%d, f%d", opcode, rs, rb); + add_reg_in(ctx, "f%d", rb); + add_reg_out(ctx, "f%d", rs); + } break; case 64: strcpy(opcode, "mcrfs"); ctx->instr_str = my_sprintf("%-8scr%d, cr%d", opcode, (rs >> 2), (ra >> 2)); + add_reg_in(ctx, "fpscr"); + add_reg_out(ctx, "cr"); break; case 70: /* mtfsb0 */ strcpy(opcode, "mtfsb0"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } ctx->instr_str = my_sprintf("%-8s%d", opcode, rs); + add_reg_out(ctx, "fpscr"); break; case 72: /* fmr */ if (ra != 0) @@ -1759,10 +2250,14 @@ void opc_group63(PPCDisasmContext* ctx) { else { strcpy(opcode, "fmr"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } ctx->instr_str = my_sprintf("%-8sf%d, f%d", opcode, rs, rb); + add_reg_in(ctx, "f%d", rb); + add_reg_out(ctx, "f%d", rs); } break; case 134: /* mtfsfi */ @@ -1770,10 +2265,13 @@ void opc_group63(PPCDisasmContext* ctx) { opc_illegal(ctx); else { strcpy(opcode, "mtfsfi"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } ctx->instr_str = my_sprintf("%-8scr%d, %d", opcode, (rs >> 2), (rb >> 1)); + add_reg_out(ctx, "fpscr"); } break; case 136: /* fnabs */ @@ -1781,10 +2279,14 @@ void opc_group63(PPCDisasmContext* ctx) { opc_illegal(ctx); else { strcpy(opcode, "fnabs"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } ctx->instr_str = my_sprintf("%-8sf%d, f%d", opcode, rs, rb); + add_reg_in(ctx, "f%d", rb); + add_reg_out(ctx, "f%d", rs); } break; case 264: /* fabs */ @@ -1792,30 +2294,43 @@ void opc_group63(PPCDisasmContext* ctx) { opc_illegal(ctx); else { strcpy(opcode, "fabs"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } ctx->instr_str = my_sprintf("%-8sf%d, f%d", opcode, rs, rb); + add_reg_in(ctx, "f%d", rb); + add_reg_out(ctx, "f%d", rs); } break; case 583: /* mffs */ strcpy(opcode, "mffs"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } if ((ra != 0) || (rb != 0)) opc_illegal(ctx); - else + else { ctx->instr_str = my_sprintf("%-8sf%d", opcode, rs); + add_reg_in(ctx, "fpscr"); + add_reg_out(ctx, "f%d", rs); + } break; case 711: /* mtfsf */ strcpy(opcode, "mtfsf"); - if (rc_set) + if (rc_set) { strcat(opcode, "."); + add_reg_out(ctx, "cr"); + } ctx->instr_str = my_sprintf("%-8s%d, f%d", opcode, fm, rb); + add_reg_in(ctx, "f%d", rs); + add_reg_out(ctx, "fpscr"); break; default: opc_illegal(ctx); @@ -1835,9 +2350,15 @@ void opc_intldst(PPCDisasmContext* ctx) { return; } + if (opc_int_ldst[opcode][0] == 'l') + add_reg_out(ctx, "r%d", rd); + else + add_reg_in(ctx, "r%d", rd); + if (ra) { ctx->instr_str = my_sprintf( "%-8sr%d, %s0x%X(r%d)", opc_int_ldst[opcode], rd, ((imm < 0) ? "-" : ""), abs(imm), ra); + add_reg_in(ctx, "r%d", ra); } else { ctx->instr_str = my_sprintf( "%-8sr%d, %s0x%X", opc_int_ldst[opcode], rd, ((imm < 0) ? "-" : ""), abs(imm)); @@ -1857,9 +2378,15 @@ void opc_fltldst(PPCDisasmContext* ctx) { return; } + if (opc_flt_ldst[opcode][0] == 'l') + add_reg_out(ctx, "f%d", rd); + else + add_reg_in(ctx, "f%d", rd); + if (ra) { ctx->instr_str = my_sprintf( "%-8sf%d, %s0x%X(r%d)", opc_flt_ldst[opcode], rd, ((imm < 0) ? "-" : ""), abs(imm), ra); + add_reg_in(ctx, "r%d", ra); } else { ctx->instr_str = my_sprintf( "%-8sf%d, %s0x%X", opc_flt_ldst[opcode], rd, ((imm < 0) ? "-" : ""), abs(imm)); diff --git a/cpu/ppc/ppcdisasm.h b/cpu/ppc/ppcdisasm.h index f542774..2c93482 100644 --- a/cpu/ppc/ppcdisasm.h +++ b/cpu/ppc/ppcdisasm.h @@ -24,12 +24,15 @@ along with this program. If not, see . #include #include +#include typedef struct PPCDisasmContext { uint32_t instr_addr; uint32_t instr_code; std::string instr_str; bool simplified; /* true if we should output simplified mnemonics */ + std::vector regs_in; + std::vector regs_out; } PPCDisasmContext; std::string disassemble_single(PPCDisasmContext* ctx);