Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 30 additions & 9 deletions src/cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -600,18 +600,39 @@ static int reference_step(struct amivm_cpu_state *cpu, struct amivm_vm *vm)
uint32_t index, target, sp;
if (fetch16(cpu, vm, next_pc, &ext) != 0)
return deliver_fault(cpu, vm, instruction_pc);
/* Full-format extensions are 68020+ and not handled here. */
if ((ext & 0x0100u) != 0u) {
set_fault(cpu, AMIVM_CPU_FAULT_ILLEGAL, instruction_pc, opcode);
return deliver_fault(cpu, vm, instruction_pc);
}
index = (ext & 0x8000u) ? cpu->a[(ext >> 12u) & 7u] : cpu->d[(ext >> 12u) & 7u];
if ((ext & 0x0800u) == 0u)
index = (uint32_t)(int32_t)(int16_t)(index & 0xffffu);
target = cpu->a[reg] + index + (uint32_t)(int32_t)(int8_t)(ext & 0xffu);
sp = cpu->a[7] - 4u;
if (!cpu_write32(cpu, vm, sp, is_supervisor(cpu), next_pc + 2u))
return deliver_fault(cpu, vm, instruction_pc);
if ((ext & 0x0100u) != 0u) { /* 68020+ full extension, no memory indirect */
uint32_t base = (ext & 0x0080u) ? 0u : cpu->a[reg];
uint32_t displacement = 0u;
unsigned bd_size = (unsigned)((ext >> 4u) & 3u);
if ((ext & 0x000fu) != 0u || bd_size == 0u) {
set_fault(cpu, AMIVM_CPU_FAULT_ILLEGAL, instruction_pc, opcode);
return deliver_fault(cpu, vm, instruction_pc);
}
if (bd_size == 2u) {
uint16_t word;
if (fetch16(cpu, vm, next_pc + 2u, &word) != 0)
return deliver_fault(cpu, vm, instruction_pc);
displacement = (uint32_t)(int32_t)(int16_t)word;
} else if (bd_size == 3u) {
if (fetch32(cpu, vm, next_pc + 2u, &displacement) != 0)
return deliver_fault(cpu, vm, instruction_pc);
}
if ((ext & 0x0040u) != 0u) index = 0u;
else index <<= (ext >> 9u) & 3u;
target = base + displacement + index;
sp = cpu->a[7] - 4u;
if (!cpu_write32(cpu, vm, sp, is_supervisor(cpu),
next_pc + 2u + (bd_size == 2u ? 2u : bd_size == 3u ? 4u : 0u)))
return deliver_fault(cpu, vm, instruction_pc);
} else {
target = cpu->a[reg] + index + (uint32_t)(int32_t)(int8_t)(ext & 0xffu);
sp = cpu->a[7] - 4u;
if (!cpu_write32(cpu, vm, sp, is_supervisor(cpu), next_pc + 2u))
return deliver_fault(cpu, vm, instruction_pc);
}
cpu->a[7] = sp;
save_active_sp(cpu);
cpu->pc = target;
Expand Down
10 changes: 10 additions & 0 deletions tests/test_m283.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,16 @@ int main(void) {
sizeof(jsr_a1_word_negative_disp),0u,1,0u,6u)==0);
CHECK(run_case_index("JSR A1.L positive",jsr_a1_long_positive,
sizeof(jsr_a1_long_positive),0u,1,0u,2u)==0);
/* M294: 68020 full extension, base A0 + signed word displacement.
* Index suppressed, no memory indirect: target ROM+0x110. */
static const uint8_t jsr_full_word_bd[] = {
0x4eu,0xb0u,0x01u,0x60u,0x00u,0x04u, /* JSR ([A0]+4), full ext */
0x60u,0xfeu, /* BRA.S self */
0x4eu,0x71u,0x4eu,0x71u,0x4eu,0x71u,
0x4eu,0x71u,0x4eu,0x75u /* +16: RTS */
};
CHECK(run_case_setup("JSR full extension word base displacement / RTS",
jsr_full_word_bd,sizeof(jsr_full_word_bd),0u,1)==0);
/* Exercise data-register and condition-code changes before a BRA loop. */
static const uint8_t moveq_zero_bra[] = {0x70u,0x00u,0x60u,0xfeu};
static const uint8_t moveq_neg_bra[] = {0x70u,0xffu,0x60u,0xfeu};
Expand Down
Loading