diff --git a/src/cpu.c b/src/cpu.c index 724c117..cdb310b 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -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; diff --git a/tests/test_m283.c b/tests/test_m283.c index 862c7f3..c37866c 100644 --- a/tests/test_m283.c +++ b/tests/test_m283.c @@ -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};