diff --git a/Processors/68000/Implementation/68000Implementation.hpp b/Processors/68000/Implementation/68000Implementation.hpp index 66df4e4cb..35b3d17ef 100644 --- a/Processors/68000/Implementation/68000Implementation.hpp +++ b/Processors/68000/Implementation/68000Implementation.hpp @@ -548,7 +548,7 @@ template void Processor: } \ \ auto step = bus_program; \ - uint32_t *address_storage = movem_addresses_; \ + uint32_t *address_storage = precomputed_addresses_; \ mask = next_word_; \ int offset = 0; @@ -596,7 +596,7 @@ template void Processor: } case Operation::MOVEMtoRl: { - setup_movem(2, movem_reads_steps_); + setup_movem(2, movem_read_steps_); // Everything for move to registers is based on an incrementing // address; per M68000PRM: @@ -613,23 +613,23 @@ template void Processor: // MOVEM to R always reads one word too many. address_storage[0] = start_address; step[0].microcycle.address = step[1].microcycle.address = address_storage; - step[0].microcycle.value = step[1].microcycle.value = &movem_spare_value_; + step[0].microcycle.value = step[1].microcycle.value = &throwaway_value_; movem_final_address_ = start_address; } break; case Operation::MOVEMtoRw: { - setup_movem(1, movem_reads_steps_); + setup_movem(1, movem_read_steps_); write_address_sequence_word(inc_action); // MOVEM to R always reads one word too many. address_storage[0] = start_address; step[0].microcycle.address = step[1].microcycle.address = address_storage; - step[0].microcycle.value = step[1].microcycle.value = &movem_spare_value_; + step[0].microcycle.value = step[1].microcycle.value = &throwaway_value_; movem_final_address_ = start_address; } break; case Operation::MOVEMtoMl: { - setup_movem(2, movem_writes_steps_); + setup_movem(2, movem_write_steps_); // MOVEM to M counts downwards and enumerates the registers in reverse order // if subject to the predecrementing mode; otherwise it counts upwards and @@ -652,7 +652,7 @@ template void Processor: } break; case Operation::MOVEMtoMw: { - setup_movem(1, movem_writes_steps_); + setup_movem(1, movem_write_steps_); if(mode == 4) { offset = 15; @@ -669,6 +669,27 @@ template void Processor: #undef inc_action #undef dec_action + // TRAP, which is a nicer form of ILLEGAL. + case Operation::TRAP: { + // Select the trap steps as next. + bus_program = trap_steps_; + + // Fill in the status word value. + destination_bus_data_[0].full = get_status(); + + // Switch to supervisor mode. + set_is_supervisor(true); + + // Pick a vector. + effective_address_[0].full = ((decoded_instruction_ & 15) + 32) << 2; + + // Schedule the proper stack activity. + precomputed_addresses_[0] = address_[7].full - 2; + precomputed_addresses_[1] = address_[7].full - 6; + precomputed_addresses_[2] = address_[7].full - 4; + address_[7].full -= 6; + } break; + /* NEGs: negatives the destination, setting the zero, negative, overflow and carry flags appropriate, and extend. diff --git a/Processors/68000/Implementation/68000Storage.cpp b/Processors/68000/Implementation/68000Storage.cpp index b294190ba..bc1b39fa8 100644 --- a/Processors/68000/Implementation/68000Storage.cpp +++ b/Processors/68000/Implementation/68000Storage.cpp @@ -377,6 +377,8 @@ struct ProcessorStorageConstructor { RTS, // Maps to an RST. MOVEUSP, // Maps a direction and register to a MOVE [to/from] USP. + + TRAP, // Maps to a TRAP. }; using Operation = ProcessorStorage::Operation; @@ -557,6 +559,7 @@ struct ProcessorStorageConstructor { {0xfff0, 0x4e60, Operation::MOVEAl, Decoder::MOVEUSP}, // 6-21 (p475) + {0xfff0, 0x4e40, Operation::TRAP, Decoder::TRAP}, // 4-188 (p292) }; #ifndef NDEBUG @@ -2424,24 +2427,6 @@ struct ProcessorStorageConstructor { // n np nr n np nw np // continue; -// case 0x1005: // MOVE (xxx).W, (d16, An) - // np nr np nw np -// continue; - -// case 0x1006: // MOVE (xxx).W, (d8, An, Xn) - // np nr n np nw np -// continue; - - case bw2(Imm, d16An): // MOVE.bw #, (d16, An) - case bw2(Imm, d8AnXn): // MOVE.bw #, (d8, An, Xn) - case bw2(Imm, d16PC): // MOVE.bw #, (d16, PC) - case bw2(Imm, d8PCXn): // MOVE.bw #, (d8, PC, Xn) - storage_.instructions[instruction].source = &storage_.destination_bus_data_[0]; - op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::DestinationMask, seq("np")); - op(calc_action_for_mode(combined_destination_mode) | MicroOp::DestinationMask, seq(pseq("np nw np", combined_destination_mode), { ea(1) }, !is_byte_access )); - op(is_byte_access ? Action::SetMoveFlagsb : Action::SetMoveFlagsl); - break; - case bw2(XXXl, d16An): // MOVE.bw (xxx).l, (d16, An) case bw2(XXXl, d8AnXn): // MOVE.bw (xxx).l, (d8, An, Xn) case bw2(XXXl, d16PC): // MOVE.bw (xxx).l, (d16, PC) @@ -2470,6 +2455,25 @@ struct ProcessorStorageConstructor { op(Action::PerformOperation, seq(pseq("np nW+ nw np", combined_destination_mode), { ea(1), ea(1) })); break; + case bw2(Imm, d16An): // MOVE.bw #, (d16, An) + case bw2(Imm, d16PC): // MOVE.bw #, (d16, PC) + case bw2(Imm, d8PCXn): // MOVE.bw #, (d8, PC, Xn) + case bw2(Imm, d8AnXn): // MOVE.bw #, (d8, An, Xn) + op(int(Action::AssembleWordDataFromPrefetch) | MicroOp::SourceMask, seq("np")); + op(calc_action_for_mode(combined_destination_mode) | MicroOp::DestinationMask, seq(pseq("np", combined_destination_mode))); + op(Action::PerformOperation, seq("nw np", { ea(1) }, !is_byte_access)); + break; + + case l2(Imm, d16An): // MOVE.l #, (d16, An) + case l2(Imm, d16PC): // MOVE.l #, (d16, PC) + case l2(Imm, d8PCXn): // MOVE.l #, (d8, PC, Xn) + case l2(Imm, d8AnXn): // MOVE.l #, (d8, An, Xn) + op(Action::None, seq("np")); + op(int(Action::AssembleLongWordDataFromPrefetch) | MicroOp::SourceMask, seq("np")); + op(calc_action_for_mode(combined_destination_mode) | MicroOp::DestinationMask, seq(pseq("np", combined_destination_mode))); + op(Action::PerformOperation, seq("nW+ nw np", { ea(1), ea(1) })); + break; + // // MOVE , (xxx).W // MOVE , (xxx).L @@ -2697,6 +2701,14 @@ struct ProcessorStorageConstructor { op(Action::None, seq("nn _ np")); break; + case Decoder::TRAP: { + // TRAP involves some oddly-sequenced stack writes, so is calculated + // at runtime; also the same sequence is used for illegal instructions. + // So the entirety is scheduled at runtime. + op(Action::PerformOperation); + op(); + } break; + case Decoder::TST: { storage_.instructions[instruction].set_source(storage_, ea_mode, ea_register); @@ -2864,8 +2876,11 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() { } movem_reads_pattern += "nr"; addresses.push_back(nullptr); - const size_t movem_reads_offset = constructor.assemble_program(movem_reads_pattern, addresses); - const size_t movem_writes_offset = constructor.assemble_program(movem_writes_pattern, addresses); + const size_t movem_read_offset = constructor.assemble_program(movem_reads_pattern, addresses); + const size_t movem_write_offset = constructor.assemble_program(movem_writes_pattern, addresses); + + // Target addresses and values will be filled in by TRAP/illegal too. + const size_t trap_offset = constructor.assemble_program("nn nw nw nW nV nv np np", { &precomputed_addresses_[0], &precomputed_addresses_[1], &precomputed_addresses_[2] }); // Install operations. constructor.install_instructions(); @@ -2882,8 +2897,17 @@ CPU::MC68000::ProcessorStorage::ProcessorStorage() { dbcc_condition_false_no_branch_steps_ = &all_bus_steps_[dbcc_condition_false_no_branch_offset]; dbcc_condition_false_branch_steps_ = &all_bus_steps_[dbcc_condition_false_branch_offset]; - movem_reads_steps_ = &all_bus_steps_[movem_reads_offset]; - movem_writes_steps_ = &all_bus_steps_[movem_writes_offset]; + movem_read_steps_ = &all_bus_steps_[movem_read_offset]; + movem_write_steps_ = &all_bus_steps_[movem_write_offset]; + + // Link the trap steps but also fill in the program counter as the source + // for its parts, and use the computed addresses. + // + // Order of output is: PC.l, SR, PC.h. + trap_steps_ = &all_bus_steps_[trap_offset]; + trap_steps_[1].microcycle.value = trap_steps_[2].microcycle.value = &program_counter_.halves.low; + trap_steps_[3].microcycle.value = trap_steps_[4].microcycle.value = &destination_bus_data_[0].halves.low; + trap_steps_[5].microcycle.value = trap_steps_[6].microcycle.value = &program_counter_.halves.high; // Set initial state. Largely TODO. active_step_ = reset_bus_steps_; diff --git a/Processors/68000/Implementation/68000Storage.hpp b/Processors/68000/Implementation/68000Storage.hpp index 8f97d3f7d..777988d4c 100644 --- a/Processors/68000/Implementation/68000Storage.hpp +++ b/Processors/68000/Implementation/68000Storage.hpp @@ -92,6 +92,8 @@ class ProcessorStorage { ORb, ORw, ORl, MULU, MULS, + + TRAP, }; /*! @@ -313,8 +315,10 @@ class ProcessorStorage { BusStep *dbcc_condition_false_no_branch_steps_; BusStep *dbcc_condition_false_branch_steps_; - BusStep *movem_reads_steps_; - BusStep *movem_writes_steps_; + BusStep *movem_read_steps_; + BusStep *movem_write_steps_; + + BusStep *trap_steps_; // Current bus step pointer, and outer program pointer. Program *active_program_ = nullptr; @@ -329,9 +333,9 @@ class ProcessorStorage { /// Sets or clears the supervisor flag, ensuring the stack pointer is properly updated. void set_is_supervisor(bool); - // Transient storage for MOVEM. - uint32_t movem_addresses_[65]; - RegisterPair16 movem_spare_value_; + // Transient storage for MOVEM, TRAP and others. + uint32_t precomputed_addresses_[65]; + RegisterPair16 throwaway_value_; uint32_t movem_final_address_; /*!