cpu/arm: fix block data transfer

Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
2024-06-13 03:54:12 +05:30
parent 08cc582f23
commit 0029e302b2
2 changed files with 36 additions and 28 deletions

View File

@@ -283,8 +283,7 @@ Instruction::exec(Cpu& cpu) {
uint32_t address = cpu.gpr[data.rn]; uint32_t address = cpu.gpr[data.rn];
Mode mode = cpu.cpsr.mode(); Mode mode = cpu.cpsr.mode();
uint8_t i = 0; int8_t i = 0;
uint8_t n_regs = std::popcount(data.regs);
pc_error(data.rn); pc_error(data.rn);
@@ -304,11 +303,7 @@ Instruction::exec(Cpu& cpu) {
} }
} }
// TODO: clean this shit // increment beforehand
// account for decrement
if (!data.up)
address -= (n_regs - 1) * alignment;
if (data.pre) if (data.pre)
address += (data.up ? alignment : -alignment); address += (data.up ? alignment : -alignment);
@@ -319,6 +314,7 @@ Instruction::exec(Cpu& cpu) {
cpu.spsr = cpu.cpsr; cpu.spsr = cpu.cpsr;
} }
if (data.up) {
for (i = 0; i < cpu.GPR_COUNT; i++) { for (i = 0; i < cpu.GPR_COUNT; i++) {
if (get_bit(data.regs, i)) { if (get_bit(data.regs, i)) {
cpu.gpr[i] = cpu.bus->read_word(address); cpu.gpr[i] = cpu.bus->read_word(address);
@@ -326,22 +322,34 @@ Instruction::exec(Cpu& cpu) {
} }
} }
} else { } else {
for (i = cpu.GPR_COUNT - 1; i >= 0; i--) {
if (get_bit(data.regs, i)) {
cpu.gpr[i] = cpu.bus->read_word(address);
address -= alignment;
}
}
}
} else {
if (data.up) {
for (i = 0; i < cpu.GPR_COUNT; i++) { for (i = 0; i < cpu.GPR_COUNT; i++) {
if (get_bit(data.regs, i)) { if (get_bit(data.regs, i)) {
cpu.bus->write_word(address, cpu.gpr[i]); cpu.bus->write_word(address, cpu.gpr[i]);
address += alignment; address += alignment;
} }
} }
} else {
for (i = cpu.GPR_COUNT - 1; i >= 0; i--) {
if (get_bit(data.regs, i)) {
cpu.bus->write_word(address, cpu.gpr[i]);
address -= alignment;
}
}
}
} }
if (!data.pre) // fix increment
address += (data.up ? alignment : -alignment); if (data.pre)
address += (data.up ? -alignment : alignment);
// reset back to original address + offset if incremented earlier
if (data.up)
address -= n_regs * alignment;
else
address -= alignment;
if (!data.pre || data.write) if (!data.pre || data.write)
cpu.gpr[data.rn] = address; cpu.gpr[data.rn] = address;

View File

@@ -557,7 +557,7 @@ TEST_CASE_METHOD(CpuFixture, "Block Data Transfer", TAG) {
setr(10, address); setr(10, address);
block_transfer->write = true; block_transfer->write = true;
exec(data); exec(data);
checker(address + alignment); checker(address + 7 * alignment);
// decrement // decrement
block_transfer->write = false; block_transfer->write = false;
@@ -568,10 +568,10 @@ TEST_CASE_METHOD(CpuFixture, "Block Data Transfer", TAG) {
checker(address + alignment * 8); checker(address + alignment * 8);
// with write // with write
setr(10, 0x3000D98); setr(10, address + alignment * 8);
block_transfer->write = true; block_transfer->write = true;
exec(data); exec(data);
checker(address + alignment * 7); checker(address + alignment);
// post increment // post increment
block_transfer->write = false; block_transfer->write = false;
@@ -580,14 +580,14 @@ TEST_CASE_METHOD(CpuFixture, "Block Data Transfer", TAG) {
// adjust rn // adjust rn
setr(10, address + alignment); setr(10, address + alignment);
exec(data); exec(data);
checker(address + alignment * 2); checker(address + alignment * 8);
// post decrement // post decrement
block_transfer->up = false; block_transfer->up = false;
// adjust rn // adjust rn
setr(10, address + alignment * 7); setr(10, address + alignment * 7);
exec(data); exec(data);
checker(address + alignment * 6); checker(address);
// with s bit // with s bit
cpu.chg_mode(Mode::Fiq); cpu.chg_mode(Mode::Fiq);