cpu/arm: fix block data transfer
Signed-off-by: Amneesh Singh <natto@weirdnatto.in>
This commit is contained in:
@@ -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,29 +314,42 @@ Instruction::exec(Cpu& cpu) {
|
|||||||
cpu.spsr = cpu.cpsr;
|
cpu.spsr = cpu.cpsr;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < cpu.GPR_COUNT; i++) {
|
if (data.up) {
|
||||||
if (get_bit(data.regs, i)) {
|
for (i = 0; i < cpu.GPR_COUNT; i++) {
|
||||||
cpu.gpr[i] = cpu.bus->read_word(address);
|
if (get_bit(data.regs, i)) {
|
||||||
address += alignment;
|
cpu.gpr[i] = cpu.bus->read_word(address);
|
||||||
|
address += alignment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} 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 {
|
} else {
|
||||||
for (i = 0; i < cpu.GPR_COUNT; i++) {
|
if (data.up) {
|
||||||
if (get_bit(data.regs, i)) {
|
for (i = 0; i < cpu.GPR_COUNT; i++) {
|
||||||
cpu.bus->write_word(address, cpu.gpr[i]);
|
if (get_bit(data.regs, i)) {
|
||||||
address += alignment;
|
cpu.bus->write_word(address, cpu.gpr[i]);
|
||||||
|
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;
|
||||||
|
@@ -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);
|
||||||
|
Reference in New Issue
Block a user