2019-03-09 05:00:23 +00:00
//
// 68000Storage.cpp
// Clock Signal
//
// Created by Thomas Harte on 08/03/2019.
// Copyright © 2019 Thomas Harte. All rights reserved.
//
# include "../68000.hpp"
2019-03-17 01:47:46 +00:00
# include <algorithm>
2019-05-03 18:37:05 +00:00
# include <cassert>
2019-05-03 18:42:36 +00:00
# include <ctime>
2019-04-30 02:08:16 +00:00
# include <map>
2019-05-03 18:43:31 +00:00
# include <vector>
2019-05-03 18:37:05 +00:00
# include <sstream>
2019-03-13 02:46:31 +00:00
2019-03-16 23:41:07 +00:00
namespace CPU {
namespace MC68000 {
2019-04-12 02:31:17 +00:00
# define Dn 0x00
# define An 0x01
# define Ind 0x02
# define PostInc 0x03
# define PreDec 0x04
# define d16An 0x05
# define d8AnXn 0x06
# define XXXw 0x10
# define XXXl 0x11
# define d16PC 0x12
# define d8PCXn 0x13
# define Imm 0x14
2019-03-16 23:41:07 +00:00
struct ProcessorStorageConstructor {
ProcessorStorageConstructor ( ProcessorStorage & storage ) : storage_ ( storage ) { }
using BusStep = ProcessorStorage : : BusStep ;
2019-03-25 03:05:57 +00:00
/*!
*/
2019-03-24 22:20:54 +00:00
int calc_action_for_mode ( int mode ) const {
using Action = ProcessorBase : : MicroOp : : Action ;
switch ( mode & 0xff ) {
2019-04-17 20:13:35 +00:00
default : assert ( false ) ;
2019-04-12 17:45:28 +00:00
case d16PC : return int ( Action : : CalcD16PC ) ;
case d8PCXn : return int ( Action : : CalcD8PCXn ) ;
case d16An : return int ( Action : : CalcD16An ) ;
case d8AnXn : return int ( Action : : CalcD8AnXn ) ;
2019-03-24 22:20:54 +00:00
}
}
2019-04-12 02:31:17 +00:00
int address_assemble_for_mode ( int mode ) const {
using Action = ProcessorBase : : MicroOp : : Action ;
assert ( ( mode & 0xff ) = = XXXw | | ( mode & 0xff ) = = XXXl ) ;
return int ( ( ( mode & 0xff ) = = XXXw ) ? Action : : AssembleWordAddressFromPrefetch : Action : : AssembleLongWordAddressFromPrefetch ) ;
}
2019-04-19 03:25:19 +00:00
int address_action_for_mode ( int mode ) const {
using Action = ProcessorBase : : MicroOp : : Action ;
switch ( mode & 0xff ) {
default : assert ( false ) ;
case d16PC : return int ( Action : : CalcD16PC ) ;
case d8PCXn : return int ( Action : : CalcD8PCXn ) ;
case d16An : return int ( Action : : CalcD16An ) ;
case d8AnXn : return int ( Action : : CalcD8AnXn ) ;
case XXXw : return int ( Action : : AssembleWordAddressFromPrefetch ) ;
case XXXl : return int ( Action : : AssembleLongWordAddressFromPrefetch ) ;
}
}
int combined_mode ( int mode , int reg , bool collapse_an_dn = false , bool collapse_postinc = false ) {
if ( collapse_an_dn & & mode = = An ) mode = Dn ;
if ( collapse_postinc & & mode = = PostInc ) mode = Ind ;
return ( mode = = 7 ) ? ( 0x10 | reg ) : mode ;
}
2019-04-12 02:31:17 +00:00
int data_assemble_for_mode ( int mode ) const {
using Action = ProcessorBase : : MicroOp : : Action ;
assert ( ( mode & 0xff ) = = XXXw | | ( mode & 0xff ) = = XXXl ) ;
return int ( ( ( mode & 0xff ) = = XXXw ) ? Action : : AssembleWordDataFromPrefetch : Action : : AssembleLongWordDataFromPrefetch ) ;
}
2019-04-25 03:01:32 +00:00
int byte_inc ( int reg ) const {
using Action = ProcessorBase : : MicroOp : : Action ;
// Special case: stack pointer byte accesses adjust by two.
return int ( ( reg = = 7 ) ? Action : : Increment2 : Action : : Increment1 ) ;
}
int byte_dec ( int reg ) const {
using Action = ProcessorBase : : MicroOp : : Action ;
// Special case: stack pointer byte accesses adjust by two.
return int ( ( reg = = 7 ) ? Action : : Decrement2 : Action : : Decrement1 ) ;
}
2019-04-24 17:01:08 +00:00
int increment_action ( bool is_long_word_access , bool is_byte_access , int reg ) const {
2019-04-19 17:29:20 +00:00
using Action = ProcessorBase : : MicroOp : : Action ;
2019-04-25 03:01:32 +00:00
if ( is_long_word_access ) return int ( Action : : Increment4 ) ;
if ( is_byte_access ) return byte_inc ( reg ) ;
return int ( Action : : Increment2 ) ;
2019-04-19 17:29:20 +00:00
}
2019-04-24 17:01:08 +00:00
int decrement_action ( bool is_long_word_access , bool is_byte_access , int reg ) const {
2019-04-19 17:29:20 +00:00
using Action = ProcessorBase : : MicroOp : : Action ;
2019-04-25 03:01:32 +00:00
if ( is_long_word_access ) return int ( Action : : Decrement4 ) ;
if ( is_byte_access ) return byte_dec ( reg ) ;
return int ( Action : : Decrement2 ) ;
2019-04-19 17:29:20 +00:00
}
2019-04-27 21:22:26 +00:00
# define pseq(x, m) ((((m)&0xff) == d8AnXn) || (((m)&0xff) == d8PCXn) ? "n " x : x)
2019-03-30 03:13:41 +00:00
2019-03-16 23:41:07 +00:00
/*!
Installs BusSteps that implement the described program into the relevant
instance storage , returning the offset within @ c all_bus_steps_ at which
the generated steps begin .
@ param access_pattern A string describing the bus activity that occurs
during this program . This should follow the same general pattern as
those in yacht . txt ; full description below .
2019-04-01 01:13:26 +00:00
@ param addresses A vector of the addresses to place on the bus coincident
with those acess steps that require them .
@ param read_full_words @ c true to indicate that read and write operations are
selecting a full word ; @ c false to signal byte accesses only .
2019-03-16 23:41:07 +00:00
@ discussion
2019-04-01 01:13:26 +00:00
The access pattern is defined to correlate closely to that in yacht . txt ; it is
a space - separated sequence of the following actions :
* n : no operation for four cycles ; data bus is not used ;
* nn : no operation for eight cycles ; data bus is not used ;
2019-04-11 02:31:04 +00:00
* r : a ' replaceable ' - length no operation ; data bus is not used and no guarantees are
made about the length of the cycle other than that when it reaches the interpreter ,
it is safe to alter the length and leave it altered ;
2019-04-01 01:13:26 +00:00
* np : program fetch ; reads from the PC and adds two to it , advancing the prefetch queue ;
* nW : write MSW of something onto the bus ;
* nw : write LSW of something onto the bus ;
* nR : read MSW of something from the bus into the source latch ;
* nr : read LSW of soemthing from the bus into the source latch ;
* nRd : read MSW of something from the bus into the destination latch ;
* nrd : read LSW of soemthing from the bus into the destination latch ;
2019-04-15 19:14:38 +00:00
* nS : push the MSW of something onto the stack * * and then * * decrement the pointer ;
* ns : push the LSW of something onto the stack * * and then * * decrement the pointer ;
2019-04-01 01:13:26 +00:00
* nU : pop the MSW of something from the stack ;
* nu : pop the LSW of something from the stack ;
* nV : fetch a vector ' s MSW ;
* nv : fetch a vector ' s LSW ;
2019-03-16 23:41:07 +00:00
* i : acquire interrupt vector in an IACK cycle ;
2019-06-21 22:20:26 +00:00
* nF : fetch the current SPs MSW ;
* nf : fetch the current SP ' s LSW ;
2019-04-01 01:13:26 +00:00
* _ : hold the reset line active for the usual period .
2019-04-25 16:19:40 +00:00
* tas : perform the final 6 cycles of a TAS : like an n nw but with the address strobe active for the entire period .
2019-05-01 19:19:24 +00:00
* int : the interrupt acknowledge cycle .
2019-03-16 23:41:07 +00:00
Quite a lot of that is duplicative , implying both something about internal
state and something about what ' s observable on the bus , but it ' s helpful to
stick to that document ' s coding exactly for easier debugging .
2019-04-03 23:13:10 +00:00
np fetches will fill the prefetch queue , attaching an action to both the
2019-06-21 22:20:26 +00:00
step that precedes them and to themselves . The SP fetches will go
to address_ [ 7 ] , whichever stack pointer that may currently be .
2019-03-16 23:41:07 +00:00
Other actions will by default act via effective_address_ and bus_data_ .
The user should fill in the steps necessary to get data into or extract
data from those .
2019-04-03 23:13:10 +00:00
nr / nw - type operations may have a + or - suffix ; if such a suffix is attached
then the corresponding effective address will be incremented or decremented
by two after the cycle has completed .
2019-03-16 23:41:07 +00:00
*/
2019-06-25 21:41:13 +00:00
size_t assemble_program ( const char * access_pattern , const std : : vector < uint32_t * > & addresses = { } , bool read_full_words = true ) {
2019-03-16 23:41:07 +00:00
auto address_iterator = addresses . begin ( ) ;
using Action = BusStep : : Action ;
2019-03-17 01:47:46 +00:00
std : : vector < BusStep > steps ;
2019-03-31 03:11:39 +00:00
// Tokenise the access pattern by splitting on spaces.
2019-06-25 21:41:13 +00:00
const char * next_access_pattern = access_pattern ;
while ( true ) {
/*
Ugly C - style string parsing here :
next_access_pattern is the end of the previous access pattern , i . e .
it is where parsing should begin to find the next one .
end_of_pattern will be where the current pattern ends , after any
modifier suffixes have been removed .
access_pattern is the beginning of the current pattern .
Obiter : this replaces a std : : stringstream > > std : : string implementation ,
that was a lot cleaner but implied a lot of std : : string constructions
that made this section of code measureable slower . Which , inter alia ,
had a bit impact on the rate at which unit tests would run .
So this ugliness is a net project improvement , I promise !
*/
while ( * next_access_pattern = = ' ' ) + + next_access_pattern ;
access_pattern = next_access_pattern ;
while ( * next_access_pattern ! = ' ' & & * next_access_pattern ! = ' \0 ' ) + + next_access_pattern ;
if ( next_access_pattern = = access_pattern ) break ;
const char * end_of_pattern = next_access_pattern ;
2019-03-16 23:41:07 +00:00
ProcessorBase : : BusStep step ;
2019-04-03 23:13:10 +00:00
// Check for a plus-or-minus suffix.
int post_adjustment = 0 ;
2019-06-25 21:41:13 +00:00
if ( end_of_pattern [ - 1 ] = = ' - ' | | end_of_pattern [ - 1 ] = = ' + ' ) {
if ( end_of_pattern [ - 1 ] = = ' - ' ) {
2019-04-03 23:13:10 +00:00
post_adjustment = - 1 ;
}
2019-06-25 21:41:13 +00:00
if ( end_of_pattern [ - 1 ] = = ' + ' ) {
2019-04-03 23:13:10 +00:00
post_adjustment = 1 ;
}
2019-06-25 21:41:13 +00:00
- - end_of_pattern ;
2019-04-03 23:13:10 +00:00
}
2019-06-25 21:41:13 +00:00
const auto token_length = end_of_pattern - access_pattern ;
2019-03-31 03:11:39 +00:00
// Do nothing (possibly twice).
2019-06-25 21:41:13 +00:00
if (
access_pattern [ 0 ] = = ' n ' & &
(
token_length = = 1 | |
( token_length = = 2 & & access_pattern [ 1 ] = = ' n ' )
)
) {
if ( token_length = = 2 ) {
2019-04-11 02:31:04 +00:00
step . microcycle . length = HalfCycles ( 8 ) ;
2019-03-31 03:11:39 +00:00
}
2019-04-11 02:31:04 +00:00
steps . push_back ( step ) ;
continue ;
}
// Do nothing, but with a length that definitely won't map it to the other do-nothings.
2019-06-25 21:41:13 +00:00
if (
access_pattern [ 0 ] = = ' r ' & &
token_length = = 1
) {
2019-06-24 21:55:09 +00:00
# ifndef NDEBUG
// If this is a debug build, not where the resizeable microcycle is
// (and double check that there's only the one).
step . microcycle . is_resizeable = true ;
# endif
2019-04-11 02:31:04 +00:00
step . microcycle . length = HalfCycles ( 0 ) ;
steps . push_back ( step ) ;
2019-03-31 03:11:39 +00:00
continue ;
}
2019-06-25 21:41:13 +00:00
if (
token_length = = 2 & &
access_pattern [ 0 ] = = ' n '
) {
// Fetch SSP.
if ( tolower ( access_pattern [ 1 ] ) = = ' f ' ) {
step . microcycle . operation = Microcycle : : NewAddress | Microcycle : : Read | Microcycle : : IsProgram ; // IsProgram is a guess.
step . microcycle . address = & storage_ . effective_address_ [ 0 ] . full ;
step . microcycle . value = isupper ( access_pattern [ 1 ] ) ? & storage_ . address_ [ 7 ] . halves . high : & storage_ . address_ [ 7 ] . halves . low ;
steps . push_back ( step ) ;
step . microcycle . operation = Microcycle : : SameAddress | Microcycle : : Read | Microcycle : : IsProgram | Microcycle : : SelectWord ;
2021-09-09 01:03:37 +00:00
step . action = isupper ( access_pattern [ 1 ] ) ? Action : : IncrementEffectiveAddress0 : Action : : IncrementEffectiveAddress0AlignStackPointer ;
2019-06-25 21:41:13 +00:00
steps . push_back ( step ) ;
continue ;
}
2019-03-31 03:11:39 +00:00
2019-06-25 21:41:13 +00:00
// Fetch exception vector.
if ( tolower ( access_pattern [ 1 ] ) = = ' v ' ) {
step . microcycle . operation = Microcycle : : NewAddress | Microcycle : : Read | Microcycle : : IsProgram ; // IsProgram is a guess.
step . microcycle . address = & storage_ . effective_address_ [ 0 ] . full ;
step . microcycle . value = isupper ( access_pattern [ 1 ] ) ? & storage_ . program_counter_ . halves . high : & storage_ . program_counter_ . halves . low ;
steps . push_back ( step ) ;
2019-03-31 03:11:39 +00:00
2019-06-25 21:41:13 +00:00
step . microcycle . operation = Microcycle : : SameAddress | Microcycle : : Read | Microcycle : : IsProgram | Microcycle : : SelectWord ;
step . action = Action : : IncrementEffectiveAddress0 ;
steps . push_back ( step ) ;
2019-03-31 03:11:39 +00:00
2019-06-25 21:41:13 +00:00
continue ;
}
2019-03-30 03:40:54 +00:00
2019-06-25 21:41:13 +00:00
// Fetch from the program counter into the prefetch queue.
if ( access_pattern [ 1 ] = = ' p ' ) {
step . microcycle . operation = Microcycle : : NewAddress | Microcycle : : Read | Microcycle : : IsProgram ;
step . microcycle . address = & storage_ . program_counter_ . full ;
step . microcycle . value = & storage_ . prefetch_queue_ . halves . low ;
step . action = Action : : AdvancePrefetch ;
steps . push_back ( step ) ;
2019-03-31 03:11:39 +00:00
2019-06-25 21:41:13 +00:00
step . microcycle . operation = Microcycle : : SameAddress | Microcycle : : Read | Microcycle : : IsProgram | Microcycle : : SelectWord ;
step . action = Action : : IncrementProgramCounter ;
steps . push_back ( step ) ;
2019-03-31 03:11:39 +00:00
2019-06-25 21:41:13 +00:00
continue ;
}
2019-03-31 03:11:39 +00:00
2019-06-25 21:41:13 +00:00
// A stack write.
if ( tolower ( access_pattern [ 1 ] ) = = ' s ' ) {
step . microcycle . operation = Microcycle : : NewAddress ;
step . microcycle . address = & storage_ . effective_address_ [ 1 ] . full ;
2020-05-19 03:55:54 +00:00
step . microcycle . value = isupper ( access_pattern [ 1 ] ) ? & storage_ . destination_bus_data_ . halves . high : & storage_ . destination_bus_data_ . halves . low ;
2019-06-25 21:41:13 +00:00
steps . push_back ( step ) ;
2019-03-31 03:11:39 +00:00
2019-06-25 21:41:13 +00:00
step . microcycle . operation = Microcycle : : SameAddress | Microcycle : : SelectWord ;
step . action = Action : : DecrementEffectiveAddress1 ;
steps . push_back ( step ) ;
continue ;
}
// A stack read.
if ( tolower ( access_pattern [ 1 ] ) = = ' u ' ) {
2020-05-19 03:55:54 +00:00
RegisterPair32 * const scratch_data = & storage_ . source_bus_data_ ;
2019-06-25 21:41:13 +00:00
step . microcycle . operation = Microcycle : : NewAddress | Microcycle : : Read ;
step . microcycle . address = & storage_ . effective_address_ [ 0 ] . full ;
step . microcycle . value = isupper ( access_pattern [ 1 ] ) ? & scratch_data - > halves . high : & scratch_data - > halves . low ;
steps . push_back ( step ) ;
step . microcycle . operation = Microcycle : : SameAddress | Microcycle : : Read | Microcycle : : SelectWord ;
step . action = Action : : IncrementEffectiveAddress0 ;
steps . push_back ( step ) ;
continue ;
}
2019-03-31 03:11:39 +00:00
}
// The reset cycle.
2019-06-25 21:41:13 +00:00
if ( token_length = = 1 & & access_pattern [ 0 ] = = ' _ ' ) {
2019-03-31 03:11:39 +00:00
step . microcycle . length = HalfCycles ( 248 ) ;
step . microcycle . operation = Microcycle : : Reset ;
steps . push_back ( step ) ;
continue ;
}
// A standard read or write.
2019-06-25 21:41:13 +00:00
if (
access_pattern [ 0 ] = = ' n ' & &
( tolower ( access_pattern [ 1 ] ) = = ' r ' | | tolower ( access_pattern [ 1 ] ) = = ' w ' ) & &
(
token_length = = 2 | |
(
token_length = = 3 & &
( access_pattern [ 2 ] = = ' d ' | | access_pattern [ 2 ] = = ' r ' )
)
)
) {
const bool is_read = tolower ( access_pattern [ 1 ] ) = = ' r ' ;
const bool use_source_storage = tolower ( end_of_pattern [ - 1 ] ) = = ' r ' ;
2020-05-19 03:55:54 +00:00
RegisterPair32 * const scratch_data = use_source_storage ? & storage_ . source_bus_data_ : & storage_ . destination_bus_data_ ;
2019-03-31 03:11:39 +00:00
2019-04-04 01:27:11 +00:00
assert ( address_iterator ! = addresses . end ( ) ) ;
2019-03-31 03:11:39 +00:00
step . microcycle . operation = Microcycle : : NewAddress | ( is_read ? Microcycle : : Read : 0 ) ;
step . microcycle . address = * address_iterator ;
2019-06-25 21:41:13 +00:00
step . microcycle . value = isupper ( access_pattern [ 1 ] ) ? & scratch_data - > halves . high : & scratch_data - > halves . low ;
2019-03-31 03:11:39 +00:00
steps . push_back ( step ) ;
2019-04-25 16:19:40 +00:00
step . microcycle . operation = Microcycle : : SameAddress | ( is_read ? Microcycle : : Read : 0 ) | ( read_full_words ? Microcycle : : SelectWord : Microcycle : : SelectByte ) ;
2019-04-03 23:13:10 +00:00
if ( post_adjustment ) {
2019-07-02 17:54:21 +00:00
assert ( ( * address_iterator = = & storage_ . effective_address_ [ 0 ] . full ) | | ( * address_iterator = = & storage_ . effective_address_ [ 1 ] . full ) ) ;
if ( * address_iterator = = & storage_ . effective_address_ [ 0 ] . full ) {
2019-04-03 23:13:10 +00:00
step . action = ( post_adjustment > 0 ) ? Action : : IncrementEffectiveAddress0 : Action : : DecrementEffectiveAddress0 ;
} else {
step . action = ( post_adjustment > 0 ) ? Action : : IncrementEffectiveAddress1 : Action : : DecrementEffectiveAddress1 ;
}
2019-03-31 03:11:39 +00:00
}
steps . push_back ( step ) ;
2019-04-04 01:27:11 +00:00
+ + address_iterator ;
2019-03-31 03:11:39 +00:00
continue ;
}
2019-06-25 21:41:13 +00:00
if ( token_length = = 3 ) {
// The completing part of a TAS.
if ( access_pattern [ 0 ] = = ' t ' & & access_pattern [ 1 ] = = ' a ' & & access_pattern [ 2 ] = = ' s ' ) {
2020-05-19 03:55:54 +00:00
RegisterPair32 * const scratch_data = & storage_ . destination_bus_data_ ;
2019-04-25 16:19:40 +00:00
2019-06-25 21:41:13 +00:00
assert ( address_iterator ! = addresses . end ( ) ) ;
2019-04-25 16:19:40 +00:00
2019-06-25 21:41:13 +00:00
step . microcycle . length = HalfCycles ( 9 ) ;
step . microcycle . operation = Microcycle : : SameAddress ;
step . microcycle . address = * address_iterator ;
step . microcycle . value = & scratch_data - > halves . low ;
steps . push_back ( step ) ;
2019-04-25 16:19:40 +00:00
2019-06-25 21:41:13 +00:00
step . microcycle . length = HalfCycles ( 3 ) ;
step . microcycle . operation = Microcycle : : SameAddress | Microcycle : : SelectByte ;
steps . push_back ( step ) ;
+ + address_iterator ;
2019-04-15 19:14:38 +00:00
2019-06-25 21:41:13 +00:00
continue ;
}
2019-04-15 19:14:38 +00:00
2019-06-25 21:41:13 +00:00
// Interrupt acknowledge.
if ( access_pattern [ 0 ] = = ' i ' & & access_pattern [ 1 ] = = ' n ' & & access_pattern [ 2 ] = = ' t ' ) {
step . microcycle . operation = Microcycle : : InterruptAcknowledge | Microcycle : : NewAddress ;
step . microcycle . address = & storage_ . effective_address_ [ 0 ] . full ; // The selected interrupt should be in bits 1– 3; but 0 should be set.
2020-05-19 03:55:54 +00:00
step . microcycle . value = & storage_ . source_bus_data_ . halves . low ;
2019-06-25 21:41:13 +00:00
steps . push_back ( step ) ;
2019-05-01 19:19:24 +00:00
2019-06-25 21:41:13 +00:00
step . microcycle . operation = Microcycle : : InterruptAcknowledge | Microcycle : : SameAddress | Microcycle : : SelectByte ;
steps . push_back ( step ) ;
2019-05-01 19:19:24 +00:00
2019-06-25 21:41:13 +00:00
continue ;
}
2019-05-01 19:19:24 +00:00
}
2019-06-25 21:41:13 +00:00
std : : cerr < < " MC68000 program builder; Unknown access token " < < std : : string ( access_pattern , end_of_pattern ) < < std : : endl ;
2019-03-31 03:11:39 +00:00
assert ( false ) ;
2019-03-16 23:41:07 +00:00
}
2019-03-12 02:47:58 +00:00
2019-03-16 23:41:07 +00:00
// Add a final 'ScheduleNextProgram' sentinel.
BusStep end_program ;
end_program . action = Action : : ScheduleNextProgram ;
2019-03-17 01:47:46 +00:00
steps . push_back ( end_program ) ;
2019-03-10 21:27:34 +00:00
2019-03-17 01:47:46 +00:00
// If the new steps already exist, just return the existing index to them;
// otherwise insert them.
2019-06-20 19:10:11 +00:00
/*const auto position = std::search(storage_.all_bus_steps_.begin(), storage_.all_bus_steps_.end(), steps.begin(), steps.end());
2019-03-17 01:47:46 +00:00
if ( position ! = storage_ . all_bus_steps_ . end ( ) ) {
return size_t ( position - storage_ . all_bus_steps_ . begin ( ) ) ;
2019-03-16 23:41:07 +00:00
}
2019-03-10 21:27:34 +00:00
2019-04-30 02:10:00 +00:00
const auto start = storage_ . all_bus_steps_ . size ( ) ;
std : : copy ( steps . begin ( ) , steps . end ( ) , std : : back_inserter ( storage_ . all_bus_steps_ ) ) ;
2019-06-20 19:10:11 +00:00
return start ; */
2019-04-30 02:10:00 +00:00
2019-04-30 02:08:16 +00:00
// If the new steps already exist, just return the existing index to them;
// otherwise insert them. A lookup table of steps to start positions within
// all_bus_steps_ is maintained to shorten setup time here
auto potential_locations = locations_by_bus_step_ [ steps . front ( ) ] ;
for ( auto index : potential_locations ) {
2019-06-20 19:10:11 +00:00
if ( index + steps . size ( ) > storage_ . all_bus_steps_ . size ( ) ) continue ;
2019-04-30 02:08:16 +00:00
if ( std : : equal (
storage_ . all_bus_steps_ . begin ( ) + ssize_t ( index ) ,
storage_ . all_bus_steps_ . begin ( ) + ssize_t ( index + steps . size ( ) ) ,
steps . begin ( ) ) ) {
return index ;
}
}
// Copy to the end, and update potential_locations.
2019-03-17 01:47:46 +00:00
const auto start = storage_ . all_bus_steps_ . size ( ) ;
std : : copy ( steps . begin ( ) , steps . end ( ) , std : : back_inserter ( storage_ . all_bus_steps_ ) ) ;
2019-04-30 02:08:16 +00:00
auto index = start ;
for ( const auto & step : steps ) {
locations_by_bus_step_ [ step ] . push_back ( index ) ;
+ + index ;
}
2019-06-20 19:10:11 +00:00
return start ;
2019-03-16 23:41:07 +00:00
}
2019-03-10 21:27:34 +00:00
2019-05-02 19:25:43 +00:00
/*!
Walks through the sequence of bus steps beginning at @ c start , replacing the value supplied for each write
encountered with the respective value from @ c values .
*/
2019-05-30 16:08:35 +00:00
void replace_write_values ( BusStep * start , const std : : initializer_list < RegisterPair16 * > & values ) {
2019-05-29 23:00:53 +00:00
const auto end = replace_write_values ( start , values . begin ( ) ) ;
assert ( end = = values . end ( ) ) ;
2019-06-13 14:20:17 +00:00
( void ) end ;
2019-05-02 19:25:43 +00:00
}
/*!
Walks through the sequence of micro - ops beginning at @ c start , replacing the value supplied for each write
encountered in each micro - op ' s bus steps with the respective value from @ c values .
*/
2019-05-30 16:08:35 +00:00
void replace_write_values ( ProcessorBase : : MicroOp * start , const std : : initializer_list < RegisterPair16 * > & values ) {
2019-05-02 19:25:43 +00:00
auto value = values . begin ( ) ;
while ( ! start - > is_terminal ( ) ) {
2019-07-25 14:14:36 +00:00
value = replace_write_values ( & storage_ . all_bus_steps_ [ start - > bus_program ] , value ) ;
2019-05-02 19:25:43 +00:00
+ + start ;
}
assert ( value = = values . end ( ) ) ;
}
2019-03-16 23:41:07 +00:00
/*!
Disassembles the instruction @ c instruction and inserts it into the
appropriate lookup tables .
2019-03-10 21:27:34 +00:00
2019-03-16 23:41:07 +00:00
install_instruction acts , in effect , in the manner of a disassembler . So this class is
formulated to run through all potential 65536 instuction encodings and attempt to
disassemble each , rather than going in the opposite direction .
2019-03-10 21:27:34 +00:00
2019-03-16 23:41:07 +00:00
This has two benefits :
2019-03-10 21:27:34 +00:00
2019-03-16 23:41:07 +00:00
( i ) which addressing modes go with which instructions falls out automatically ;
( ii ) it is a lot easier during the manual verification stage of development to work
from known instructions to their disassembly rather than vice versa ; especially
( iii ) given that there are plentiful disassemblers against which to test work in progress .
*/
2019-03-17 01:47:46 +00:00
void install_instructions ( ) {
2019-03-16 23:41:07 +00:00
enum class Decoder {
2019-04-16 23:50:10 +00:00
ABCD_SBCD , // Maps source and desintation registers and a register/memory selection bit to an ABCD or SBCD.
ADD_SUB , // Maps a register and a register and mode to an ADD or SUB.
ADDA_SUBA , // Maps a destination register and a source mode and register to an ADDA or SUBA.
2019-04-18 20:34:48 +00:00
ADDQ_SUBQ , // Maps a register and a mode to an ADDQ or SUBQ.
2019-04-27 20:57:21 +00:00
ADDX_SUBX , // Maps source and destination registers, and register/memory mode to an ADDX or SUBX.
2019-04-18 20:34:48 +00:00
AND_OR_EOR , // Maps a source register, operation mode and destination register and mode to an AND, OR or EOR.
2019-04-09 02:51:18 +00:00
BRA , // Maps to a BRA. All fields are decoded at runtime.
2019-04-16 23:50:10 +00:00
Bcc_BSR , // Maps to a Bcc or BSR. Other than determining the type of operation, fields are decoded at runtime.
2019-04-09 02:51:18 +00:00
BTST , // Maps a source register and a destination register and mode to a BTST.
BTSTIMM , // Maps a destination mode and register to a BTST #.
2019-04-15 22:11:02 +00:00
BCLR , // Maps a source register and a destination register and mode to a BCLR.
BCLRIMM , // Maps a destination mode and register to a BCLR #.
2019-04-16 23:50:10 +00:00
CLR_NEG_NEGX_NOT , // Maps a destination mode and register to a CLR, NEG, NEGX or NOT.
2019-04-09 02:51:18 +00:00
2019-04-09 02:40:38 +00:00
CMP , // Maps a destination register and a source mode and register to a CMP.
CMPI , // Maps a destination mode and register to a CMPI.
CMPA , // Maps a destination register and a source mode and register to a CMPA.
CMPM , // Maps to a CMPM.
2019-04-17 02:16:43 +00:00
EORI_ORI_ANDI_SUBI_ADDI , // Maps a mode and register to one of EORI, ORI, ANDI, SUBI or ADDI.
2019-04-09 02:51:18 +00:00
JMP , // Maps a mode and register to a JMP.
2019-04-17 02:16:43 +00:00
JSR , // Maps a mode and register to a JSR.
2019-04-09 02:51:18 +00:00
LEA , // Maps a destination register and a source mode and register to an LEA.
MOVE , // Maps a source mode and register and a destination mode and register to a MOVE.
2019-04-25 18:39:32 +00:00
MOVEtoSRCCR , // Maps a source mode and register to a MOVE to SR or MOVE to CCR.
2019-04-28 01:29:50 +00:00
MOVEfromSR_NBCD , // Maps a source mode and register to a MOVE fom SR.
2019-04-09 02:51:18 +00:00
MOVEq , // Maps a destination register to a MOVEQ.
2019-04-17 02:16:43 +00:00
MULU_MULS , // Maps a destination register and a source mode and register to a MULU or MULS.
2019-04-27 02:22:35 +00:00
DIVU_DIVS , // Maps a destination register and a source mode and register to a DIVU or DIVS.
2019-04-17 02:16:43 +00:00
2019-04-09 02:51:18 +00:00
RESET , // Maps to a RESET.
2019-04-09 20:54:41 +00:00
2019-04-16 23:50:10 +00:00
ASLR_LSLR_ROLR_ROXLRr , // Maps a destination register to a AS[L/R], LS[L/R], RO[L/R], ROX[L/R]; shift quantities are
2019-04-09 20:54:41 +00:00
// decoded at runtime.
2019-04-16 23:50:10 +00:00
ASLR_LSLR_ROLR_ROXLRm , // Maps a destination mode and register to a memory-based AS[L/R], LS[L/R], RO[L/R], ROX[L/R].
2019-04-14 18:09:28 +00:00
2019-04-29 02:52:54 +00:00
MOVEM , // Maps a mode and register as if they were a 'destination' and sets up bus steps with a suitable
2019-04-14 18:09:28 +00:00
// hole for the runtime part to install proper MOVEM activity.
2019-04-29 02:52:54 +00:00
MOVEP , // Maps a data register, address register and operation mode to a MOVEP.
2019-04-15 14:03:52 +00:00
2019-04-19 00:50:58 +00:00
RTE_RTR , // Maps to an RTE/RTR.
2019-04-17 02:16:43 +00:00
Scc_DBcc , // Maps a mode and destination register to either a DBcc or Scc.
2019-04-15 19:14:38 +00:00
TST , // Maps a mode and register to a TST.
2019-04-17 02:16:43 +00:00
RTS , // Maps to an RST.
2019-04-17 20:58:59 +00:00
MOVEUSP , // Maps a direction and register to a MOVE [to/from] USP.
2019-04-18 02:21:56 +00:00
TRAP , // Maps to a TRAP.
2019-04-28 19:52:58 +00:00
TRAPV , // Maps to a TRAPV.
2019-04-28 19:47:21 +00:00
CHK , // Maps to a CHK.
2019-04-19 03:46:01 +00:00
NOP , // Maps to a NOP.
2019-04-19 15:27:43 +00:00
EXG , // Maps source and destination registers and an operation mode to an EXG.
2019-04-25 22:22:19 +00:00
EXT_SWAP , // Maps a source register to a SWAP or EXT.
2019-04-24 21:38:59 +00:00
EORI_ORI_ANDI_SR , // Maps to an EORI, ORI or ANDI to SR/CCR.
2019-04-25 03:01:32 +00:00
BCHG_BSET , // Maps a mode and register, and possibly a source register, to a BCHG or BSET.
2019-04-25 16:19:40 +00:00
TAS , // Maps a mode and register to a TAS.
2019-04-26 17:49:59 +00:00
PEA , // Maps a mode and register to a PEA.
2019-04-28 21:12:31 +00:00
LINK , // Maps a register to a LINK.
UNLINK , // Maps a register to an UNLINK.
2019-04-29 23:30:00 +00:00
STOP , // Maps to a STOP.
2019-03-16 23:41:07 +00:00
} ;
using Operation = ProcessorStorage : : Operation ;
using Action = ProcessorStorage : : MicroOp : : Action ;
2019-03-19 02:51:32 +00:00
using MicroOp = ProcessorBase : : MicroOp ;
2019-03-16 23:41:07 +00:00
struct PatternMapping {
uint16_t mask , value ;
Operation operation ;
Decoder decoder ;
} ;
/*
Inspired partly by ' wrm ' ( https : //github.com/wrm-za I assume); the following
table draws from the M68000 Programmer ' s Reference Manual , currently available at
https : //www.nxp.com/files-static/archives/doc/ref_manual/M68000PRM.pdf
After each line is the internal page number on which documentation of that
instruction mapping can be found , followed by the page number within the PDF
linked above .
NB : a vector is used to allow easy iteration .
*/
2019-05-30 16:08:35 +00:00
const std : : initializer_list < PatternMapping > mappings = {
2019-04-28 01:29:50 +00:00
{ 0xf1f0 , 0xc100 , Operation : : ABCD , Decoder : : ABCD_SBCD } , // 4-3 (p107)
{ 0xf1f0 , 0x8100 , Operation : : SBCD , Decoder : : ABCD_SBCD } , // 4-171 (p275)
{ 0xffc0 , 0x4800 , Operation : : NBCD , Decoder : : MOVEfromSR_NBCD } , // 4-142 (p246)
2019-03-16 23:41:07 +00:00
2019-04-18 20:34:48 +00:00
{ 0xf0c0 , 0xc000 , Operation : : ANDb , Decoder : : AND_OR_EOR } , // 4-15 (p119)
{ 0xf0c0 , 0xc040 , Operation : : ANDw , Decoder : : AND_OR_EOR } , // 4-15 (p119)
{ 0xf0c0 , 0xc080 , Operation : : ANDl , Decoder : : AND_OR_EOR } , // 4-15 (p119)
{ 0xf0c0 , 0x8000 , Operation : : ORb , Decoder : : AND_OR_EOR } , // 4-150 (p254)
{ 0xf0c0 , 0x8040 , Operation : : ORw , Decoder : : AND_OR_EOR } , // 4-150 (p254)
{ 0xf0c0 , 0x8080 , Operation : : ORl , Decoder : : AND_OR_EOR } , // 4-150 (p254)
{ 0xf0c0 , 0xb000 , Operation : : EORb , Decoder : : AND_OR_EOR } , // 4-100 (p204)
{ 0xf0c0 , 0xb040 , Operation : : EORw , Decoder : : AND_OR_EOR } , // 4-100 (p204)
{ 0xf0c0 , 0xb080 , Operation : : EORl , Decoder : : AND_OR_EOR } , // 4-100 (p204)
2019-03-16 23:41:07 +00:00
2019-04-16 23:50:10 +00:00
{ 0xffc0 , 0x0600 , Operation : : ADDb , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-9 (p113)
{ 0xffc0 , 0x0640 , Operation : : ADDw , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-9 (p113)
{ 0xffc0 , 0x0680 , Operation : : ADDl , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-9 (p113)
2019-04-29 21:45:52 +00:00
{ 0xffc0 , 0x0200 , Operation : : ANDb , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-18 (p122)
{ 0xffc0 , 0x0240 , Operation : : ANDw , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-18 (p122)
{ 0xffc0 , 0x0280 , Operation : : ANDl , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-18 (p122)
2019-04-16 23:50:10 +00:00
2019-04-29 21:45:52 +00:00
{ 0xffc0 , 0x0000 , Operation : : ORb , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-153 (p257)
{ 0xffc0 , 0x0040 , Operation : : ORw , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-153 (p257)
{ 0xffc0 , 0x0080 , Operation : : ORl , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-153 (p257)
2019-04-16 23:50:10 +00:00
2019-04-29 21:45:52 +00:00
{ 0xffc0 , 0x0a00 , Operation : : EORb , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-102 (p206)
{ 0xffc0 , 0x0a40 , Operation : : EORw , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-102 (p206)
{ 0xffc0 , 0x0a80 , Operation : : EORl , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-102 (p206)
2019-03-16 23:41:07 +00:00
2019-04-16 23:50:10 +00:00
{ 0xffc0 , 0x0400 , Operation : : SUBb , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-179 (p283)
{ 0xffc0 , 0x0440 , Operation : : SUBw , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-179 (p283)
{ 0xffc0 , 0x0480 , Operation : : SUBl , Decoder : : EORI_ORI_ANDI_SUBI_ADDI } , // 4-179 (p283)
2019-03-16 23:41:07 +00:00
2019-03-30 03:13:41 +00:00
{ 0xf000 , 0x1000 , Operation : : MOVEb , Decoder : : MOVE } , // 4-116 (p220)
{ 0xf000 , 0x2000 , Operation : : MOVEl , Decoder : : MOVE } , // 4-116 (p220)
{ 0xf000 , 0x3000 , Operation : : MOVEw , Decoder : : MOVE } , // 4-116 (p220)
2019-03-24 22:20:54 +00:00
2019-04-28 01:29:50 +00:00
{ 0xffc0 , 0x46c0 , Operation : : MOVEtoSR , Decoder : : MOVEtoSRCCR } , // 6-19 (p473)
{ 0xffc0 , 0x44c0 , Operation : : MOVEtoCCR , Decoder : : MOVEtoSRCCR } , // 4-123 (p227)
{ 0xffc0 , 0x40c0 , Operation : : MOVEfromSR , Decoder : : MOVEfromSR_NBCD } , // 6-17 (p471)
2019-03-25 03:05:57 +00:00
2019-04-06 14:41:19 +00:00
{ 0xf1c0 , 0xb000 , Operation : : CMPb , Decoder : : CMP } , // 4-75 (p179)
{ 0xf1c0 , 0xb040 , Operation : : CMPw , Decoder : : CMP } , // 4-75 (p179)
{ 0xf1c0 , 0xb080 , Operation : : CMPl , Decoder : : CMP } , // 4-75 (p179)
2019-04-09 02:40:38 +00:00
2019-06-27 01:42:48 +00:00
{ 0xf1c0 , 0xb0c0 , Operation : : CMPAw , Decoder : : CMPA } , // 4-77 (p181)
2019-04-09 02:40:38 +00:00
{ 0xf1c0 , 0xb1c0 , Operation : : CMPl , Decoder : : CMPA } , // 4-77 (p181)
2019-03-26 02:54:49 +00:00
{ 0xffc0 , 0x0c00 , Operation : : CMPb , Decoder : : CMPI } , // 4-79 (p183)
{ 0xffc0 , 0x0c40 , Operation : : CMPw , Decoder : : CMPI } , // 4-79 (p183)
{ 0xffc0 , 0x0c80 , Operation : : CMPl , Decoder : : CMPI } , // 4-79 (p183)
2019-04-09 02:40:38 +00:00
{ 0xf1f8 , 0xb108 , Operation : : CMPb , Decoder : : CMPM } , // 4-81 (p185)
{ 0xf1f8 , 0xb148 , Operation : : CMPw , Decoder : : CMPM } , // 4-81 (p185)
{ 0xf1f8 , 0xb188 , Operation : : CMPl , Decoder : : CMPM } , // 4-81 (p185)
2019-04-09 20:54:41 +00:00
// {0xff00, 0x6000, Operation::BRA, Decoder::BRA}, // 4-55 (p159) TODO: confirm that this really, really is just a special case of Bcc.
2019-04-16 23:50:10 +00:00
{ 0xf000 , 0x6000 , Operation : : Bcc , Decoder : : Bcc_BSR } , // 4-25 (p129) and 4-59 (p163)
2019-04-09 20:54:41 +00:00
2019-03-27 02:07:28 +00:00
{ 0xf1c0 , 0x41c0 , Operation : : MOVEAl , Decoder : : LEA } , // 4-110 (p214)
2019-05-29 18:37:15 +00:00
{ 0xffc0 , 0x4840 , Operation : : PEA , Decoder : : PEA } , // 4-159 (p263)
2019-04-26 17:49:59 +00:00
2019-03-30 03:13:41 +00:00
{ 0xf100 , 0x7000 , Operation : : MOVEq , Decoder : : MOVEq } , // 4-134 (p238)
2019-03-30 03:40:54 +00:00
{ 0xffff , 0x4e70 , Operation : : None , Decoder : : RESET } , // 6-83 (p537)
2019-04-01 01:13:26 +00:00
{ 0xffc0 , 0x4ec0 , Operation : : JMP , Decoder : : JMP } , // 4-108 (p212)
2019-04-15 19:14:38 +00:00
{ 0xffc0 , 0x4e80 , Operation : : JMP , Decoder : : JSR } , // 4-109 (p213)
2019-06-03 19:29:50 +00:00
{ 0xffff , 0x4e75 , Operation : : RTS , Decoder : : RTS } , // 4-169 (p273)
2019-04-03 01:50:58 +00:00
2019-04-16 23:50:10 +00:00
{ 0xf0c0 , 0x9000 , Operation : : SUBb , Decoder : : ADD_SUB } , // 4-174 (p278)
{ 0xf0c0 , 0x9040 , Operation : : SUBw , Decoder : : ADD_SUB } , // 4-174 (p278)
{ 0xf0c0 , 0x9080 , Operation : : SUBl , Decoder : : ADD_SUB } , // 4-174 (p278)
2019-04-03 01:50:58 +00:00
2019-04-16 23:50:10 +00:00
{ 0xf0c0 , 0xd000 , Operation : : ADDb , Decoder : : ADD_SUB } , // 4-4 (p108)
{ 0xf0c0 , 0xd040 , Operation : : ADDw , Decoder : : ADD_SUB } , // 4-4 (p108)
{ 0xf0c0 , 0xd080 , Operation : : ADDl , Decoder : : ADD_SUB } , // 4-4 (p108)
2019-04-03 01:50:58 +00:00
2019-04-16 23:50:10 +00:00
{ 0xf1c0 , 0xd0c0 , Operation : : ADDAw , Decoder : : ADDA_SUBA } , // 4-7 (p111)
{ 0xf1c0 , 0xd1c0 , Operation : : ADDAl , Decoder : : ADDA_SUBA } , // 4-7 (p111)
{ 0xf1c0 , 0x90c0 , Operation : : SUBAw , Decoder : : ADDA_SUBA } , // 4-177 (p281)
{ 0xf1c0 , 0x91c0 , Operation : : SUBAl , Decoder : : ADDA_SUBA } , // 4-177 (p281)
2019-04-05 01:43:22 +00:00
2019-04-16 23:50:10 +00:00
{ 0xf1c0 , 0x5000 , Operation : : ADDQb , Decoder : : ADDQ_SUBQ } , // 4-11 (p115)
{ 0xf1c0 , 0x5040 , Operation : : ADDQw , Decoder : : ADDQ_SUBQ } , // 4-11 (p115)
{ 0xf1c0 , 0x5080 , Operation : : ADDQl , Decoder : : ADDQ_SUBQ } , // 4-11 (p115)
2019-04-16 15:19:45 +00:00
2019-04-16 23:50:10 +00:00
{ 0xf1c0 , 0x5100 , Operation : : SUBQb , Decoder : : ADDQ_SUBQ } , // 4-181 (p285)
{ 0xf1c0 , 0x5140 , Operation : : SUBQw , Decoder : : ADDQ_SUBQ } , // 4-181 (p285)
{ 0xf1c0 , 0x5180 , Operation : : SUBQl , Decoder : : ADDQ_SUBQ } , // 4-181 (p285)
2019-04-16 15:19:45 +00:00
2019-04-27 20:57:21 +00:00
{ 0xf1f0 , 0xd100 , Operation : : ADDXb , Decoder : : ADDX_SUBX } , // 4-14 (p118)
{ 0xf1f0 , 0xd140 , Operation : : ADDXw , Decoder : : ADDX_SUBX } , // 4-14 (p118)
{ 0xf1f0 , 0xd180 , Operation : : ADDXl , Decoder : : ADDX_SUBX } , // 4-14 (p118)
{ 0xf1f0 , 0x9100 , Operation : : SUBXb , Decoder : : ADDX_SUBX } , // 4-184 (p288)
{ 0xf1f0 , 0x9140 , Operation : : SUBXw , Decoder : : ADDX_SUBX } , // 4-184 (p288)
{ 0xf1f0 , 0x9180 , Operation : : SUBXl , Decoder : : ADDX_SUBX } , // 4-184 (p288)
2019-04-05 01:43:22 +00:00
{ 0xf1c0 , 0x0100 , Operation : : BTSTb , Decoder : : BTST } , // 4-62 (p166)
{ 0xffc0 , 0x0800 , Operation : : BTSTb , Decoder : : BTSTIMM } , // 4-63 (p167)
2019-04-07 03:21:01 +00:00
2019-04-15 22:11:02 +00:00
{ 0xf1c0 , 0x0180 , Operation : : BCLRb , Decoder : : BCLR } , // 4-31 (p135)
{ 0xffc0 , 0x0880 , Operation : : BCLRb , Decoder : : BCLRIMM } , // 4-32 (p136)
2019-04-16 23:50:10 +00:00
{ 0xf0c0 , 0x50c0 , Operation : : Scc , Decoder : : Scc_DBcc } , // Scc: 4-173 (p276); DBcc: 4-91 (p195)
{ 0xffc0 , 0x4200 , Operation : : CLRb , Decoder : : CLR_NEG_NEGX_NOT } , // 4-73 (p177)
{ 0xffc0 , 0x4240 , Operation : : CLRw , Decoder : : CLR_NEG_NEGX_NOT } , // 4-73 (p177)
{ 0xffc0 , 0x4280 , Operation : : CLRl , Decoder : : CLR_NEG_NEGX_NOT } , // 4-73 (p177)
{ 0xffc0 , 0x4400 , Operation : : NEGb , Decoder : : CLR_NEG_NEGX_NOT } , // 4-144 (p248)
{ 0xffc0 , 0x4440 , Operation : : NEGw , Decoder : : CLR_NEG_NEGX_NOT } , // 4-144 (p248)
{ 0xffc0 , 0x4480 , Operation : : NEGl , Decoder : : CLR_NEG_NEGX_NOT } , // 4-144 (p248)
{ 0xffc0 , 0x4000 , Operation : : NEGXb , Decoder : : CLR_NEG_NEGX_NOT } , // 4-146 (p250)
{ 0xffc0 , 0x4040 , Operation : : NEGXw , Decoder : : CLR_NEG_NEGX_NOT } , // 4-146 (p250)
{ 0xffc0 , 0x4080 , Operation : : NEGXl , Decoder : : CLR_NEG_NEGX_NOT } , // 4-146 (p250)
{ 0xffc0 , 0x4600 , Operation : : NOTb , Decoder : : CLR_NEG_NEGX_NOT } , // 4-148 (p250)
{ 0xffc0 , 0x4640 , Operation : : NOTw , Decoder : : CLR_NEG_NEGX_NOT } , // 4-148 (p250)
{ 0xffc0 , 0x4680 , Operation : : NOTl , Decoder : : CLR_NEG_NEGX_NOT } , // 4-148 (p250)
{ 0xf1d8 , 0xe100 , Operation : : ASLb , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-22 (p126)
{ 0xf1d8 , 0xe140 , Operation : : ASLw , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-22 (p126)
{ 0xf1d8 , 0xe180 , Operation : : ASLl , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-22 (p126)
{ 0xffc0 , 0xe1c0 , Operation : : ASLm , Decoder : : ASLR_LSLR_ROLR_ROXLRm } , // 4-22 (p126)
{ 0xf1d8 , 0xe000 , Operation : : ASRb , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-22 (p126)
{ 0xf1d8 , 0xe040 , Operation : : ASRw , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-22 (p126)
{ 0xf1d8 , 0xe080 , Operation : : ASRl , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-22 (p126)
{ 0xffc0 , 0xe0c0 , Operation : : ASRm , Decoder : : ASLR_LSLR_ROLR_ROXLRm } , // 4-22 (p126)
{ 0xf1d8 , 0xe108 , Operation : : LSLb , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-113 (p217)
{ 0xf1d8 , 0xe148 , Operation : : LSLw , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-113 (p217)
{ 0xf1d8 , 0xe188 , Operation : : LSLl , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-113 (p217)
{ 0xffc0 , 0xe3c0 , Operation : : LSLm , Decoder : : ASLR_LSLR_ROLR_ROXLRm } , // 4-113 (p217)
{ 0xf1d8 , 0xe008 , Operation : : LSRb , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-113 (p217)
{ 0xf1d8 , 0xe048 , Operation : : LSRw , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-113 (p217)
{ 0xf1d8 , 0xe088 , Operation : : LSRl , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-113 (p217)
{ 0xffc0 , 0xe2c0 , Operation : : LSRm , Decoder : : ASLR_LSLR_ROLR_ROXLRm } , // 4-113 (p217)
{ 0xf1d8 , 0xe118 , Operation : : ROLb , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-160 (p264)
{ 0xf1d8 , 0xe158 , Operation : : ROLw , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-160 (p264)
{ 0xf1d8 , 0xe198 , Operation : : ROLl , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-160 (p264)
{ 0xffc0 , 0xe7c0 , Operation : : ROLm , Decoder : : ASLR_LSLR_ROLR_ROXLRm } , // 4-160 (p264)
{ 0xf1d8 , 0xe018 , Operation : : RORb , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-160 (p264)
{ 0xf1d8 , 0xe058 , Operation : : RORw , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-160 (p264)
{ 0xf1d8 , 0xe098 , Operation : : RORl , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-160 (p264)
{ 0xffc0 , 0xe6c0 , Operation : : RORm , Decoder : : ASLR_LSLR_ROLR_ROXLRm } , // 4-160 (p264)
{ 0xf1d8 , 0xe110 , Operation : : ROXLb , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-163 (p267)
{ 0xf1d8 , 0xe150 , Operation : : ROXLw , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-163 (p267)
{ 0xf1d8 , 0xe190 , Operation : : ROXLl , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-163 (p267)
{ 0xffc0 , 0xe5c0 , Operation : : ROXLm , Decoder : : ASLR_LSLR_ROLR_ROXLRm } , // 4-163 (p267)
{ 0xf1d8 , 0xe010 , Operation : : ROXRb , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-163 (p267)
{ 0xf1d8 , 0xe050 , Operation : : ROXRw , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-163 (p267)
{ 0xf1d8 , 0xe090 , Operation : : ROXRl , Decoder : : ASLR_LSLR_ROLR_ROXLRr } , // 4-163 (p267)
{ 0xffc0 , 0xe4c0 , Operation : : ROXRm , Decoder : : ASLR_LSLR_ROLR_ROXLRm } , // 4-163 (p267)
2019-04-14 18:09:28 +00:00
{ 0xffc0 , 0x48c0 , Operation : : MOVEMtoMl , Decoder : : MOVEM } , // 4-128 (p232)
{ 0xffc0 , 0x4880 , Operation : : MOVEMtoMw , Decoder : : MOVEM } , // 4-128 (p232)
{ 0xffc0 , 0x4cc0 , Operation : : MOVEMtoRl , Decoder : : MOVEM } , // 4-128 (p232)
{ 0xffc0 , 0x4c80 , Operation : : MOVEMtoRw , Decoder : : MOVEM } , // 4-128 (p232)
2019-04-15 14:03:52 +00:00
2019-04-29 02:52:54 +00:00
{ 0xf1f8 , 0x0108 , Operation : : MOVEPtoRw , Decoder : : MOVEP } , // 4-133 (p237)
{ 0xf1f8 , 0x0148 , Operation : : MOVEPtoRl , Decoder : : MOVEP } , // 4-133 (p237)
{ 0xf1f8 , 0x0188 , Operation : : MOVEPtoMw , Decoder : : MOVEP } , // 4-133 (p237)
{ 0xf1f8 , 0x01c8 , Operation : : MOVEPtoMl , Decoder : : MOVEP } , // 4-133 (p237)
2019-04-15 14:03:52 +00:00
{ 0xffc0 , 0x4a00 , Operation : : TSTb , Decoder : : TST } , // 4-192 (p296)
{ 0xffc0 , 0x4a40 , Operation : : TSTw , Decoder : : TST } , // 4-192 (p296)
{ 0xffc0 , 0x4a80 , Operation : : TSTl , Decoder : : TST } , // 4-192 (p296)
2019-04-15 19:14:38 +00:00
2019-04-17 02:16:43 +00:00
{ 0xf1c0 , 0xc0c0 , Operation : : MULU , Decoder : : MULU_MULS } , // 4-139 (p243)
{ 0xf1c0 , 0xc1c0 , Operation : : MULS , Decoder : : MULU_MULS } , // 4-136 (p240)
2019-04-27 02:22:35 +00:00
{ 0xf1c0 , 0x80c0 , Operation : : DIVU , Decoder : : DIVU_DIVS } , // 4-97 (p201)
{ 0xf1c0 , 0x81c0 , Operation : : DIVS , Decoder : : DIVU_DIVS } , // 4-93 (p197)
2019-04-17 20:58:59 +00:00
{ 0xfff0 , 0x4e60 , Operation : : MOVEAl , Decoder : : MOVEUSP } , // 6-21 (p475)
2019-04-18 02:21:56 +00:00
{ 0xfff0 , 0x4e40 , Operation : : TRAP , Decoder : : TRAP } , // 4-188 (p292)
2019-04-28 19:52:58 +00:00
{ 0xffff , 0x4e76 , Operation : : TRAPV , Decoder : : TRAPV } , // 4-191 (p295)
2019-04-28 19:47:21 +00:00
{ 0xf1c0 , 0x4180 , Operation : : CHK , Decoder : : CHK } , // 4-69 (p173)
2019-04-19 00:50:58 +00:00
{ 0xffff , 0x4e77 , Operation : : RTE_RTR , Decoder : : RTE_RTR } , // 4-168 (p272) [RTR]
{ 0xffff , 0x4e73 , Operation : : RTE_RTR , Decoder : : RTE_RTR } , // 6-84 (p538) [RTE]
2019-04-19 03:46:01 +00:00
{ 0xffff , 0x4e71 , Operation : : None , Decoder : : NOP } , // 8-13 (p469)
2019-04-19 15:27:43 +00:00
{ 0xf1f8 , 0xc140 , Operation : : EXG , Decoder : : EXG } , // 4-105 (p209)
{ 0xf1f8 , 0xc148 , Operation : : EXG , Decoder : : EXG } , // 4-105 (p209)
{ 0xf1f8 , 0xc188 , Operation : : EXG , Decoder : : EXG } , // 4-105 (p209)
2019-04-25 22:22:19 +00:00
{ 0xfff8 , 0x4840 , Operation : : SWAP , Decoder : : EXT_SWAP } , // 4-185 (p289)
2019-04-24 21:38:59 +00:00
{ 0xffff , 0x027c , Operation : : ANDItoSR , Decoder : : EORI_ORI_ANDI_SR } ,
{ 0xffff , 0x023c , Operation : : ANDItoCCR , Decoder : : EORI_ORI_ANDI_SR } ,
{ 0xffff , 0x0a7c , Operation : : EORItoSR , Decoder : : EORI_ORI_ANDI_SR } ,
{ 0xffff , 0x0a3c , Operation : : EORItoCCR , Decoder : : EORI_ORI_ANDI_SR } ,
{ 0xffff , 0x007c , Operation : : ORItoSR , Decoder : : EORI_ORI_ANDI_SR } ,
{ 0xffff , 0x003c , Operation : : ORItoCCR , Decoder : : EORI_ORI_ANDI_SR } ,
2019-04-25 03:01:32 +00:00
{ 0xf1c0 , 0x0140 , Operation : : BCHGb , Decoder : : BCHG_BSET } , // 4-28 (p132)
{ 0xffc0 , 0x0840 , Operation : : BCHGb , Decoder : : BCHG_BSET } , // 4-29 (p133)
{ 0xf1c0 , 0x01c0 , Operation : : BSETb , Decoder : : BCHG_BSET } , // 4-57 (p161)
{ 0xffc0 , 0x08c0 , Operation : : BSETb , Decoder : : BCHG_BSET } , // 4-58 (p162)
2019-04-25 16:19:40 +00:00
{ 0xffc0 , 0x4ac0 , Operation : : TAS , Decoder : : TAS } , // 4-186 (p290)
2019-04-25 22:22:19 +00:00
{ 0xfff8 , 0x4880 , Operation : : EXTbtow , Decoder : : EXT_SWAP } , // 4-106 (p210)
{ 0xfff8 , 0x48c0 , Operation : : EXTwtol , Decoder : : EXT_SWAP } , // 4-106 (p210)
2019-04-28 21:12:31 +00:00
{ 0xfff8 , 0x4e50 , Operation : : LINK , Decoder : : LINK } , // 4-111 (p215)
{ 0xfff8 , 0x4e58 , Operation : : UNLINK , Decoder : : UNLINK } , // 4-194 (p298)
2019-04-29 23:30:00 +00:00
{ 0xffff , 0x4e72 , Operation : : STOP , Decoder : : STOP } , // 6-85 (p539)
2019-03-16 23:41:07 +00:00
} ;
std : : vector < size_t > micro_op_pointers ( 65536 , std : : numeric_limits < size_t > : : max ( ) ) ;
2019-03-17 01:47:46 +00:00
// The arbitrary_base is used so that the offsets returned by assemble_program into
// storage_.all_bus_steps_ can be retained and mapped into the final version of
// storage_.all_bus_steps_ at the end.
2019-07-25 14:14:36 +00:00
// BusStep arbitrary_base;
2019-03-17 01:47:46 +00:00
2019-03-21 03:21:02 +00:00
# define op(...) storage_.all_micro_ops_.emplace_back(__VA_ARGS__)
2019-07-25 14:14:36 +00:00
# define seq(...) assemble_program(__VA_ARGS__)
2019-04-04 01:27:11 +00:00
# define ea(n) &storage_.effective_address_[n].full
# define a(n) &storage_.address_[n].full
2019-03-21 03:21:02 +00:00
2019-04-12 19:48:29 +00:00
# define bw(x) (x)
# define l(x) (0x10000 | (x))
2019-04-12 02:31:17 +00:00
2019-03-16 23:41:07 +00:00
// Perform a linear search of the mappings above for this instruction.
2019-04-30 02:20:18 +00:00
for ( ssize_t instruction = 65535 ; instruction > = 0 ; - - instruction ) {
2019-04-18 20:34:48 +00:00
# ifndef NDEBUG
int hits = 0 ;
# endif
2019-03-16 23:41:07 +00:00
for ( const auto & mapping : mappings ) {
if ( ( instruction & mapping . mask ) = = mapping . value ) {
2019-03-22 23:25:53 +00:00
auto operation = mapping . operation ;
2019-03-17 02:36:09 +00:00
const auto micro_op_start = storage_ . all_micro_ops_ . size ( ) ;
2019-03-16 23:41:07 +00:00
2019-04-19 17:29:20 +00:00
// The following fields are used commonly enough to be worth pulling out here.
2019-04-06 14:41:19 +00:00
const int ea_register = instruction & 7 ;
const int ea_mode = ( instruction > > 3 ) & 7 ;
2019-04-19 17:29:20 +00:00
const int data_register = ( instruction > > 9 ) & 7 ;
const int op_mode = ( instruction > > 6 ) & 7 ;
const bool op_mode_high_bit = ! ! ( op_mode & 4 ) ;
// These are almost always true; they're non-const so that they can be corrected
// by the few deviations.
bool is_byte_access = ( op_mode & 3 ) = = 0 ;
bool is_long_word_access = ( op_mode & 3 ) = = 2 ;
2019-03-25 03:05:57 +00:00
2019-06-19 21:00:44 +00:00
// Temporary storage for the Program fields.
ProcessorBase : : Program program ;
2019-04-24 17:01:08 +00:00
# define dec(n) decrement_action(is_long_word_access, is_byte_access, n)
# define inc(n) increment_action(is_long_word_access, is_byte_access, n)
2019-04-20 02:41:06 +00:00
2019-03-16 23:41:07 +00:00
switch ( mapping . decoder ) {
2019-04-29 23:30:00 +00:00
case Decoder : : STOP : {
2019-07-25 02:02:50 +00:00
program . set_requires_supervisor ( true ) ;
2019-04-29 23:30:00 +00:00
op ( Action : : None , seq ( " n " ) ) ;
op ( Action : : PerformOperation ) ;
} break ;
2019-04-28 21:12:31 +00:00
case Decoder : : LINK : {
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , An , ea_register ) ;
2019-04-28 21:12:31 +00:00
op ( Action : : PerformOperation , seq ( " np nW+ nw np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
} break ;
case Decoder : : UNLINK : {
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , An , ea_register ) ;
2019-04-28 21:12:31 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " nRd+ nrd np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
op ( Action : : PerformOperation ) ;
} break ;
2019-04-25 16:19:40 +00:00
case Decoder : : TAS : {
const int mode = combined_mode ( ea_mode , ea_register ) ;
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , ea_mode , ea_register ) ;
2019-04-25 16:19:40 +00:00
switch ( mode ) {
default : continue ;
case Dn : // TAS Dn
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
case Ind : // TAS (An)
case PostInc : // TAS (An)+
op ( Action : : None , seq ( " nrd " , { a ( ea_register ) } , false ) ) ;
op ( Action : : PerformOperation , seq ( " tas np " , { a ( ea_register ) } , false ) ) ;
if ( mode = = PostInc ) {
op ( byte_inc ( ea_register ) | MicroOp : : DestinationMask ) ;
}
break ;
case PreDec : // TAS -(An)
op ( byte_dec ( ea_register ) | MicroOp : : DestinationMask , seq ( " n nrd " , { a ( ea_register ) } , false ) ) ;
op ( Action : : PerformOperation , seq ( " tas np " , { a ( ea_register ) } , false ) ) ;
break ;
case XXXl : // TAS (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-25 16:19:40 +00:00
case XXXw : // TAS (xxx).w
case d16An : // TAS (d16, An)
case d8AnXn : // TAS (d8, An, Xn)
2019-04-25 16:42:05 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask , seq ( " np nrd " , { ea ( 1 ) } , false ) ) ;
2019-04-25 16:19:40 +00:00
op ( Action : : PerformOperation , seq ( " tas np " , { ea ( 1 ) } , false ) ) ;
break ;
}
} break ;
2019-04-25 03:01:32 +00:00
case Decoder : : BCHG_BSET : {
const int mode = combined_mode ( ea_mode , ea_register ) ;
// Operations on a register are .l; all others are the default .b.
if ( ea_mode = = Dn ) {
operation = ( operation = = Operation : : BSETb ) ? Operation : : BSETl : Operation : : BCHGl ;
}
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , ea_mode , ea_register ) ;
2019-04-25 03:01:32 +00:00
if ( instruction & 0x100 ) {
// The bit is nominated by a register.
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , Dn , data_register ) ;
2019-04-25 03:01:32 +00:00
} else {
// The bit is nominated by a constant, that will be obtained right here.
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , Imm , 0 ) ;
2019-04-25 03:01:32 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
}
switch ( mode ) {
default : continue ;
case Dn : // [BCHG/BSET].l Dn, Dn
// Execution length depends on the selected bit, so allow flexible time for that.
op ( Action : : None , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " r " ) ) ;
break ;
case Ind : // [BCHG/BSET].b Dn, (An)
case PostInc : // [BCHG/BSET].b Dn, (An)+
op ( Action : : None , seq ( " nrd np " , { a ( ea_register ) } , false ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { a ( ea_register ) } , false ) ) ;
if ( mode = = PostInc ) {
op ( byte_inc ( ea_register ) | MicroOp : : DestinationMask ) ;
}
break ;
case PreDec : // [BCHG/BSET].b Dn, -(An)
op ( byte_dec ( ea_register ) | MicroOp : : DestinationMask , seq ( " n nrd np " , { a ( ea_register ) } , false ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { a ( ea_register ) } , false ) ) ;
break ;
case XXXl : // [BCHG/BSET].b Dn, (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-25 03:01:32 +00:00
case XXXw : // [BCHG/BSET].b Dn, (xxx).w
case d16An : // [BCHG/BSET].b Dn, (d16, An)
case d8AnXn : // [BCHG/BSET].b Dn, (d8, An, Xn)
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask , seq ( pseq ( " np nrd np " , mode ) , { ea ( 1 ) } , false ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { ea ( 1 ) } , false ) ) ;
break ;
}
} break ;
2019-04-24 21:38:59 +00:00
case Decoder : : EORI_ORI_ANDI_SR : {
// The source used here is always the high word of the prefetch queue.
2019-07-25 02:02:50 +00:00
program . set_requires_supervisor ( ! ! ( instruction & 0x40 ) ) ;
2019-04-24 21:38:59 +00:00
op ( Action : : None , seq ( " np nn nn " ) ) ;
op ( Action : : PerformOperation , seq ( " np np " ) ) ;
} break ;
2019-04-25 22:22:19 +00:00
case Decoder : : EXT_SWAP : {
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , Dn , ea_register ) ;
2019-04-24 17:06:12 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
2019-04-19 15:27:43 +00:00
} break ;
case Decoder : : EXG : {
switch ( ( instruction > > 3 ) & 31 ) {
default : continue ;
case 0x08 :
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , Dn , data_register ) ;
program . set_destination ( storage_ , Dn , ea_register ) ;
2019-04-19 15:27:43 +00:00
break ;
case 0x09 :
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , An , data_register ) ;
program . set_destination ( storage_ , An , ea_register ) ;
2019-04-19 15:27:43 +00:00
break ;
case 0x11 :
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , Dn , data_register ) ;
program . set_destination ( storage_ , An , ea_register ) ;
2019-04-19 15:27:43 +00:00
break ;
}
2019-06-24 02:21:25 +00:00
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
2019-04-19 15:27:43 +00:00
} break ;
2019-04-19 03:46:01 +00:00
case Decoder : : NOP : {
op ( Action : : None , seq ( " np " ) ) ;
} break ;
2019-04-19 00:50:58 +00:00
case Decoder : : RTE_RTR : {
2019-07-25 02:02:50 +00:00
program . set_requires_supervisor ( instruction = = 0x4e73 ) ;
2019-04-19 00:50:58 +00:00
2019-12-26 00:49:49 +00:00
// The targets of the nR nr nr below are reset to the program counter elsewhere;
// look for the comment "relink the RTE and RTR bus steps". It is currently not
// explicitly tested that these bus steps are not shared with a non-RTE/RTR operation,
// just assumed because the repetition of nr is fairly silly. A more explicit soution
// might be preferable in the future.
2019-04-19 00:50:58 +00:00
op ( Action : : PrepareRTE_RTR , seq ( " nR nr nr " , { & storage_ . precomputed_addresses_ [ 0 ] , & storage_ . precomputed_addresses_ [ 1 ] , & storage_ . precomputed_addresses_ [ 2 ] } ) ) ;
op ( Action : : PerformOperation , seq ( " np np " ) ) ;
op ( ) ;
} break ;
2019-04-18 20:34:48 +00:00
case Decoder : : AND_OR_EOR : {
2019-04-19 17:29:20 +00:00
const bool to_ea = op_mode_high_bit ;
2019-04-18 20:34:48 +00:00
const bool is_eor = ( instruction > > 12 ) = = 0xb ;
// Weed out illegal operation modes.
if ( op_mode = = 7 ) continue ;
const int mode = combined_mode ( ea_mode , ea_register ) ;
if ( to_ea ) {
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , ea_mode , ea_register ) ;
program . set_source ( storage_ , Dn , data_register ) ;
2019-04-18 20:34:48 +00:00
// Only EOR takes Dn as a destination effective address.
if ( ! is_eor & & mode = = Dn ) continue ;
switch ( is_long_word_access ? l ( mode ) : bw ( mode ) ) {
default : continue ;
case bw ( Dn ) : // EOR.bw Dn, Dn
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
case l ( Dn ) : // EOR.l Dn, Dn
op ( Action : : PerformOperation , seq ( " np nn " ) ) ;
break ;
case bw ( Ind ) : // [AND/OR/EOR].bw Dn, (An)
case bw ( PostInc ) : // [AND/OR/EOR].bw Dn, (An)+
2019-05-29 18:37:15 +00:00
op ( Action : : None , seq ( " nrd " , { a ( ea_register ) } , ! is_byte_access ) ) ;
2019-04-18 20:34:48 +00:00
op ( Action : : PerformOperation , seq ( " np nw " , { a ( ea_register ) } , ! is_byte_access ) ) ;
if ( mode = = PostInc ) {
2019-04-24 17:01:08 +00:00
op ( inc ( ea_register ) | MicroOp : : DestinationMask ) ;
2019-04-18 20:34:48 +00:00
}
break ;
case bw ( PreDec ) : // [AND/OR/EOR].bw Dn, -(An)
2019-11-09 16:25:23 +00:00
op ( dec ( ea_register ) | MicroOp : : DestinationMask , seq ( " n nrd " , { a ( ea_register ) } , ! is_byte_access ) ) ;
2019-04-18 20:34:48 +00:00
op ( Action : : PerformOperation , seq ( " np nw " , { a ( ea_register ) } , ! is_byte_access ) ) ;
break ;
case l ( PreDec ) : // [AND/OR/EOR].l Dn, -(An)
op ( int ( Action : : Decrement4 ) | MicroOp : : DestinationMask , seq ( " n " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-25 18:19:13 +00:00
case l ( Ind ) : // [AND/OR/EOR].l Dn, (An)
case l ( PostInc ) : // [AND/OR/EOR].l Dn, (An)+
2019-04-18 20:34:48 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " nRd+ nrd " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " np nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
if ( mode = = PostInc ) {
op ( int ( Action : : Increment4 ) | MicroOp : : DestinationMask ) ;
}
break ;
case bw ( XXXl ) : // [AND/OR/EOR].bw Dn, (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-18 20:34:48 +00:00
case bw ( XXXw ) : // [AND/OR/EOR].bw Dn, (xxx).w
2019-04-30 02:37:23 +00:00
case bw ( d16An ) : // [AND/OR/EOR].bw Dn, (d16, An)
case bw ( d8AnXn ) : // [AND/OR/EOR].bw Dn, (d8, An, Xn)
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask , seq ( pseq ( " np nrd " , mode ) , { ea ( 1 ) } , ! is_byte_access ) ) ;
2019-04-18 20:34:48 +00:00
op ( Action : : PerformOperation , seq ( " np nw " , { ea ( 1 ) } , ! is_byte_access ) ) ;
break ;
case l ( XXXl ) : // [AND/OR/EOR].l Dn, (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-18 20:34:48 +00:00
case l ( XXXw ) : // [AND/OR/EOR].l Dn, (xxx).w
2019-04-30 02:37:23 +00:00
case l ( d16An ) : // [AND/OR/EOR].l Dn, (d16, An)
case l ( d8AnXn ) : // [AND/OR/EOR].l Dn, (d8, An, Xn)
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask , seq ( pseq ( " np nRd+ nrd " , mode ) , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-18 20:34:48 +00:00
op ( Action : : PerformOperation , seq ( " np nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
}
} else {
// EORs can be to EA only.
if ( is_eor ) continue ;
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , ea_mode , ea_register ) ;
program . set_destination ( storage_ , Dn , data_register ) ;
2019-04-18 20:34:48 +00:00
2019-04-25 18:19:13 +00:00
switch ( is_long_word_access ? l ( mode ) : bw ( mode ) ) {
2019-04-18 20:34:48 +00:00
default : continue ;
case bw ( Dn ) : // [AND/OR].bw Dn, Dn
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
case l ( Dn ) : // [AND/OR].l Dn, Dn
op ( Action : : PerformOperation , seq ( " np nn " ) ) ;
break ;
case bw ( Ind ) : // [AND/OR].bw (An), Dn
case bw ( PostInc ) : // [AND/OR].bw (An)+, Dn
op ( Action : : None , seq ( " nr " , { a ( ea_register ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " np " ) ) ;
if ( mode = = PostInc ) {
2019-04-24 17:01:08 +00:00
op ( inc ( ea_register ) | MicroOp : : SourceMask ) ;
2019-04-18 20:34:48 +00:00
}
break ;
case bw ( PreDec ) : // [AND/OR].bw -(An), Dn
2019-04-24 17:01:08 +00:00
op ( dec ( ea_register ) | MicroOp : : SourceMask , seq ( " n nr " , { a ( ea_register ) } , ! is_byte_access ) ) ;
2019-04-18 20:34:48 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
case l ( PreDec ) : // [AND/OR].l -(An), Dn
op ( int ( Action : : Decrement4 ) | MicroOp : : SourceMask , seq ( " n " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-18 20:34:48 +00:00
case l ( Ind ) : // [AND/OR].l (An), Dn,
case l ( PostInc ) : // [AND/OR].l (An)+, Dn
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask , seq ( " nR+ nr " , { ea ( 0 ) , ea ( 0 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
if ( mode = = PostInc ) {
op ( int ( Action : : Increment4 ) | MicroOp : : SourceMask ) ;
}
break ;
2019-04-30 02:37:23 +00:00
case bw ( XXXl ) : // [AND/OR].bw (xxx).l, Dn
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-30 02:37:23 +00:00
case bw ( XXXw ) : // [AND/OR].bw (xxx).w, Dn
2019-04-18 20:34:48 +00:00
case bw ( d16An ) : // [AND/OR].bw (d16, An), Dn
case bw ( d16PC ) : // [AND/OR].bw (d16, PC), Dn
case bw ( d8AnXn ) : // [AND/OR].bw (d8, An, Xn), Dn
case bw ( d8PCXn ) : // [AND/OR].bw (d8, PX, Xn), Dn
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( pseq ( " np nr " , mode ) , { ea ( 0 ) } , ! is_byte_access ) ) ;
2019-04-18 20:34:48 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
2019-04-30 02:37:23 +00:00
case l ( XXXl ) : // [AND/OR].bw (xxx).l, Dn
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-30 02:37:23 +00:00
case l ( XXXw ) : // [AND/OR].bw (xxx).w, Dn
2019-04-18 20:34:48 +00:00
case l ( d16An ) : // [AND/OR].l (d16, An), Dn
case l ( d16PC ) : // [AND/OR].l (d16, PC), Dn
case l ( d8AnXn ) : // [AND/OR].l (d8, An, Xn), Dn
case l ( d8PCXn ) : // [AND/OR].l (d8, PX, Xn), Dn
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( pseq ( " np nR+ nr " , mode ) , { ea ( 0 ) , ea ( 0 ) } ) ) ;
2019-04-18 20:34:48 +00:00
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
break ;
case bw ( Imm ) : // [AND/OR].bw #, Dn
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
case l ( Imm ) : // [AND/OR].l #, Dn
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " np nn " ) ) ;
break ;
}
}
} break ;
2019-04-27 02:22:35 +00:00
case Decoder : : DIVU_DIVS : {
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , ea_mode , ea_register ) ;
program . set_destination ( storage_ , Dn , data_register ) ;
2019-04-27 02:22:35 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
switch ( mode ) {
default : continue ;
case Dn : // [DIVU/DIVS] Dn, Dn
op ( Action : : PerformOperation , seq ( " r " ) ) ;
op ( Action : : None , seq ( " np " ) ) ;
break ;
case Ind : // [DIVU/DIVS] (An), Dn
case PostInc : // [DIVU/DIVS] (An)+, Dn
op ( Action : : None , seq ( " nr " , { a ( ea_register ) } ) ) ;
op ( Action : : PerformOperation , seq ( " r np " ) ) ;
if ( mode = = PostInc ) {
op ( int ( Action : : Increment2 ) | MicroOp : : SourceMask ) ;
}
break ;
case PreDec : // [DIVU/DIVS] -(An), Dn
op ( int ( Action : : Decrement2 ) | MicroOp : : SourceMask , seq ( " nr " , { a ( ea_register ) } ) ) ;
op ( Action : : PerformOperation , seq ( " r np " ) ) ;
break ;
case XXXl : // [DIVU/DIVS] (XXX).l, Dn
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-27 02:22:35 +00:00
case XXXw : // [DIVU/DIVS] (XXX).w, Dn
case d16An : // [DIVU/DIVS] (d16, An), Dn
case d16PC : // [DIVU/DIVS] (d16, PC), Dn
case d8AnXn : // [DIVU/DIVS] (d8, An, Xn), Dn
case d8PCXn : // [DIVU/DIVS] (d8, PC, Xn), Dn
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( " np nr " , { ea ( 0 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " r np " ) ) ;
break ;
case Imm : // [DIVU/DIVS] #, Dn
// DEVIATION FROM YACHT.TXT. It shows an additional np, which is incorrect.
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " r np " ) ) ;
break ;
}
} break ;
2019-04-17 02:16:43 +00:00
case Decoder : : MULU_MULS : {
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , ea_mode , ea_register ) ;
program . set_destination ( storage_ , Dn , data_register ) ;
2019-04-17 02:16:43 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
switch ( mode ) {
default : continue ;
2019-04-27 02:22:35 +00:00
case Dn : // [MULU/MULS] Dn, Dn
2019-04-17 02:16:43 +00:00
op ( Action : : None , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " r " ) ) ;
break ;
2019-04-27 02:22:35 +00:00
case Ind : // [MULU/MULS] (An), Dn
case PostInc : // [MULU/MULS] (An)+, Dn
2019-04-17 02:16:43 +00:00
op ( Action : : None , seq ( " nr np " , { a ( ea_register ) } ) ) ;
op ( Action : : PerformOperation , seq ( " r " ) ) ;
if ( mode = = PostInc ) {
op ( int ( Action : : Increment2 ) | MicroOp : : SourceMask ) ;
}
break ;
2019-04-27 02:22:35 +00:00
case PreDec : // [MULU/MULS] -(An), Dn
2019-04-17 02:16:43 +00:00
op ( int ( Action : : Decrement2 ) | MicroOp : : SourceMask , seq ( " n nr np " , { a ( ea_register ) } ) ) ;
op ( Action : : PerformOperation , seq ( " r " ) ) ;
break ;
2019-04-27 02:22:35 +00:00
case XXXl : // [MULU/MULS] (XXX).l, Dn
2019-04-17 02:16:43 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-27 02:22:35 +00:00
case XXXw : // [MULU/MULS] (XXX).w, Dn
case d16An : // [MULU/MULS] (d16, An), Dn
case d16PC : // [MULU/MULS] (d16, PC), Dn
case d8AnXn : // [MULU/MULS] (d8, An, Xn), Dn
case d8PCXn : // [MULU/MULS] (d8, PX, Xn), Dn
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( pseq ( " n np nr np " , mode ) , { ea ( 0 ) } ) ) ;
2019-04-17 02:16:43 +00:00
op ( Action : : PerformOperation , seq ( " r " ) ) ;
break ;
2019-04-27 02:22:35 +00:00
case Imm : // [MULU/MULS] #, Dn
// DEVIATION FROM YACHT.TXT. It shows an additional np, which is incorrect.
2019-04-17 19:15:48 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
2019-04-17 02:16:43 +00:00
op ( Action : : PerformOperation , seq ( " r " ) ) ;
break ;
}
} break ;
2019-04-16 23:50:10 +00:00
case Decoder : : EORI_ORI_ANDI_SUBI_ADDI : {
const int mode = combined_mode ( ea_mode , ea_register ) ;
// Source is always something cribbed from the instruction stream;
// destination is going to be in the write address unit.
2019-07-24 22:22:44 +00:00
program . set_source ( storage_ , Imm , 0 ) ;
program . set_destination ( storage_ , mode , ea_register ) ;
2019-04-16 23:50:10 +00:00
switch ( is_long_word_access ? l ( mode ) : bw ( mode ) ) {
default : continue ;
2019-04-17 01:29:37 +00:00
case bw ( Dn ) : // [EORI/ORI/ANDI/SUBI/ADDI].bw #, Dn
2019-04-24 01:23:20 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
2019-04-16 23:50:10 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-24 01:23:20 +00:00
case l ( Dn ) : // [EORI/ORI/ANDI/SUBI/ADDI].l #, Dn
2019-04-16 23:50:10 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2019-04-24 01:23:20 +00:00
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np nn " ) ) ;
2019-04-16 23:50:10 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-17 01:29:37 +00:00
case bw ( Ind ) : // [EORI/ORI/ANDI/SUBI/ADDI].bw #, (An)
case bw ( PostInc ) : // [EORI/ORI/ANDI/SUBI/ADDI].bw #, (An)+
2019-04-16 23:50:10 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np nrd np " , { a ( ea_register ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { a ( ea_register ) } , ! is_byte_access ) ) ;
if ( mode = = PostInc ) {
2019-04-24 17:01:08 +00:00
op ( inc ( ea_register ) | MicroOp : : DestinationMask ) ;
2019-04-16 23:50:10 +00:00
}
break ;
2019-04-17 01:29:37 +00:00
case l ( Ind ) : // [EORI/ORI/ANDI/SUBI/ADDI].l #, (An)
case l ( PostInc ) : // [EORI/ORI/ANDI/SUBI/ADDI].l #, (An)+
2019-04-16 23:50:10 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np nRd+ nrd np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
if ( mode = = PostInc ) {
op ( int ( Action : : Increment4 ) | MicroOp : : DestinationMask ) ;
}
break ;
2019-04-17 01:29:37 +00:00
case bw ( PreDec ) : // [EORI/ORI/ANDI/SUBI/ADDI].bw #, -(An)
2019-04-24 17:01:08 +00:00
op ( dec ( ea_register ) | MicroOp : : DestinationMask ) ;
2019-04-16 23:50:10 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np n nrd np " , { a ( ea_register ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { a ( ea_register ) } , ! is_byte_access ) ) ;
break ;
2019-04-17 01:29:37 +00:00
case l ( PreDec ) : // [EORI/ORI/ANDI/SUBI/ADDI].l #, -(An)
2019-04-16 23:50:10 +00:00
op ( int ( Action : : Decrement4 ) | MicroOp : : DestinationMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np n nRd+ nrd np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
2019-04-30 02:37:23 +00:00
case bw ( XXXw ) : // [EORI/ORI/ANDI/SUBI/ADDI].bw #, (xxx).w
2019-04-17 01:29:37 +00:00
case bw ( d8AnXn ) : // [EORI/ORI/ANDI/SUBI/ADDI].bw #, (d8, An, Xn)
case bw ( d16An ) : // [EORI/ORI/ANDI/SUBI/ADDI].bw #, (d16, An)
2019-04-16 23:50:10 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask ,
2019-04-16 23:50:10 +00:00
seq ( pseq ( " np nrd np " , mode ) , { ea ( 1 ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { ea ( 1 ) } , ! is_byte_access ) ) ;
break ;
2019-04-30 02:37:23 +00:00
case l ( XXXw ) : // [EORI/ORI/ANDI/SUBI/ADDI].l #, (xxx).w
2019-04-17 01:34:16 +00:00
case l ( d8AnXn ) : // [EORI/ORI/ANDI/SUBI/ADDI].l #, (d8, An, Xn)
case l ( d16An ) : // [EORI/ORI/ANDI/SUBI/ADDI].l #, (d16, An)
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask ,
2019-04-17 01:34:16 +00:00
seq ( pseq ( " np nRd+ nrd np " , mode ) , { ea ( 1 ) , ea ( 1 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
2019-04-17 01:29:37 +00:00
case bw ( XXXl ) : // [EORI/ORI/ANDI/SUBI/ADDI].bw #, (xxx).l
2019-04-16 23:50:10 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask ,
seq ( " np nrd np " , { ea ( 1 ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { ea ( 1 ) } , ! is_byte_access ) ) ;
break ;
2019-04-17 01:34:16 +00:00
case l ( XXXl ) : // [EORI/ORI/ANDI/SUBI/ADDI].l #, (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask ,
seq ( " np nRd+ nrd np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
2019-04-16 23:50:10 +00:00
}
} break ;
case Decoder : : ADD_SUB : {
2019-04-03 01:50:58 +00:00
// ADD and SUB definitely always involve a data register and an arbitrary addressing mode;
// which direction they operate in depends on bit 8.
const bool reverse_source_destination = ! ( instruction & 256 ) ;
2019-04-06 14:41:19 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
2019-04-03 01:50:58 +00:00
if ( reverse_source_destination ) {
2019-07-24 22:22:44 +00:00
program . set_destination ( storage_ , Dn , data_register ) ;
program . set_source ( storage_ , Imm , ea_register ) ;
2019-04-03 01:50:58 +00:00
// Perform [ADD/SUB].blw <ea>, Dn
2019-04-12 17:45:28 +00:00
switch ( is_long_word_access ? l ( mode ) : bw ( mode ) ) {
2019-04-03 01:50:58 +00:00
default : continue ;
2019-04-12 02:31:17 +00:00
case bw ( Dn ) : // ADD/SUB.bw Dn, Dn
2019-07-24 22:22:44 +00:00
program . set_source ( storage_ , Dn , ea_register ) ;
// program.source = &storage_.data_[ea_register];
2019-04-03 01:50:58 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
2019-04-12 02:31:17 +00:00
case l ( Dn ) : // ADD/SUB.l Dn, Dn
2019-07-24 22:22:44 +00:00
program . set_source ( storage_ , Dn , ea_register ) ;
// program.source = &storage_.data_[ea_register];
2019-04-03 01:50:58 +00:00
op ( Action : : PerformOperation , seq ( " np nn " ) ) ;
break ;
2019-04-12 02:31:17 +00:00
case bw ( An ) : // ADD/SUB.bw An, Dn
2019-04-26 02:54:58 +00:00
// Address registers can't provide single bytes.
if ( is_byte_access ) continue ;
2019-07-24 22:22:44 +00:00
program . set_source ( storage_ , An , ea_register ) ;
// program.source = &storage_.address_[ea_register];
2019-04-03 01:50:58 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
2019-04-12 02:31:17 +00:00
case l ( An ) : // ADD/SUB.l An, Dn
2019-07-24 22:22:44 +00:00
program . set_source ( storage_ , An , ea_register ) ;
// program.source = &storage_.address_[ea_register];
2019-04-03 01:50:58 +00:00
op ( Action : : PerformOperation , seq ( " np nn " ) ) ;
break ;
2019-04-12 02:31:17 +00:00
case bw ( Ind ) : // ADD/SUB.bw (An), Dn
case bw ( PostInc ) : // ADD/SUB.bw (An)+, Dn
2019-04-06 14:41:19 +00:00
op ( Action : : None , seq ( " nr np " , { a ( ea_register ) } , ! is_byte_access ) ) ;
2019-04-12 02:31:17 +00:00
if ( ea_mode = = PostInc ) {
2019-04-24 17:01:08 +00:00
op ( inc ( ea_register ) | MicroOp : : SourceMask ) ;
2019-04-03 01:50:58 +00:00
}
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 02:31:17 +00:00
case l ( Ind ) : // ADD/SUB.l (An), Dn
case l ( PostInc ) : // ADD/SUB.l (An)+, Dn
2019-04-04 01:27:11 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask ,
seq ( " nR+ nr np n " , { ea ( 0 ) , ea ( 0 ) } ) ) ;
2019-04-12 17:45:28 +00:00
if ( mode = = PostInc ) {
2019-04-03 01:50:58 +00:00
op ( int ( Action : : Increment4 ) | MicroOp : : SourceMask ) ;
}
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 02:31:17 +00:00
case bw ( PreDec ) : // ADD/SUB.bw -(An), Dn
2019-04-24 17:01:08 +00:00
op ( dec ( ea_register ) | MicroOp : : SourceMask ,
2019-04-06 14:41:19 +00:00
seq ( " n nr np " , { a ( ea_register ) } , ! is_byte_access ) ) ;
2019-04-03 01:50:58 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 02:31:17 +00:00
case l ( PreDec ) : // ADD/SUB.l -(An), Dn
2019-04-04 01:27:11 +00:00
op ( int ( Action : : Decrement4 ) | MicroOp : : SourceMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask ,
seq ( " n nR+ nr np n " , { ea ( 0 ) , ea ( 0 ) } ) ) ;
2019-04-03 01:50:58 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 02:31:17 +00:00
case bw ( XXXl ) : // ADD/SUB.bw (xxx).l, Dn
2019-04-03 01:50:58 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-12 02:31:17 +00:00
case bw ( XXXw ) : // ADD/SUB.bw (xxx).w, Dn
case bw ( d16PC ) : // ADD/SUB.bw (d16, PC), Dn
case bw ( d8PCXn ) : // ADD/SUB.bw (d8, PC, Xn), Dn
case bw ( d16An ) : // ADD/SUB.bw (d16, An), Dn
case bw ( d8AnXn ) : // ADD/SUB.bw (d8, An, Xn), Dn
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask ,
2019-04-04 01:27:11 +00:00
seq ( pseq ( " np nr np " , mode ) , { ea ( 0 ) } , ! is_byte_access ) ) ;
2019-04-03 01:50:58 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-30 02:37:23 +00:00
case l ( XXXl ) : // ADD/SUB.l (xxx).l, Dn
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-30 02:37:23 +00:00
case l ( XXXw ) : // ADD/SUB.l (xxx).w, Dn
2019-04-12 02:31:17 +00:00
case l ( d16PC ) : // ADD/SUB.l (d16, PC), Dn
case l ( d8PCXn ) : // ADD/SUB.l (d8, PC, Xn), Dn
case l ( d16An ) : // ADD/SUB.l (d16, An), Dn
case l ( d8AnXn ) : // ADD/SUB.l (d8, An, Xn), Dn
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask ,
2019-04-04 01:27:11 +00:00
seq ( pseq ( " np nR+ nr np n " , mode ) , { ea ( 0 ) , ea ( 0 ) } ) ) ;
2019-04-03 01:50:58 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 02:31:17 +00:00
case bw ( Imm ) : // ADD/SUB.bw #, Dn
2019-04-03 01:50:58 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 02:31:17 +00:00
case l ( Imm ) : // ADD/SUB.l #, Dn
2019-04-03 01:50:58 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2019-04-04 02:39:01 +00:00
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np nn " ) ) ;
2019-04-03 01:50:58 +00:00
op ( Action : : PerformOperation ) ;
break ;
}
} else {
2019-04-06 14:41:19 +00:00
const auto destination_register = ea_register ;
2019-07-24 22:22:44 +00:00
program . set_destination ( storage_ , Ind , destination_register ) ;
program . set_source ( storage_ , Dn , data_register ) ;
2019-04-03 01:50:58 +00:00
// Perform [ADD/SUB].blw Dn, <ea>
2019-04-12 17:45:28 +00:00
switch ( is_long_word_access ? l ( mode ) : bw ( mode ) ) {
2019-04-03 01:50:58 +00:00
default : continue ;
2019-04-12 02:31:17 +00:00
case bw ( Ind ) : // ADD/SUB.bw Dn, (An)
case bw ( PostInc ) : // ADD/SUB.bw Dn, (An)+
2019-04-04 01:41:59 +00:00
op ( Action : : None , seq ( " nrd np " , { a ( destination_register ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { a ( destination_register ) } , ! is_byte_access ) ) ;
2019-04-12 02:31:17 +00:00
if ( ea_mode = = PostInc ) {
2019-04-24 17:01:08 +00:00
op ( inc ( destination_register ) | MicroOp : : DestinationMask ) ;
2019-04-03 01:50:58 +00:00
}
break ;
2019-04-12 02:31:17 +00:00
case l ( Ind ) : // ADD/SUB.l Dn, (An)
case l ( PostInc ) : // ADD/SUB.l Dn, (An)+
2019-04-04 01:41:59 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " nRd+ nrd np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-04 01:27:11 +00:00
op ( Action : : PerformOperation , seq ( " nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-12 02:31:17 +00:00
if ( ea_mode = = PostInc ) {
2019-04-04 01:27:11 +00:00
op ( int ( Action : : Increment4 ) | MicroOp : : DestinationMask ) ;
}
break ;
2019-04-03 01:50:58 +00:00
2019-04-12 02:31:17 +00:00
case bw ( PreDec ) : // ADD/SUB.bw Dn, -(An)
2019-04-24 17:01:08 +00:00
op ( dec ( destination_register ) | MicroOp : : DestinationMask ,
2019-04-04 01:41:59 +00:00
seq ( " n nrd np " , { a ( destination_register ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { a ( destination_register ) } , ! is_byte_access ) ) ;
break ;
2019-04-03 01:50:58 +00:00
2019-04-12 02:31:17 +00:00
case l ( PreDec ) : // ADD/SUB.l Dn, -(An)
2019-04-04 01:41:59 +00:00
op ( int ( Action : : Decrement4 ) | MicroOp : : DestinationMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask ,
seq ( " n nRd+ nrd np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
op ( Action : : PerformOperation ,
seq ( " nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
2019-04-03 01:50:58 +00:00
2019-04-30 02:37:23 +00:00
case bw ( XXXl ) : // ADD/SUB.bw Dn, (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-30 02:37:23 +00:00
case bw ( XXXw ) : // ADD/SUB.bw Dn, (xxx).w
2019-04-12 02:31:17 +00:00
case bw ( d16An ) : // ADD/SUB.bw (d16, An), Dn
case bw ( d8AnXn ) : // ADD/SUB.bw (d8, An, Xn), Dn
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask ,
2019-04-04 02:39:01 +00:00
seq ( pseq ( " np nrd np " , mode ) , { ea ( 1 ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { ea ( 1 ) } , ! is_byte_access ) ) ;
break ;
2019-04-30 02:37:23 +00:00
case l ( XXXl ) : // ADD/SUB.l Dn, (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-30 02:37:23 +00:00
case l ( XXXw ) : // ADD/SUB.l Dn, (xxx).w
2019-04-12 02:31:17 +00:00
case l ( d16An ) : // ADD/SUB.l (d16, An), Dn
case l ( d8AnXn ) : // ADD/SUB.l (d8, An, Xn), Dn
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask ,
2019-04-04 02:39:01 +00:00
seq ( pseq ( " np nRd+ nrd np " , mode ) , { ea ( 1 ) , ea ( 1 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
}
}
} break ;
2019-04-03 01:50:58 +00:00
2019-04-16 23:50:10 +00:00
case Decoder : : ADDA_SUBA : {
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , 1 , data_register ) ;
program . set_source ( storage_ , ea_mode , ea_register ) ;
2019-04-03 01:50:58 +00:00
2019-04-06 14:41:19 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
2019-04-19 17:29:20 +00:00
is_long_word_access = op_mode_high_bit ;
2019-04-04 02:39:01 +00:00
2019-04-12 17:45:28 +00:00
switch ( is_long_word_access ? l ( mode ) : bw ( mode ) ) {
2019-04-04 02:39:01 +00:00
default : continue ;
2019-04-12 02:31:17 +00:00
case bw ( Dn ) : // ADDA/SUBA.w Dn, An
case bw ( An ) : // ADDA/SUBA.w An, An
case l ( Dn ) : // ADDA/SUBA.l Dn, An
case l ( An ) : // ADDA/SUBA.l An, An
2019-04-04 02:39:01 +00:00
op ( Action : : PerformOperation , seq ( " np nn " ) ) ;
break ;
2019-04-12 02:31:17 +00:00
case bw ( Ind ) : // ADDA/SUBA.w (An), An
case bw ( PostInc ) : // ADDA/SUBA.w (An)+, An
2019-04-06 14:41:19 +00:00
op ( Action : : None , seq ( " nr np nn " , { a ( ea_register ) } ) ) ;
2019-04-12 02:31:17 +00:00
if ( ea_mode = = PostInc ) {
2019-04-04 02:39:01 +00:00
op ( int ( Action : : Increment2 ) | MicroOp : : SourceMask ) ;
}
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 02:31:17 +00:00
case l ( Ind ) : // ADDA/SUBA.l (An), An
case l ( PostInc ) : // ADDA/SUBA.l (An)+, An
2019-04-04 02:39:01 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask , seq ( " nR+ nr np n " , { ea ( 0 ) , ea ( 0 ) } ) ) ;
2019-04-12 17:45:28 +00:00
if ( mode = = PostInc ) {
2019-04-04 02:39:01 +00:00
op ( int ( Action : : Increment4 ) | MicroOp : : SourceMask ) ;
}
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 02:31:17 +00:00
case bw ( PreDec ) : // ADDA/SUBA.w -(An), An
2019-04-04 02:39:01 +00:00
op ( int ( Action : : Decrement2 ) | MicroOp : : SourceMask ) ;
2019-04-06 14:41:19 +00:00
op ( Action : : None , seq ( " n nr np nn " , { a ( ea_register ) } ) ) ;
2019-04-04 02:39:01 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 02:31:17 +00:00
case l ( PreDec ) : // ADDA/SUBA.l -(An), An
2019-04-04 02:39:01 +00:00
op ( int ( Action : : Decrement4 ) | MicroOp : : SourceMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask , seq ( " n nR+ nr np n " , { ea ( 0 ) , ea ( 0 ) } ) ) ;
op ( Action : : PerformOperation ) ;
break ;
2019-04-30 02:37:23 +00:00
case bw ( XXXl ) : // ADDA/SUBA.w (xxx).l, An
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-30 02:37:23 +00:00
case bw ( XXXw ) : // ADDA/SUBA.w (xxx).w, An
2019-04-12 02:31:17 +00:00
case bw ( d16An ) : // ADDA/SUBA.w (d16, An), An
case bw ( d8AnXn ) : // ADDA/SUBA.w (d8, An, Xn), An
2019-04-27 21:22:26 +00:00
case bw ( d16PC ) : // ADDA/SUBA.w (d16, PC), An
case bw ( d8PCXn ) : // ADDA/SUBA.w (d8, PC, Xn), An
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask ,
2019-04-20 03:02:41 +00:00
seq ( pseq ( " np nr np nn " , mode ) , { ea ( 0 ) } ) ) ;
2019-04-04 02:39:01 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-30 02:37:23 +00:00
case l ( XXXl ) : // ADDA/SUBA.l (xxx).l, An
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-30 02:37:23 +00:00
case l ( XXXw ) : // ADDA/SUBA.l (xxx).w, An
2019-04-12 02:31:17 +00:00
case l ( d16An ) : // ADDA/SUBA.l (d16, An), An
case l ( d8AnXn ) : // ADDA/SUBA.l (d8, An, Xn), An
2019-04-27 21:22:26 +00:00
case l ( d16PC ) : // ADDA/SUBA.l (d16, PC), An
case l ( d8PCXn ) : // ADDA/SUBA.l (d8, PC, Xn), An
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask ,
2019-04-20 03:02:41 +00:00
seq ( pseq ( " np nR+ nr np n " , mode ) , { ea ( 0 ) , ea ( 0 ) } ) ) ;
2019-04-04 02:39:01 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 02:31:17 +00:00
case bw ( Imm ) : // ADDA/SUBA.w #, An
2019-04-04 02:39:01 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np nn " ) ) ;
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 02:31:17 +00:00
case l ( Imm ) : // ADDA/SUBA.l #, Dn
2019-04-04 02:39:01 +00:00
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np nn " ) ) ;
op ( Action : : PerformOperation ) ;
break ;
2019-04-03 01:50:58 +00:00
}
} break ;
2019-04-16 23:50:10 +00:00
case Decoder : : ADDQ_SUBQ : {
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , ea_mode , ea_register ) ;
2019-04-16 15:19:45 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
2019-04-24 13:59:54 +00:00
// If the destination is an address register then byte mode isn't allowed, and
// flags shouldn't be affected (so, a different operation is used).
if ( mode = = An ) {
if ( is_byte_access ) continue ;
switch ( operation ) {
default : break ;
case Operation : : ADDQl : // TODO: should the adds be distinguished? If so, how?
case Operation : : ADDQw : operation = Operation : : ADDQAl ; break ;
case Operation : : SUBQl :
case Operation : : SUBQw : operation = Operation : : SUBQAl ; break ;
}
}
2019-04-16 15:19:45 +00:00
switch ( is_long_word_access ? l ( mode ) : bw ( mode ) ) {
default : continue ;
2019-04-16 18:28:31 +00:00
case bw ( Dn ) : // [ADD/SUB]Q.bw #, Dn
2019-04-16 15:19:45 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
2019-04-16 18:28:31 +00:00
case l ( Dn ) : // [ADD/SUB]Q.l #, Dn
case l ( An ) : // [ADD/SUB]Q.l #, An
case bw ( An ) : // [ADD/SUB]Q.bw #, An
2019-04-16 15:19:45 +00:00
op ( Action : : PerformOperation , seq ( " np nn " ) ) ;
break ;
2019-04-16 18:28:31 +00:00
case bw ( Ind ) : // [ADD/SUB]Q.bw #, (An)
case bw ( PostInc ) : // [ADD/SUB]Q.bw #, (An)+
2019-04-16 15:19:45 +00:00
op ( Action : : None , seq ( " nrd np " , { a ( ea_register ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { a ( ea_register ) } , ! is_byte_access ) ) ;
if ( mode = = PostInc ) {
2019-04-24 17:01:08 +00:00
op ( inc ( ea_register ) | MicroOp : : DestinationMask ) ;
2019-04-16 15:19:45 +00:00
}
break ;
2019-04-16 18:28:31 +00:00
case l ( PreDec ) : // [ADD/SUB]Q.l #, -(An)
op ( int ( Action : : Decrement4 ) | MicroOp : : DestinationMask , seq ( " n " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-16 18:28:31 +00:00
case l ( Ind ) : // [ADD/SUB]Q.l #, (An)
case l ( PostInc ) : // [ADD/SUB]Q.l #, (An)+
2019-04-16 15:19:45 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " nRd+ nrd np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
if ( mode = = PostInc ) {
op ( int ( Action : : Increment4 ) | MicroOp : : DestinationMask ) ;
}
break ;
2019-04-16 18:28:31 +00:00
case bw ( PreDec ) : // [ADD/SUB]Q.bw #, -(An)
2019-04-24 17:01:08 +00:00
op ( dec ( ea_register ) | MicroOp : : DestinationMask ,
2019-04-16 18:28:31 +00:00
seq ( " n nrd np " , { a ( ea_register ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { a ( ea_register ) } , ! is_byte_access ) ) ;
break ;
case bw ( XXXl ) : // [ADD/SUB]Q.bw #, (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-16 18:28:31 +00:00
case bw ( XXXw ) : // [ADD/SUB]Q.bw #, (xxx).w
2019-04-30 02:37:23 +00:00
case bw ( d16An ) : // [ADD/SUB]Q.bw #, (d16, An)
case bw ( d8AnXn ) : // [ADD/SUB]Q.bw #, (d8, An, Xn)
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask , seq ( pseq ( " np nrd np " , mode ) , { ea ( 1 ) } , ! is_byte_access ) ) ;
2019-04-16 18:28:31 +00:00
op ( Action : : PerformOperation , seq ( " nw " , { ea ( 1 ) } , ! is_byte_access ) ) ;
break ;
case l ( XXXl ) : // [ADD/SUB]Q.l #, (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-16 18:28:31 +00:00
case l ( XXXw ) : // [ADD/SUB]Q.l #, (xxx).w
2019-04-30 02:37:23 +00:00
case l ( d16An ) : // [ADD/SUB]Q.l #, (d16, An)
case l ( d8AnXn ) : // [ADD/SUB]Q.l #, (d8, An, Xn)
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask , seq ( pseq ( " np nRd+ nrd np " , mode ) , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-16 18:28:31 +00:00
op ( Action : : PerformOperation , seq ( " nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
2019-04-16 15:19:45 +00:00
}
} break ;
2019-04-27 20:57:21 +00:00
case Decoder : : ADDX_SUBX : {
if ( instruction & 0x8 ) {
// Use predecrementing address registers.
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , Ind , ea_register ) ;
program . set_destination ( storage_ , Ind , data_register ) ;
2019-04-27 20:57:21 +00:00
if ( is_long_word_access ) {
// Access order is very atypical here: it's lower parts each for both words,
// and then also a lower-part-first write.
2019-06-25 23:18:07 +00:00
op ( int ( Action : : Decrement2 ) | MicroOp : : SourceMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask ,
seq ( " n nr- nR " , { ea ( 0 ) , ea ( 0 ) } ) ) ;
op ( int ( Action : : Decrement2 ) | MicroOp : : DestinationMask | MicroOp : : SourceMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask ,
seq ( " nrd- nRd+ " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-27 20:57:21 +00:00
op ( Action : : PerformOperation , seq ( " nw- np nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-06-25 23:18:07 +00:00
op ( int ( Action : : Decrement2 ) | MicroOp : : DestinationMask ) ;
2019-04-27 20:57:21 +00:00
} else {
2019-06-25 23:18:07 +00:00
op ( dec ( ea_register ) | MicroOp : : SourceMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask ,
seq ( " n nr " , { ea ( 0 ) } , ! is_byte_access ) ) ;
op ( dec ( data_register ) | MicroOp : : DestinationMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask ,
seq ( " nrd np " , { ea ( 1 ) } , ! is_byte_access ) ) ;
2019-04-27 20:57:21 +00:00
op ( Action : : PerformOperation , seq ( " nw " , { ea ( 1 ) } , ! is_byte_access ) ) ;
}
} else {
// Use data registers.
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , Dn , ea_register ) ;
program . set_destination ( storage_ , Dn , data_register ) ;
2019-04-27 20:57:21 +00:00
if ( is_long_word_access ) {
op ( Action : : PerformOperation , seq ( " np nn " ) ) ;
} else {
op ( Action : : PerformOperation , seq ( " np " ) ) ;
}
}
} break ;
2019-03-26 02:54:49 +00:00
// This decoder actually decodes nothing; it just schedules a PerformOperation followed by an empty step.
2019-04-16 23:50:10 +00:00
case Decoder : : Bcc_BSR : {
2019-04-16 03:20:36 +00:00
const int condition = ( instruction > > 8 ) & 0xf ;
if ( condition = = 1 ) {
// This is BSR, which is unconditional and means pushing a return address to the stack first.
// Push the return address to the stack.
2019-04-17 14:02:14 +00:00
op ( Action : : PrepareBSR , seq ( " n nW+ nw " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-16 03:20:36 +00:00
}
// This is Bcc.
2019-03-26 02:54:49 +00:00
op ( Action : : PerformOperation ) ;
2019-03-30 03:40:54 +00:00
op ( ) ; // The above looks terminal, but will be dynamically reprogrammed.
2019-03-26 02:54:49 +00:00
} break ;
// A little artificial, there's nothing really to decode for BRA.
case Decoder : : BRA : {
op ( Action : : PerformOperation , seq ( " n np np " ) ) ;
} break ;
2019-04-15 22:11:02 +00:00
// Decodes a BTST, potential mutating the operation into a BTSTl,
// or a BCLR.
case Decoder : : BCLR :
2019-04-05 01:43:22 +00:00
case Decoder : : BTST : {
2019-04-15 22:11:02 +00:00
const bool is_bclr = mapping . decoder = = Decoder : : BCLR ;
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , 0 , data_register ) ;
program . set_destination ( storage_ , ea_mode , ea_register ) ;
2019-04-05 01:43:22 +00:00
2019-04-06 14:41:19 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
2019-04-05 01:43:22 +00:00
switch ( mode ) {
default : continue ;
2019-04-12 02:31:17 +00:00
case Dn : // BTST.l Dn, Dn
2019-04-15 22:11:02 +00:00
if ( is_bclr ) {
operation = Operation : : BCLRl ;
op ( Action : : None , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " r " ) ) ;
} else {
operation = Operation : : BTSTl ;
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
}
2019-04-05 01:43:22 +00:00
break ;
2019-04-12 02:31:17 +00:00
case Ind : // BTST.b Dn, (An)
case PostInc : // BTST.b Dn, (An)+
2019-04-15 22:11:02 +00:00
op ( Action : : None , seq ( " nrd np " , { a ( ea_register ) } , false ) ) ;
2019-07-25 14:14:36 +00:00
op ( Action : : PerformOperation , is_bclr ? seq ( " nw " , { a ( ea_register ) } , false ) : MicroOp : : NoBusProgram ) ;
2019-04-12 17:45:28 +00:00
if ( mode = = PostInc ) {
2019-04-25 03:01:32 +00:00
op ( byte_inc ( ea_register ) | MicroOp : : DestinationMask ) ;
2019-04-05 01:43:22 +00:00
}
break ;
2019-04-12 02:31:17 +00:00
case PreDec : // BTST.b Dn, -(An)
2019-04-25 03:01:32 +00:00
op ( byte_dec ( ea_register ) | MicroOp : : DestinationMask , seq ( " n nrd np " , { a ( ea_register ) } , false ) ) ;
2019-07-25 14:14:36 +00:00
op ( Action : : PerformOperation , is_bclr ? seq ( " nw " , { a ( ea_register ) } , false ) : MicroOp : : NoBusProgram ) ;
2019-04-05 01:43:22 +00:00
break ;
2019-04-29 03:20:50 +00:00
case XXXl : // BTST.b Dn, (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-29 03:20:50 +00:00
case XXXw : // BTST.b Dn, (xxx).w
2019-04-12 02:31:17 +00:00
case d16An : // BTST.b Dn, (d16, An)
case d8AnXn : // BTST.b Dn, (d8, An, Xn)
case d16PC : // BTST.b Dn, (d16, PC)
case d8PCXn : // BTST.b Dn, (d8, PC, Xn)
2019-04-26 02:54:58 +00:00
// PC-relative addressing isn't support for BCLR.
if ( ( mode = = d16PC | | mode = = d8PCXn ) & & is_bclr ) continue ;
2019-04-29 03:20:50 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask ,
2019-04-05 01:43:22 +00:00
seq ( pseq ( " np nrd np " , mode ) , { ea ( 1 ) } , false ) ) ;
2019-07-25 14:14:36 +00:00
op ( Action : : PerformOperation , is_bclr ? seq ( " nw " , { ea ( 1 ) } , false ) : MicroOp : : NoBusProgram ) ;
2019-04-05 01:43:22 +00:00
break ;
2019-04-29 03:20:50 +00:00
case Imm : // BTST.b Dn, #
if ( is_bclr ) continue ;
/* Yacht.txt doesn't cover this; this is a guess. */
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " np " ) ) ;
2019-04-05 01:43:22 +00:00
break ;
}
} break ;
2019-04-15 22:11:02 +00:00
case Decoder : : BCLRIMM :
2019-04-05 01:43:22 +00:00
case Decoder : : BTSTIMM : {
2019-04-15 22:11:02 +00:00
const bool is_bclr = mapping . decoder = = Decoder : : BCLRIMM ;
2019-07-24 22:22:44 +00:00
program . set_source ( storage_ , Imm , 0 ) ;
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , ea_mode , ea_register ) ;
2019-04-05 01:43:22 +00:00
2019-04-06 14:41:19 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
2019-04-05 01:43:22 +00:00
switch ( mode ) {
default : continue ;
2019-04-12 02:31:17 +00:00
case Dn : // BTST.l #, Dn
2019-04-15 22:11:02 +00:00
if ( is_bclr ) {
operation = Operation : : BCLRl ;
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
op ( Action : : PerformOperation , seq ( " r " ) ) ;
} else {
operation = Operation : : BTSTl ;
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np n " ) ) ;
op ( Action : : PerformOperation ) ;
}
2019-04-05 01:43:22 +00:00
break ;
2019-04-12 02:31:17 +00:00
case Ind : // BTST.b #, (An)
case PostInc : // BTST.b #, (An)+
2019-04-15 22:11:02 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np nrd np " , { a ( ea_register ) } , false ) ) ;
2019-07-25 14:14:36 +00:00
op ( Action : : PerformOperation , is_bclr ? seq ( " nw " , { a ( ea_register ) } , false ) : MicroOp : : NoBusProgram ) ;
2019-04-12 17:45:28 +00:00
if ( mode = = PostInc ) {
2019-04-25 03:01:32 +00:00
op ( byte_inc ( ea_register ) | MicroOp : : DestinationMask ) ;
2019-04-05 01:43:22 +00:00
}
break ;
2019-04-12 02:31:17 +00:00
case PreDec : // BTST.b #, -(An)
2019-04-05 01:43:22 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
2019-04-25 03:01:32 +00:00
op ( byte_dec ( ea_register ) | MicroOp : : DestinationMask , seq ( " n nrd np " , { a ( ea_register ) } , false ) ) ;
2019-07-25 14:14:36 +00:00
op ( Action : : PerformOperation , is_bclr ? seq ( " nw " , { a ( ea_register ) } , false ) : MicroOp : : NoBusProgram ) ;
2019-04-05 01:43:22 +00:00
break ;
2019-05-07 01:14:16 +00:00
case XXXw : // BTST.b #, (xxx).w
2019-04-12 02:31:17 +00:00
case d16An : // BTST.b #, (d16, An)
case d8AnXn : // BTST.b #, (d8, An, Xn)
case d16PC : // BTST.b #, (d16, PC)
case d8PCXn : // BTST.b #, (d8, PC, Xn)
2019-04-26 02:54:58 +00:00
// PC-relative addressing isn't support for BCLR.
if ( ( mode = = d16PC | | mode = = d8PCXn ) & & is_bclr ) continue ;
2019-04-05 01:43:22 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask ,
2019-04-05 01:43:22 +00:00
seq ( pseq ( " np nrd np " , mode ) , { ea ( 1 ) } , false ) ) ;
2019-07-25 14:14:36 +00:00
op ( Action : : PerformOperation , is_bclr ? seq ( " nw " , { ea ( 1 ) } , false ) : MicroOp : : NoBusProgram ) ;
2019-04-05 01:43:22 +00:00
break ;
2019-04-12 02:31:17 +00:00
case XXXl : // BTST.b #, (xxx).l
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
2019-04-05 01:43:22 +00:00
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask ,
seq ( " np nrd np " , { ea ( 1 ) } , false ) ) ;
2019-07-25 14:14:36 +00:00
op ( Action : : PerformOperation , is_bclr ? seq ( " nw " , { ea ( 1 ) } , false ) : MicroOp : : NoBusProgram ) ;
2019-04-05 01:43:22 +00:00
break ;
}
} break ;
2019-03-17 03:14:18 +00:00
// Decodes the format used by ABCD and SBCD.
2019-04-16 23:50:10 +00:00
case Decoder : : ABCD_SBCD : {
2019-03-16 23:41:07 +00:00
if ( instruction & 8 ) {
2019-12-17 01:01:19 +00:00
// [A/S]BCD -(An), -(An)
2019-06-19 22:13:06 +00:00
program . set_source ( storage_ , Ind , ea_register ) ;
program . set_destination ( storage_ , Ind , data_register ) ;
2019-04-24 17:01:08 +00:00
2019-06-19 22:13:06 +00:00
op ( MicroOp : : SourceMask | dec ( ea_register ) , seq ( " n nr " , { a ( ea_register ) } , false ) ) ;
op ( MicroOp : : DestinationMask | dec ( data_register ) , seq ( " nrd np " , { a ( data_register ) } , false ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { a ( data_register ) } , false ) ) ;
2019-03-16 23:41:07 +00:00
} else {
2019-12-17 01:01:19 +00:00
// [A/S]BCD Dn, Dn
2019-06-19 22:13:06 +00:00
program . set_source ( storage_ , Dn , ea_register ) ;
program . set_destination ( storage_ , Dn , data_register ) ;
2019-03-16 23:41:07 +00:00
2019-03-21 03:21:02 +00:00
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
2019-03-16 23:41:07 +00:00
}
} break ;
2019-04-16 23:50:10 +00:00
case Decoder : : ASLR_LSLR_ROLR_ROXLRr : {
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , 0 , ea_register ) ;
2019-04-10 01:48:08 +00:00
2019-04-10 02:12:37 +00:00
// All further decoding occurs at runtime; that's also when the proper number of
// no-op cycles will be scheduled.
if ( ( ( instruction > > 6 ) & 3 ) = = 2 ) {
2019-06-23 21:33:12 +00:00
op ( Action : : None , seq ( " np nn " ) ) ; // Long-word rotates take an extra two cycles.
2019-04-10 02:12:37 +00:00
} else {
op ( Action : : None , seq ( " np n " ) ) ;
}
2019-04-11 02:31:04 +00:00
// Use a no-op bus cycle that can have its length filled in later.
op ( Action : : PerformOperation , seq ( " r " ) ) ;
2019-04-10 01:48:08 +00:00
} break ;
2019-04-16 23:50:10 +00:00
case Decoder : : ASLR_LSLR_ROLR_ROXLRm : {
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , ea_mode , ea_register ) ;
2019-04-10 01:48:08 +00:00
2019-04-12 02:31:17 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
switch ( mode ) {
2019-04-10 01:48:08 +00:00
default : continue ;
2019-04-12 02:31:17 +00:00
case Ind : // AS(L/R)/LS(L/R)/RO(L/R)/ROX(L/R).w (An)
case PostInc : // AS(L/R)/LS(L/R)/RO(L/R)/ROX(L/R).w (An)+
2019-04-10 01:48:08 +00:00
op ( Action : : None , seq ( " nrd np " , { a ( ea_register ) } ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { a ( ea_register ) } ) ) ;
2019-04-12 17:45:28 +00:00
if ( ea_mode = = PostInc ) {
2019-04-10 01:48:08 +00:00
op ( int ( Action : : Increment2 ) | MicroOp : : DestinationMask ) ;
}
break ;
2019-04-12 02:31:17 +00:00
case PreDec : // AS(L/R)/LS(L/R)/RO(L/R)/ROX(L/R).w -(An)
2019-04-10 01:48:08 +00:00
op ( int ( Action : : Decrement2 ) | MicroOp : : DestinationMask , seq ( " n nrd np " , { a ( ea_register ) } ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { a ( ea_register ) } ) ) ;
break ;
2019-04-12 02:31:17 +00:00
case XXXl : // AS(L/R)/LS(L/R)/RO(L/R)/ROX(L/R).w (xxx).l
2019-04-10 01:48:08 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-12 02:31:17 +00:00
case XXXw : // AS(L/R)/LS(L/R)/RO(L/R)/ROX(L/R).w (xxx).w
2019-04-30 02:37:23 +00:00
case d16An : // AS(L/R)/LS(L/R)/RO(L/R)/ROX(L/R).w (d16, An)
case d8AnXn : // AS(L/R)/LS(L/R)/RO(L/R)/ROX(L/R).w (d8, An, Xn)
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask ,
seq ( pseq ( " np nrd np " , mode ) , { ea ( 1 ) } ) ) ;
2019-04-10 01:48:08 +00:00
op ( Action : : PerformOperation , seq ( " nw " , { ea ( 1 ) } ) ) ;
break ;
}
} break ;
2019-04-16 23:50:10 +00:00
case Decoder : : CLR_NEG_NEGX_NOT : {
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , ea_mode , ea_register ) ;
2019-04-08 02:07:39 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
2019-04-12 17:45:28 +00:00
switch ( is_long_word_access ? l ( mode ) : bw ( mode ) ) {
2019-04-08 02:07:39 +00:00
default : continue ;
2019-04-12 17:45:28 +00:00
case bw ( Dn ) : // [CLR/NEG/NEGX/NOT].bw Dn
2019-04-08 02:07:39 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
2019-06-24 23:43:30 +00:00
case l ( Dn ) : // [CLR/NEG/NEGX/NOT].l Dn
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
break ;
2019-04-12 17:45:28 +00:00
case bw ( Ind ) : // [CLR/NEG/NEGX/NOT].bw (An)
case bw ( PostInc ) : // [CLR/NEG/NEGX/NOT].bw (An)+
2019-04-08 02:07:39 +00:00
op ( Action : : None , seq ( " nrd " , { a ( ea_register ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " np nw " , { a ( ea_register ) } , ! is_byte_access ) ) ;
2019-04-12 17:45:28 +00:00
if ( ea_mode = = PostInc ) {
2019-04-24 17:01:08 +00:00
op ( inc ( ea_register ) | MicroOp : : DestinationMask ) ;
2019-04-08 02:07:39 +00:00
}
break ;
2019-04-12 17:45:28 +00:00
case l ( Ind ) : // [CLR/NEG/NEGX/NOT].l (An)
case l ( PostInc ) : // [CLR/NEG/NEGX/NOT].l (An)+
2019-04-08 02:07:39 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " nRd+ nrd " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " np nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-12 17:45:28 +00:00
if ( ea_mode = = PostInc ) {
2019-04-08 02:07:39 +00:00
op ( int ( Action : : Increment4 ) | MicroOp : : DestinationMask ) ;
}
break ;
2019-04-12 17:45:28 +00:00
case bw ( PreDec ) : // [CLR/NEG/NEGX/NOT].bw -(An)
2019-04-24 17:01:08 +00:00
op ( dec ( ea_register ) | MicroOp : : DestinationMask ,
2019-04-08 02:07:39 +00:00
seq ( " nrd " , { a ( ea_register ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " np nw " , { a ( ea_register ) } , ! is_byte_access ) ) ;
break ;
2019-04-12 17:45:28 +00:00
case l ( PreDec ) : // [CLR/NEG/NEGX/NOT].l -(An)
2019-04-08 02:07:39 +00:00
op ( int ( Action : : Decrement4 ) | MicroOp : : DestinationMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask ,
seq ( " n nRd+ nrd " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " np nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
2019-04-30 02:37:23 +00:00
case bw ( XXXl ) : // [CLR/NEG/NEGX/NOT].bw (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-30 02:37:23 +00:00
case bw ( XXXw ) : // [CLR/NEG/NEGX/NOT].bw (xxx).w
2019-04-12 17:45:28 +00:00
case bw ( d16An ) : // [CLR/NEG/NEGX/NOT].bw (d16, An)
case bw ( d8AnXn ) : // [CLR/NEG/NEGX/NOT].bw (d8, An, Xn)
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask ,
seq ( pseq ( " np nrd " , mode ) , { ea ( 1 ) } , ! is_byte_access ) ) ;
2019-04-08 02:07:39 +00:00
op ( Action : : PerformOperation , seq ( " np nw " , { ea ( 1 ) } , ! is_byte_access ) ) ;
break ;
2019-04-30 02:37:23 +00:00
case l ( XXXl ) : // [CLR/NEG/NEGX/NOT].l (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-30 02:37:23 +00:00
case l ( XXXw ) : // [CLR/NEG/NEGX/NOT].l (xxx).w
2019-04-12 17:45:28 +00:00
case l ( d16An ) : // [CLR/NEG/NEGX/NOT].l (d16, An)
case l ( d8AnXn ) : // [CLR/NEG/NEGX/NOT].l (d8, An, Xn)
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask ,
2019-04-12 02:31:17 +00:00
seq ( pseq ( " np nRd+ nrd " , mode ) , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-08 02:07:39 +00:00
op ( Action : : PerformOperation , seq ( " np nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
}
} break ;
2019-04-06 14:41:19 +00:00
case Decoder : : CMP : {
2019-07-24 22:22:44 +00:00
program . set_destination ( storage_ , Dn , data_register ) ;
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , ea_mode , ea_register ) ;
2019-04-06 14:41:19 +00:00
// Byte accesses are not allowed with address registers.
2019-04-26 02:54:58 +00:00
if ( is_byte_access & & ea_mode = = An ) {
2019-04-06 14:41:19 +00:00
continue ;
}
2019-04-12 17:45:28 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
switch ( is_long_word_access ? l ( mode ) : bw ( mode ) ) {
2019-04-06 14:41:19 +00:00
default : continue ;
2019-04-12 17:45:28 +00:00
case bw ( Dn ) : // CMP.bw Dn, Dn
case bw ( An ) : // CMP.w An, Dn
2019-04-06 14:41:19 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
2019-06-27 02:02:04 +00:00
case l ( Dn ) : // CMP.l Dn, Dn
case l ( An ) : // CMP.l An, Dn
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
break ;
2019-04-12 17:45:28 +00:00
case bw ( Ind ) : // CMP.bw (An), Dn
case bw ( PostInc ) : // CMP.bw (An)+, Dn
2019-04-06 14:41:19 +00:00
op ( Action : : None , seq ( " nr np " , { a ( ea_register ) } , ! is_byte_access ) ) ;
2019-04-12 17:45:28 +00:00
if ( mode = = PostInc ) {
2019-04-24 17:01:08 +00:00
op ( inc ( ea_register ) | MicroOp : : SourceMask ) ;
2019-04-06 14:41:19 +00:00
}
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 17:45:28 +00:00
case l ( Ind ) : // CMP.l (An), Dn
case l ( PostInc ) : // CMP.l (An)+, Dn
2019-04-06 14:41:19 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask , seq ( " nR+ nr np n " , { ea ( 0 ) , ea ( 0 ) } ) ) ;
2019-04-12 17:45:28 +00:00
if ( mode = = PostInc ) {
2019-04-06 14:41:19 +00:00
op ( int ( Action : : Increment4 ) | MicroOp : : SourceMask ) ;
}
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 17:45:28 +00:00
case bw ( PreDec ) : // CMP.bw -(An), Dn
2019-04-24 17:01:08 +00:00
op ( dec ( ea_register ) | MicroOp : : SourceMask ,
2019-04-06 14:41:19 +00:00
seq ( " n nr np " , { a ( ea_register ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 17:45:28 +00:00
case l ( PreDec ) : // CMP.l -(An), Dn
2019-04-06 14:41:19 +00:00
op ( int ( Action : : Decrement4 ) | MicroOp : : SourceMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask , seq ( " n nR+ nr np n " , { ea ( 0 ) , ea ( 0 ) } ) ) ;
op ( Action : : PerformOperation ) ;
break ;
2019-04-30 02:37:23 +00:00
case bw ( XXXl ) : // CMP.bw (xxx).l, Dn
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-30 02:37:23 +00:00
case bw ( XXXw ) : // CMP.bw (xxx).w, Dn
2019-04-12 17:45:28 +00:00
case bw ( d16An ) : // CMP.bw (d16, An), Dn
case bw ( d8AnXn ) : // CMP.bw (d8, An, Xn), Dn
case bw ( d16PC ) : // CMP.bw (d16, PC), Dn
case bw ( d8PCXn ) : // CMP.bw (d8, PC, Xn), Dn
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask ,
seq ( pseq ( " np nr np " , mode ) , { ea ( 0 ) } , ! is_byte_access ) ) ;
2019-04-06 14:41:19 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-30 02:37:23 +00:00
case l ( XXXl ) : // CMP.l (xxx).l, Dn
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-30 02:37:23 +00:00
case l ( XXXw ) : // CMP.l (xxx).w, Dn
2019-04-12 17:45:28 +00:00
case l ( d16An ) : // CMP.l (d16, An), Dn
case l ( d8AnXn ) : // CMP.l (d8, An, Xn), Dn
case l ( d16PC ) : // CMP.l (d16, PC), Dn
case l ( d8PCXn ) : // CMP.l (d8, PC, Xn), Dn
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask ,
2019-04-12 02:31:17 +00:00
seq ( pseq ( " np nR+ nr np n " , mode ) , { ea ( 0 ) , ea ( 0 ) } ) ) ;
2019-04-06 14:41:19 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 17:45:28 +00:00
case bw ( Imm ) : // CMP.br #, Dn
2019-07-25 02:02:50 +00:00
program . set_source ( storage_ , & storage_ . prefetch_queue_ ) ;
2019-04-06 14:41:19 +00:00
op ( Action : : PerformOperation , seq ( " np np " ) ) ;
break ;
2019-04-12 17:45:28 +00:00
case l ( Imm ) : // CMP.l #, Dn
2019-07-25 02:02:50 +00:00
program . set_source ( storage_ , & storage_ . prefetch_queue_ ) ;
2019-04-06 14:41:19 +00:00
op ( Action : : None , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " np np n " ) ) ;
break ;
}
} break ;
2019-04-09 02:40:38 +00:00
case Decoder : : CMPA : {
2019-04-21 01:21:33 +00:00
// Only operation modes 011 and 111 are accepted, and long words are selected
// by the top bit.
if ( ( ( op_mode ) & 3 ) ! = 3 ) continue ;
is_long_word_access = op_mode = = 7 ;
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , ea_mode , ea_register ) ;
2019-07-24 22:22:44 +00:00
program . set_destination ( storage_ , An , data_register ) ;
2019-04-09 02:40:38 +00:00
2019-04-21 01:23:36 +00:00
const int mode = combined_mode ( ea_mode , ea_register , true ) ;
2019-04-12 17:45:28 +00:00
switch ( is_long_word_access ? l ( mode ) : bw ( mode ) ) {
2019-04-09 02:40:38 +00:00
default : continue ;
2019-04-21 01:23:36 +00:00
case bw ( Dn ) : // CMPA.w [An/Dn], An
case l ( Dn ) : // CMPA.l [An/Dn], An
2019-04-09 02:40:38 +00:00
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
break ;
2019-04-12 17:45:28 +00:00
case bw ( Ind ) : // CMPA.w (An), An
case bw ( PostInc ) : // CMPA.w (An)+, An
2019-04-09 02:40:38 +00:00
op ( Action : : None , seq ( " nr " , { a ( ea_register ) } ) ) ;
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
2019-04-21 01:23:36 +00:00
if ( mode = = PostInc ) {
2019-04-09 02:40:38 +00:00
op ( int ( Action : : Increment2 ) | MicroOp : : SourceMask ) ;
}
break ;
2019-04-12 17:45:28 +00:00
case l ( Ind ) : // CMPA.l (An), An
case l ( PostInc ) : // CMPA.l (An)+, An
2019-04-09 02:40:38 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask , seq ( " nR+ nr " , { ea ( 0 ) , ea ( 0 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
2019-04-21 01:23:36 +00:00
if ( mode = = PostInc ) {
2019-04-09 02:40:38 +00:00
op ( int ( Action : : Increment4 ) | MicroOp : : SourceMask ) ;
}
break ;
2019-04-12 17:45:28 +00:00
case bw ( PreDec ) : // CMPA.w -(An), An
2019-04-09 02:40:38 +00:00
op ( int ( Action : : Decrement2 ) | MicroOp : : SourceMask , seq ( " n nr " , { a ( ea_register ) } ) ) ;
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
break ;
2019-04-12 17:45:28 +00:00
case l ( PreDec ) : // CMPA.l -(An), An
2019-04-09 02:40:38 +00:00
op ( int ( Action : : Decrement4 ) | MicroOp : : SourceMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask , seq ( " nR+ nr " , { ea ( 0 ) , ea ( 0 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
break ;
2019-04-21 01:23:36 +00:00
case bw ( XXXl ) : // CMPA.w (xxx).l, An
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:50:37 +00:00
[[fallthrough]] ;
2019-04-21 01:23:36 +00:00
case bw ( XXXw ) : // CMPA.w (xxx).w, An
2019-04-12 17:45:28 +00:00
case bw ( d16PC ) : // CMPA.w (d16, PC), An
case bw ( d8PCXn ) : // CMPA.w (d8, PC, Xn), An
case bw ( d16An ) : // CMPA.w (d16, An), An
case bw ( d8AnXn ) : // CMPA.w (d8, An, Xn), An
2019-04-21 01:23:36 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( pseq ( " np nr " , mode ) , { ea ( 0 ) } ) ) ;
2019-04-09 02:40:38 +00:00
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
break ;
2019-04-21 01:23:36 +00:00
case l ( XXXl ) : // CMPA.l (xxx).l, An
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-21 01:23:36 +00:00
case l ( XXXw ) : // CMPA.l (xxx).w, An
2019-04-12 17:45:28 +00:00
case l ( d16PC ) : // CMPA.l (d16, PC), An
case l ( d8PCXn ) : // CMPA.l (d8, PC, Xn), An
case l ( d16An ) : // CMPA.l (d16, An), An
case l ( d8AnXn ) : // CMPA.l (d8, An, Xn), An
2019-04-21 01:23:36 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( pseq ( " np nR+ nr " , mode ) , { ea ( 0 ) , ea ( 0 ) } ) ) ;
2019-04-09 02:40:38 +00:00
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
break ;
2019-04-12 17:45:28 +00:00
case bw ( Imm ) : // CMPA.w #, An
2019-07-25 02:02:50 +00:00
program . set_source ( storage_ , & storage_ . prefetch_queue_ ) ;
2019-04-09 02:40:38 +00:00
op ( Action : : PerformOperation , seq ( " np np n " ) ) ;
break ;
2019-04-12 17:45:28 +00:00
case l ( Imm ) : // CMPA.l #, An
2019-07-25 02:02:50 +00:00
program . set_source ( storage_ , & storage_ . prefetch_queue_ ) ;
2019-04-09 02:40:38 +00:00
op ( Action : : None , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " np np n " ) ) ;
break ;
}
} break ;
2019-03-25 03:05:57 +00:00
case Decoder : : CMPI : {
2019-04-26 02:54:58 +00:00
if ( ea_mode = = An ) continue ;
2019-03-24 22:20:54 +00:00
2019-04-06 14:41:19 +00:00
const auto destination_mode = ea_mode ;
const auto destination_register = ea_register ;
2019-03-25 03:05:57 +00:00
2019-07-24 22:22:44 +00:00
program . set_source ( storage_ , Imm , 0 ) ; // i.e. from the fetched data latch.
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , destination_mode , destination_register ) ;
2019-03-25 03:05:57 +00:00
2019-04-12 17:45:28 +00:00
const int mode = combined_mode ( destination_mode , destination_register ) ;
switch ( is_long_word_access ? l ( mode ) : bw ( mode ) ) {
default : continue ;
case bw ( Dn ) : // CMPI.bw #, Dn
2019-07-25 02:02:50 +00:00
program . set_source ( storage_ , & storage_ . prefetch_queue_ ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation , seq ( " np np " ) ) ;
2019-03-24 22:20:54 +00:00
break ;
2019-04-12 17:45:28 +00:00
case l ( Dn ) : // CMPI.l #, Dn
2019-07-25 02:02:50 +00:00
program . set_source ( storage_ , & storage_ . prefetch_queue_ ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : None , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " np np n " ) ) ;
break ;
2019-03-24 22:20:54 +00:00
2019-04-12 17:45:28 +00:00
case bw ( Ind ) : // CMPI.bw #, (An)
case bw ( PostInc ) : // CMPI.bw #, (An)+
2019-04-04 01:27:11 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np nrd np " , { a ( destination_register ) } , ! is_byte_access ) ) ;
2019-04-12 17:45:28 +00:00
if ( mode = = PostInc ) {
2019-04-24 17:01:08 +00:00
op ( inc ( destination_register ) | MicroOp : : DestinationMask ) ;
2019-03-25 03:05:57 +00:00
}
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 17:45:28 +00:00
case l ( Ind ) : // CMPI.l #, (An)
case l ( PostInc ) : // CMPI.l #, (An)+
2019-03-30 03:13:41 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
2019-04-04 01:27:11 +00:00
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np nRd+ nrd np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-12 17:45:28 +00:00
if ( mode = = PostInc ) {
2019-03-25 03:05:57 +00:00
op ( int ( Action : : Increment4 ) | MicroOp : : DestinationMask ) ;
}
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 17:45:28 +00:00
case bw ( PreDec ) : // CMPI.bw #, -(An)
2019-03-25 03:05:57 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np n " ) ) ;
2019-04-24 17:01:08 +00:00
op ( dec ( destination_register ) | MicroOp : : DestinationMask , seq ( " nrd np " , { a ( destination_register ) } , ! is_byte_access ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 17:45:28 +00:00
case l ( PreDec ) : // CMPI.l #, -(An)
2019-03-25 03:05:57 +00:00
op ( int ( Action : : Decrement4 ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
2019-04-04 02:39:01 +00:00
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np n " ) ) ;
2019-04-04 01:27:11 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " nRd+ nrd np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-30 02:37:23 +00:00
case bw ( XXXw ) : // CMPI.bw #, (xxx).w
2019-04-12 17:45:28 +00:00
case bw ( d16An ) : // CMPI.bw #, (d16, An)
case bw ( d8AnXn ) : // CMPI.bw #, (d8, An, Xn)
2019-03-25 03:05:57 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask ,
2019-04-24 18:45:24 +00:00
seq ( pseq ( " np nrd np " , mode ) , { ea ( 1 ) } , ! is_byte_access ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 17:45:28 +00:00
case l ( d16An ) : // CMPI.l #, (d16, An)
case l ( d8AnXn ) : // CMPI.l #, (d8, An, Xn)
2019-03-30 03:13:41 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
2019-03-25 03:05:57 +00:00
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
2019-03-27 02:07:28 +00:00
op ( calc_action_for_mode ( mode ) | MicroOp : : DestinationMask ,
2019-04-04 01:27:11 +00:00
seq ( pseq ( " np nRd+ nrd np " , mode ) , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 17:45:28 +00:00
case l ( XXXw ) : // CMPI.l #, (xxx).w
2019-03-25 03:05:57 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2019-06-19 17:52:56 +00:00
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
op ( int ( Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np nRd+ nrd np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 17:45:28 +00:00
case bw ( XXXl ) : // CMPI.bw #, (xxx).l
2019-03-25 03:05:57 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
2019-04-04 01:27:11 +00:00
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np nrd np " , { ea ( 1 ) } , ! is_byte_access ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 17:45:28 +00:00
case l ( XXXl ) : // CMPI.l #, (xxx).l
2019-03-25 03:05:57 +00:00
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
2019-04-04 01:27:11 +00:00
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np nRd+ nrd np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-03-24 22:20:54 +00:00
}
2019-03-25 03:05:57 +00:00
} break ;
2019-04-09 02:40:38 +00:00
case Decoder : : CMPM : {
2019-06-26 01:46:01 +00:00
program . set_source ( storage_ , PostInc , ea_register ) ;
program . set_destination ( storage_ , PostInc , data_register ) ;
2019-04-09 02:40:38 +00:00
2019-04-27 20:57:21 +00:00
const bool is_byte_operation = operation = = Operation : : CMPb ;
2019-04-09 02:40:38 +00:00
switch ( operation ) {
default : continue ;
case Operation : : CMPb : // CMPM.b, (An)+, (An)+
2019-06-26 01:46:01 +00:00
case Operation : : CMPw : // CMPM.w, (An)+, (An)+
op ( Action : : None , seq ( " nr " , { a ( ea_register ) } , ! is_byte_operation ) ) ;
op ( inc ( ea_register ) | MicroOp : : SourceMask ,
seq ( " nrd np " , { a ( data_register ) } , ! is_byte_operation ) ) ;
op ( inc ( data_register ) | MicroOp : : DestinationMask ) ;
2019-04-09 02:40:38 +00:00
op ( Action : : PerformOperation ) ;
2019-06-26 01:46:01 +00:00
break ;
2019-04-09 02:40:38 +00:00
2019-06-26 01:46:01 +00:00
case Operation : : CMPl : // CMPM.l, (An)+, (An)+
2019-06-26 01:24:03 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask ,
seq ( " nR+ nr " , { ea ( 0 ) , ea ( 0 ) } ) ) ;
op ( int ( Action : : Increment4 ) | MicroOp : : SourceMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask ,
seq ( " nRd+ nrd np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
op ( int ( Action : : Increment4 ) | MicroOp : : DestinationMask ) ;
2019-04-09 02:40:38 +00:00
op ( Action : : PerformOperation ) ;
break ;
}
} break ;
2019-04-16 23:50:10 +00:00
case Decoder : : Scc_DBcc : {
2019-04-15 02:39:13 +00:00
if ( ea_mode = = 1 ) {
// This is a DBcc. Decode as such.
2019-04-15 13:49:23 +00:00
operation = Operation : : DBcc ;
2019-07-24 22:22:44 +00:00
program . set_source ( storage_ , Dn , ea_register ) ;
2019-04-15 02:39:13 +00:00
// Jump straight into deciding what steps to take next,
// which will be selected dynamically.
op ( Action : : PerformOperation ) ;
op ( ) ;
} else {
// This is an Scc.
2019-06-19 17:15:12 +00:00
// Scc is implemented on the 68000 a read-modify-write operation.
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , ea_mode , ea_register ) ;
program . set_destination ( storage_ , ea_mode , ea_register ) ;
2019-04-15 02:39:13 +00:00
2019-06-19 17:15:12 +00:00
// Scc is always a byte operation.
is_byte_access = true ;
is_long_word_access = false ;
2019-04-15 02:39:13 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
switch ( mode ) {
default : continue ;
case Dn :
op ( Action : : PerformOperation , seq ( " np " ) ) ;
// TODO: if condition true, an extra n.
break ;
case Ind :
case PostInc :
op ( Action : : PerformOperation , seq ( " nr np nw " , { a ( ea_register ) , a ( ea_register ) } , false ) ) ;
if ( mode = = PostInc ) {
2019-04-24 17:01:08 +00:00
op ( inc ( ea_register ) | MicroOp : : DestinationMask ) ;
2019-04-15 02:39:13 +00:00
}
break ;
case PreDec :
2019-04-24 17:01:08 +00:00
op ( dec ( ea_register ) | MicroOp : : DestinationMask ) ;
2019-04-15 02:39:13 +00:00
op ( Action : : PerformOperation , seq ( " n nr np nw " , { a ( ea_register ) , a ( ea_register ) } , false ) ) ;
break ;
case XXXl :
2019-05-09 10:28:55 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-05-09 10:28:55 +00:00
case XXXw :
2019-04-30 02:37:23 +00:00
case d16An :
case d8AnXn :
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask , seq ( pseq ( " np nrd " , mode ) , { ea ( 1 ) } , false ) ) ;
2019-04-15 02:39:13 +00:00
op ( Action : : PerformOperation , seq ( " np nw " , { ea ( 1 ) } , false ) ) ;
break ;
}
}
2019-04-07 03:21:01 +00:00
} break ;
2019-04-15 19:14:38 +00:00
case Decoder : : JSR : {
2019-05-09 10:43:07 +00:00
// Ensure a proper source register is connected up for (d16, An) and (d8, An, Xn)-type addressing.
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , ea_mode , ea_register ) ;
2019-05-09 10:43:07 +00:00
// ... but otherwise assume that the true source of a destination will be the computed source address.
2019-07-25 02:02:50 +00:00
program . set_source ( storage_ , & storage_ . effective_address_ [ 0 ] ) ;
2019-05-09 10:43:07 +00:00
2020-01-05 03:22:33 +00:00
// Beware below: PrepareJSR will pre-emptively subtract four from A7 in order
// to facilitate the peculiar stack write order of JSR. Therefore any address
// calculation that might be a function of A7 needs to be done before PrepareJSR.
2019-04-15 19:14:38 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
switch ( mode ) {
default : continue ;
case Ind : // JSR (An)
2019-06-03 19:29:50 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask ) ;
2019-04-17 14:02:14 +00:00
op ( Action : : PrepareJSR ) ;
2019-04-16 02:02:52 +00:00
op ( Action : : PerformOperation , seq ( " np nW+ nw np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-15 19:14:38 +00:00
break ;
2019-04-30 02:37:23 +00:00
case XXXl : // JSR (xxx).L
op ( Action : : None , seq ( " np " ) ) ;
2019-06-24 19:36:33 +00:00
op ( Action : : PrepareJSR ) ; // TODO: improve PrepareJSR to be able to compute alternative
// offsets from the current PC, and thereby move this one slot earlier.
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask ) ;
op ( Action : : PerformOperation , seq ( " np nW+ nw np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
2019-04-30 02:37:23 +00:00
case XXXw : // JSR (xxx).W
2019-04-15 19:14:38 +00:00
case d16PC : // JSR (d16, PC)
case d16An : // JSR (d16, An)
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask ) ;
2020-01-05 03:22:33 +00:00
op ( Action : : PrepareJSR ) ;
2019-04-16 02:37:11 +00:00
op ( Action : : PerformOperation , seq ( " n np nW+ nw np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-15 19:14:38 +00:00
break ;
case d8PCXn : // JSR (d8, PC, Xn)
case d8AnXn : // JSR (d8, An, Xn)
2019-04-16 02:37:11 +00:00
op ( calc_action_for_mode ( mode ) | MicroOp : : SourceMask ) ;
2020-01-05 03:22:33 +00:00
op ( Action : : PrepareJSR ) ;
2019-04-16 02:37:11 +00:00
op ( Action : : PerformOperation , seq ( " n nn np nW+ nw np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-15 19:14:38 +00:00
break ;
}
} break ;
case Decoder : : RTS : {
op ( Action : : PrepareRTS , seq ( " nU nu " ) ) ;
op ( Action : : PerformOperation , seq ( " np np " ) ) ;
} break ;
2019-04-01 01:13:26 +00:00
case Decoder : : JMP : {
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , ea_mode , ea_register ) ;
2019-04-06 14:41:19 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
2019-04-01 01:13:26 +00:00
switch ( mode ) {
default : continue ;
2019-04-12 17:45:28 +00:00
case Ind : // JMP (An)
2019-06-03 19:29:50 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask ) ;
2019-04-01 01:13:26 +00:00
op ( Action : : PerformOperation , seq ( " np np " ) ) ;
break ;
2019-06-03 19:29:50 +00:00
case XXXw : // JMP (xxx).W
2019-04-12 17:45:28 +00:00
case d16PC : // JMP (d16, PC)
case d16An : // JMP (d16, An)
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask ) ;
2019-04-16 02:37:11 +00:00
op ( Action : : PerformOperation , seq ( " n np np " ) ) ;
2019-04-01 01:13:26 +00:00
break ;
2019-04-12 17:45:28 +00:00
case d8PCXn : // JMP (d8, PC, Xn)
case d8AnXn : // JMP (d8, An, Xn)
2019-04-16 02:37:11 +00:00
op ( calc_action_for_mode ( mode ) | MicroOp : : SourceMask ) ;
op ( Action : : PerformOperation , seq ( " n nn np np " ) ) ;
2019-04-01 01:13:26 +00:00
break ;
2019-06-03 19:29:50 +00:00
case XXXl : // JMP (xxx).L
2019-04-01 01:13:26 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2019-04-15 19:14:38 +00:00
op ( address_assemble_for_mode ( mode ) | MicroOp : : SourceMask ) ;
op ( Action : : PerformOperation , seq ( " np np " ) ) ;
break ;
2019-04-01 01:13:26 +00:00
}
} break ;
2019-04-26 17:49:59 +00:00
case Decoder : : PEA : {
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , An , ea_register ) ;
2019-07-24 22:22:44 +00:00
program . set_destination ( storage_ , Imm , 7 ) ; // Immediate destination => store to the destination bus latch.
2019-04-26 17:49:59 +00:00
2019-05-06 02:47:54 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
2019-04-26 17:49:59 +00:00
switch ( mode ) {
default : continue ;
case Ind : // PEA (An)
2019-05-29 18:37:15 +00:00
operation = Operation : : MOVEAl ;
2019-06-27 21:59:03 +00:00
op ( Action : : PerformOperation ) ;
2019-06-27 03:24:54 +00:00
op ( int ( Action : : Decrement4 ) | MicroOp : : DestinationMask ) ;
2019-06-27 21:59:03 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " np nW+ nw " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-26 17:49:59 +00:00
break ;
case XXXl : // PEA (XXX).l
case XXXw : // PEA (XXX).w
2019-07-25 14:14:36 +00:00
op ( int ( Action : : Decrement4 ) | MicroOp : : DestinationMask , ( mode = = XXXl ) ? seq ( " np " ) : MicroOp : : NoBusProgram ) ;
2019-04-26 17:49:59 +00:00
op ( address_assemble_for_mode ( mode ) | MicroOp : : SourceMask ) ;
2019-06-27 21:59:03 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask ) ;
2019-04-26 17:49:59 +00:00
op ( Action : : PerformOperation , seq ( " np nW+ nw np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
case d16An : // PEA (d16, An)
case d16PC : // PEA (d16, PC)
case d8AnXn : // PEA (d8, An, Xn)
case d8PCXn : // PEA (d8, PC, Xn)
op ( calc_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( pseq ( " np " , mode ) ) ) ;
2019-06-27 03:24:54 +00:00
op ( int ( Action : : Decrement4 ) | MicroOp : : DestinationMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask ) ;
2019-04-26 17:49:59 +00:00
op ( Action : : PerformOperation , seq ( pseq ( " np nW+ nw " , mode ) , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
}
} break ;
2019-03-27 02:07:28 +00:00
case Decoder : : LEA : {
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , An , data_register ) ;
2019-03-27 02:07:28 +00:00
2019-04-06 14:41:19 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
2019-07-24 22:39:36 +00:00
program . set_source_address ( storage_ , ea_register ) ;
2019-07-25 02:02:50 +00:00
program . set_source ( storage_ ,
2019-04-12 19:48:29 +00:00
( mode = = Ind ) ?
& storage_ . address_ [ ea_register ] :
2019-07-25 02:02:50 +00:00
& storage_ . effective_address_ [ 0 ] ) ;
2019-04-12 19:48:29 +00:00
2019-03-27 02:07:28 +00:00
switch ( mode ) {
default : continue ;
2019-04-12 17:45:28 +00:00
case Ind : // LEA (An), An (i.e. MOVEA)
2019-03-27 02:07:28 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
2019-12-17 01:01:19 +00:00
case XXXl : // LEA (xxx).L, An
2019-04-30 02:37:23 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-30 02:37:23 +00:00
case XXXw : // LEA (xxx).W, An
2019-04-12 17:45:28 +00:00
case d16An : // LEA (d16, An), An
2019-04-12 19:48:29 +00:00
case d16PC : // LEA (d16, PC), An
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
2019-03-27 02:07:28 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-04-12 19:48:29 +00:00
case d8AnXn : // LEA (d8, An, Xn), An
case d8PCXn : // LEA (d8, PC, Xn), An
2019-03-27 02:07:28 +00:00
op ( calc_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( " n np n np " ) ) ;
op ( Action : : PerformOperation ) ;
break ;
}
} break ;
2019-04-28 01:29:50 +00:00
case Decoder : : MOVEfromSR_NBCD : {
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , ea_mode , ea_register ) ;
2019-04-28 01:29:50 +00:00
is_byte_access = operation = = Operation : : NBCD ;
2019-12-17 01:01:19 +00:00
is_long_word_access = false ;
2019-04-25 18:39:32 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
switch ( mode ) {
default : continue ;
case Dn : // MOVE SR, Dn
op ( Action : : PerformOperation , seq ( " np n " ) ) ;
break ;
case Ind : // MOVE SR, (An)
case PostInc : // MOVE SR, (An)+
2019-04-28 01:29:50 +00:00
op ( Action : : None , seq ( " nrd " , { a ( ea_register ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " np nw " , { a ( ea_register ) } , ! is_byte_access ) ) ;
2019-04-25 18:39:32 +00:00
if ( mode = = PostInc ) {
2019-12-17 01:01:19 +00:00
op ( inc ( ea_register ) | MicroOp : : DestinationMask ) ;
2019-04-25 18:39:32 +00:00
}
break ;
case PreDec : // MOVE SR, -(An)
2019-12-17 01:01:19 +00:00
op ( dec ( ea_register ) | MicroOp : : DestinationMask , seq ( " n nrd " , { a ( ea_register ) } , ! is_byte_access ) ) ;
2019-04-28 01:29:50 +00:00
op ( Action : : PerformOperation , seq ( " np nw " , { a ( ea_register ) } , ! is_byte_access ) ) ;
2019-04-25 18:39:32 +00:00
break ;
case XXXl : // MOVE SR, (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-25 18:39:32 +00:00
case XXXw : // MOVE SR, (xxx).w
case d16An : // MOVE SR, (d16, An)
case d8AnXn : // MOVE SR, (d8, An, Xn)
2019-04-28 01:29:50 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask , seq ( pseq ( " np nrd " , mode ) , { ea ( 1 ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " np nw " , { ea ( 1 ) } , ! is_byte_access ) ) ;
2019-04-25 18:39:32 +00:00
break ;
}
} break ;
2019-04-08 02:24:17 +00:00
case Decoder : : MOVEtoSRCCR : {
2019-04-26 02:54:58 +00:00
if ( ea_mode = = An ) continue ;
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , ea_mode , ea_register ) ;
2019-07-25 02:02:50 +00:00
program . set_requires_supervisor ( operation = = Operation : : MOVEtoSR ) ;
2019-03-24 22:20:54 +00:00
2019-12-17 03:38:54 +00:00
is_long_word_access = false ;
is_byte_access = false ; // Even MOVE, CCR is a .w.
2019-03-24 22:20:54 +00:00
/* DEVIATION FROM YACHT.TXT: it has all of these reading an extra word from the PC;
this looks like a mistake so I ' ve padded with nil cycles in the middle . */
2019-04-06 14:41:19 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
2019-03-25 03:05:57 +00:00
switch ( mode ) {
2019-04-12 17:45:28 +00:00
default : continue ;
2019-12-17 03:38:54 +00:00
case Dn : // MOVE Dn, SR/CCR
2019-03-24 22:20:54 +00:00
op ( Action : : PerformOperation , seq ( " nn np " ) ) ;
break ;
2019-12-17 03:38:54 +00:00
case Ind : // MOVE (An), SR/CCR
case PostInc : // MOVE (An)+, SR/CCR
op ( Action : : None , seq ( " nr nn nn np " , { a ( ea_register ) } , ! is_byte_access ) ) ;
2019-04-12 17:45:28 +00:00
if ( mode = = PostInc ) {
2019-12-17 03:38:54 +00:00
op ( inc ( ea_register ) | MicroOp : : SourceMask ) ;
2019-03-24 22:20:54 +00:00
}
op ( Action : : PerformOperation ) ;
break ;
2019-12-17 03:38:54 +00:00
case PreDec : // MOVE -(An), SR/CCR
op ( dec ( ea_register ) | MicroOp : : SourceMask , seq ( " n nr nn nn np " , { a ( ea_register ) } , ! is_byte_access ) ) ;
2019-03-24 22:20:54 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-12-17 03:38:54 +00:00
case XXXl : // MOVE (xxx).L, SR/CCR
2019-04-30 02:37:23 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-12-17 03:38:54 +00:00
case XXXw : // MOVE (xxx).W, SR/CCR
case d16PC : // MOVE (d16, PC), SR/CCR
case d8PCXn : // MOVE (d8, PC, Xn), SR/CCR
case d16An : // MOVE (d16, An), SR/CCR
case d8AnXn : // MOVE (d8, An, Xn), SR/CCR
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( pseq ( " np nr nn nn np " , mode ) , { ea ( 0 ) } , ! is_byte_access ) ) ;
2019-03-24 22:20:54 +00:00
op ( Action : : PerformOperation ) ;
break ;
2019-12-17 03:38:54 +00:00
case Imm : // MOVE #, SR/CCR
2019-07-25 02:02:50 +00:00
program . set_source ( storage_ , & storage_ . prefetch_queue_ ) ;
2019-03-24 22:20:54 +00:00
op ( int ( Action : : PerformOperation ) , seq ( " np nn nn np " ) ) ;
break ;
}
} break ;
2019-03-30 03:13:41 +00:00
case Decoder : : MOVEq : {
2019-07-24 22:22:44 +00:00
program . set_destination ( storage_ , Dn , data_register ) ;
2019-03-30 03:13:41 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
} break ;
2019-04-29 02:52:54 +00:00
case Decoder : : MOVEP : {
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , An , ea_register ) ;
program . set_source ( storage_ , Dn , data_register ) ;
2019-04-29 02:52:54 +00:00
switch ( operation ) {
default : continue ;
// Both of the MOVEP to memory instructions perform their operation first — it will
// break up the source value into 8-bit chunks for the write section.
case Operation : : MOVEPtoMw :
op ( Action : : PerformOperation ) ;
op ( int ( Action : : CalcD16An ) | MicroOp : : DestinationMask , seq ( " np nW+ nw np " , { ea ( 1 ) , ea ( 1 ) } , false ) ) ;
break ;
case Operation : : MOVEPtoMl :
op ( Action : : PerformOperation ) ;
op ( int ( Action : : CalcD16An ) | MicroOp : : DestinationMask , seq ( " np nW+ nWr+ nw+ nwr np " , { ea ( 1 ) , ea ( 1 ) , ea ( 1 ) , ea ( 1 ) } , false ) ) ;
break ;
case Operation : : MOVEPtoRw :
op ( int ( Action : : CalcD16An ) | MicroOp : : DestinationMask , seq ( " np nRd+ nrd np " , { ea ( 1 ) , ea ( 1 ) } , false ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case Operation : : MOVEPtoRl :
2019-06-26 23:39:04 +00:00
// TODO: nR+ increments EA(0), not EA(1). Fix.
2019-04-29 02:52:54 +00:00
op ( int ( Action : : CalcD16An ) | MicroOp : : DestinationMask , seq ( " np nRd+ nR+ nrd+ nr np " , { ea ( 1 ) , ea ( 1 ) , ea ( 1 ) , ea ( 1 ) } , false ) ) ;
op ( Action : : PerformOperation ) ;
break ;
}
} break ;
2019-04-14 18:09:28 +00:00
case Decoder : : MOVEM : {
// For the sake of commonality, both to R and to M will evaluate their addresses
// as if they were destinations.
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , ea_mode , ea_register ) ;
2019-04-14 18:09:28 +00:00
// Standard prefix: acquire the register selection flags and fetch the next program
// word to replace them.
op ( Action : : CopyNextWord , seq ( " np " ) ) ;
// Do whatever is necessary to calculate the proper start address.
const int mode = combined_mode ( ea_mode , ea_register ) ;
const bool is_to_m = ( operation = = Operation : : MOVEMtoMl | | operation = = Operation : : MOVEMtoMw ) ;
switch ( mode ) {
default : continue ;
case Ind :
case PreDec :
case PostInc : {
// Deal with the illegal combinations.
if ( mode = = PostInc & & is_to_m ) continue ;
if ( mode = = PreDec & & ! is_to_m ) continue ;
} break ;
2019-04-30 02:37:23 +00:00
case XXXl :
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-30 02:37:23 +00:00
case XXXw :
2019-04-14 18:09:28 +00:00
case d16An :
case d8AnXn :
case d16PC :
case d8PCXn :
// PC-relative addressing is permitted for moving to registers only.
if ( ( mode = = d16PC | | mode = = d8PCXn ) & & is_to_m ) continue ;
2019-04-30 02:37:23 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : DestinationMask , seq ( pseq ( " np " , mode ) ) ) ;
2019-04-14 18:09:28 +00:00
break ;
}
// Standard suffix: perform the MOVEM, which will mean evaluating the
// register selection flags and substituting the necessary reads or writes.
op ( Action : : PerformOperation ) ;
// A final program fetch will cue up the next instruction.
2019-04-15 00:02:18 +00:00
op ( is_to_m ? Action : : MOVEMtoMComplete : Action : : MOVEMtoRComplete , seq ( " np " ) ) ;
2019-04-14 18:09:28 +00:00
} break ;
2019-04-17 20:58:59 +00:00
case Decoder : : MOVEUSP : {
2019-07-25 02:02:50 +00:00
program . set_requires_supervisor ( true ) ;
2019-04-17 20:58:59 +00:00
// Observation here: because this is a privileged instruction, the user stack pointer
2019-04-20 02:41:06 +00:00
// definitely isn't currently [copied into] A7.
2019-04-17 20:58:59 +00:00
if ( instruction & 0x8 ) {
// Transfer FROM the USP.
2019-07-25 02:02:50 +00:00
program . set_source ( storage_ , & storage_ . stack_pointers_ [ 0 ] ) ;
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , An , ea_register ) ;
2019-04-20 02:41:06 +00:00
} else {
// Transfer TO the USP.
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , An , ea_register ) ;
2019-07-25 02:02:50 +00:00
program . set_destination ( storage_ , & storage_ . stack_pointers_ [ 0 ] ) ;
2019-04-17 20:58:59 +00:00
}
op ( Action : : PerformOperation , seq ( " np " ) ) ;
} break ;
2019-03-24 22:20:54 +00:00
// Decodes the format used by most MOVEs and all MOVEAs.
2019-03-30 03:13:41 +00:00
case Decoder : : MOVE : {
2019-03-17 03:14:18 +00:00
const int destination_mode = ( instruction > > 6 ) & 7 ;
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , ea_mode , ea_register ) ;
program . set_destination ( storage_ , destination_mode , data_register ) ;
2019-03-17 03:14:18 +00:00
2019-04-19 17:29:20 +00:00
// These don't come from the usual place.
is_byte_access = mapping . operation = = Operation : : MOVEb ;
is_long_word_access = mapping . operation = = Operation : : MOVEl ;
2019-03-30 03:13:41 +00:00
2019-04-12 20:10:17 +00:00
// If the move is to an address register, switch the MOVE to a MOVEA.
2019-04-19 03:25:19 +00:00
// Also: there are no byte moves to address registers.
if ( destination_mode = = An ) {
if ( is_byte_access ) {
continue ;
}
2019-03-30 03:13:41 +00:00
operation = is_long_word_access ? Operation : : MOVEAl : Operation : : MOVEAw ;
}
2019-04-26 02:54:58 +00:00
// ... there are also no byte moves from address registers.
if ( ea_mode = = An & & is_byte_access ) continue ;
2019-05-28 19:17:03 +00:00
// Perform the MOVE[A]'s fetch..
const int combined_source_mode = combined_mode ( ea_mode , ea_register , true ) ;
switch ( is_long_word_access ? l ( combined_source_mode ) : bw ( combined_source_mode ) ) {
default : continue ;
2019-03-24 01:03:52 +00:00
2019-05-28 19:17:03 +00:00
case l ( Dn ) : // MOVE[A].l [An/Dn], <ea>
case bw ( Dn ) : // MOVE[A].bw [An/Dn], <ea>
2019-03-24 01:03:52 +00:00
break ;
2019-05-28 19:17:03 +00:00
case bw ( PreDec ) : // MOVE[A].bw -(An), <ea>
op ( dec ( ea_register ) | MicroOp : : SourceMask , seq ( " n nr " , { a ( ea_register ) } , ! is_byte_access ) ) ;
2019-03-24 01:03:52 +00:00
break ;
2019-05-28 19:17:03 +00:00
case bw ( Ind ) : // MOVE[A].bw (An), <ea>
case bw ( PostInc ) : // MOVE[A].bw (An)+, <ea>
op ( Action : : None , seq ( " nr " , { a ( ea_register ) } , ! is_byte_access ) ) ;
if ( combined_source_mode = = PostInc ) {
op ( inc ( ea_register ) | MicroOp : : SourceMask ) ;
}
2019-03-28 01:26:04 +00:00
break ;
2019-03-24 01:03:52 +00:00
2019-05-28 19:17:03 +00:00
case l ( PreDec ) : // MOVE[A].l -(An), <ea>
op ( dec ( ea_register ) | MicroOp : : SourceMask , seq ( " n " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-05-28 19:17:03 +00:00
case l ( Ind ) : // MOVE[A].l (An), <ea>
case l ( PostInc ) : // MOVE[A].l (An)+, <ea>
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask ,
seq ( " nR+ nr " , { ea ( 0 ) , ea ( 0 ) } ) ) ;
if ( combined_source_mode = = PostInc ) {
op ( inc ( ea_register ) | MicroOp : : SourceMask ) ;
}
2019-03-28 01:26:04 +00:00
break ;
2019-03-24 01:03:52 +00:00
2019-05-28 19:17:03 +00:00
case bw ( XXXl ) : // MOVE[A].bw (xxx).L, <ea>
2019-04-19 03:25:19 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-05-28 19:17:03 +00:00
case bw ( XXXw ) : // MOVE[A].bw (xxx).W, <ea>
case bw ( d16An ) : // MOVE[A].bw (d16, An), <ea>
case bw ( d8AnXn ) : // MOVE[A].bw (d8, An, Xn), <ea>
case bw ( d16PC ) : // MOVE[A].bw (d16, PC), <ea>
case bw ( d8PCXn ) : // MOVE[A].bw (d8, PC, Xn), <ea>
2019-04-19 03:25:19 +00:00
op ( address_action_for_mode ( combined_source_mode ) | MicroOp : : SourceMask ,
2019-05-28 19:17:03 +00:00
seq ( pseq ( " np nr " , combined_source_mode ) , { ea ( 0 ) } ,
! is_byte_access ) ) ;
2019-03-28 01:26:04 +00:00
break ;
2019-03-24 01:03:52 +00:00
2019-05-28 19:17:03 +00:00
case l ( XXXl ) : // MOVE[A].l (xxx).L, <ea>
2019-04-19 03:25:19 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-05-28 19:17:03 +00:00
case l ( XXXw ) : // MOVE[A].l (xxx).W, <ea>
case l ( d16An ) : // MOVE[A].l (d16, An), <ea>
case l ( d8AnXn ) : // MOVE[A].l (d8, An, Xn), <ea>
case l ( d16PC ) : // MOVE[A].l (d16, PC), <ea>
case l ( d8PCXn ) : // MOVE[A].l (d8, PC, Xn), <ea>
2019-04-19 03:25:19 +00:00
op ( address_action_for_mode ( combined_source_mode ) | MicroOp : : SourceMask ,
2019-05-28 19:17:03 +00:00
seq ( pseq ( " np nR+ nr " , combined_source_mode ) , { ea ( 0 ) , ea ( 0 ) } ) ) ;
2019-03-30 03:13:41 +00:00
break ;
2019-05-28 19:17:03 +00:00
case l ( Imm ) : // MOVE[A].l #, <ea>
2019-03-30 03:13:41 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2019-05-28 19:17:03 +00:00
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
2019-03-30 03:13:41 +00:00
break ;
2019-05-28 19:17:03 +00:00
case bw ( Imm ) : // MOVE[A].bw #, <ea>
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
2019-03-30 03:13:41 +00:00
break ;
2019-05-28 19:17:03 +00:00
}
2019-03-30 03:13:41 +00:00
2019-05-28 19:17:03 +00:00
// Perform the MOVE[A]'s store.
const int combined_destination_mode = combined_mode ( destination_mode , data_register , true ) ;
switch ( is_long_word_access ? l ( combined_destination_mode ) : bw ( combined_destination_mode ) ) {
default : continue ;
2019-03-30 03:13:41 +00:00
2019-05-28 19:17:03 +00:00
case l ( Dn ) : // MOVE[A].l <ea>, [An/Dn]
case bw ( Dn ) : // MOVE[A].bw <ea>, [An/Dn]
2019-07-09 22:07:11 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
2019-03-30 03:13:41 +00:00
break ;
2019-05-28 19:17:03 +00:00
case bw ( PreDec ) : // MOVE[A].bw <ea>, -(An)
2019-07-09 22:07:11 +00:00
op ( Action : : PerformOperation ) ;
2019-04-27 20:57:21 +00:00
op ( dec ( data_register ) | MicroOp : : DestinationMask ,
seq ( " np nw " , { a ( data_register ) } , ! is_byte_access ) ) ;
2019-03-30 03:13:41 +00:00
break ;
2019-05-28 19:17:03 +00:00
case bw ( Ind ) : // MOVE[A].bw <ea>, (An)
case bw ( PostInc ) : // MOVE[A].bw <ea>, (An)+
2019-07-09 22:07:11 +00:00
op ( Action : : PerformOperation , seq ( " nw np " , { a ( data_register ) } , ! is_byte_access ) ) ;
2019-05-28 19:17:03 +00:00
if ( combined_destination_mode = = PostInc ) {
op ( inc ( data_register ) | MicroOp : : DestinationMask ) ;
}
2019-04-18 03:05:16 +00:00
break ;
2019-05-28 19:17:03 +00:00
case l ( PreDec ) : // MOVE[A].l <ea>, -(An)
2019-07-09 22:07:11 +00:00
op ( Action : : PerformOperation ) ;
2019-04-18 03:05:16 +00:00
op ( int ( Action : : Decrement2 ) | MicroOp : : DestinationMask ) ;
2019-05-28 19:17:03 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask ,
seq ( " np nw- nW " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-18 03:05:16 +00:00
op ( int ( Action : : Decrement2 ) | MicroOp : : DestinationMask ) ;
break ;
2019-03-30 03:13:41 +00:00
2019-05-28 19:17:03 +00:00
case l ( Ind ) : // MOVE[A].l <ea>, (An)
case l ( PostInc ) : // MOVE[A].l <ea>, (An)+
2019-07-09 22:07:11 +00:00
op ( Action : : PerformOperation ) ;
2019-05-28 19:17:03 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask ,
seq ( " nW+ nw np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
if ( combined_destination_mode = = PostInc ) {
op ( inc ( data_register ) | MicroOp : : DestinationMask ) ;
}
2019-04-17 20:13:35 +00:00
break ;
2019-05-28 19:17:03 +00:00
case bw ( XXXw ) : // MOVE[A].bw <ea>, (xxx).W
case bw ( d16An ) : // MOVE[A].bw <ea>, (d16, An)
case bw ( d8AnXn ) : // MOVE[A].bw <ea>, (d8, An, Xn)
2019-07-09 22:07:11 +00:00
op ( Action : : PerformOperation ) ;
2019-05-28 19:17:03 +00:00
op ( address_action_for_mode ( combined_destination_mode ) | MicroOp : : DestinationMask ,
seq ( pseq ( " np nw np " , combined_destination_mode ) , { ea ( 1 ) } ,
! is_byte_access ) ) ;
2019-04-18 02:21:56 +00:00
break ;
2019-05-28 19:17:03 +00:00
case l ( XXXw ) : // MOVE[A].l <ea>, (xxx).W
case l ( d16An ) : // MOVE[A].l <ea>, (d16, An)
case l ( d8AnXn ) : // MOVE[A].l <ea>, (d8, An, Xn)
2019-07-09 22:07:11 +00:00
op ( Action : : PerformOperation ) ;
2019-05-28 19:17:03 +00:00
op ( address_action_for_mode ( combined_destination_mode ) | MicroOp : : DestinationMask ,
seq ( pseq ( " np nW+ nw np " , combined_destination_mode ) , { ea ( 1 ) , ea ( 1 ) } ) ) ;
2019-04-18 02:21:56 +00:00
break ;
2019-05-28 19:17:03 +00:00
case bw ( XXXl ) : // MOVE[A].bw <ea>, (xxx).L
2019-07-09 22:07:11 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
2019-05-28 19:17:03 +00:00
switch ( combined_source_mode ) { // The pattern here is a function of source and destination.
case Dn :
case Imm :
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask ,
seq ( " np nw np " , { ea ( 1 ) } , ! is_byte_access ) ) ;
break ;
default :
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask ,
seq ( " nw np np " , { ea ( 1 ) } , ! is_byte_access ) ) ;
break ;
}
2019-04-01 02:34:28 +00:00
break ;
2019-03-21 03:21:02 +00:00
2019-05-28 19:17:03 +00:00
case l ( XXXl ) : // MOVE[A].l <ea>, (xxx).L
2019-07-09 22:07:11 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
2019-05-28 19:17:03 +00:00
switch ( combined_source_mode ) { // The pattern here is a function of source and destination.
case Dn :
case Imm :
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask ,
seq ( " np nW+ nw np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
default :
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask ,
seq ( " nW+ nw np np " , { ea ( 1 ) , ea ( 1 ) } ) ) ;
break ;
2019-04-24 17:01:08 +00:00
}
2019-05-28 19:17:03 +00:00
break ;
2019-04-19 03:25:19 +00:00
}
2019-03-17 03:14:18 +00:00
} break ;
2019-03-30 03:40:54 +00:00
case Decoder : : RESET :
2019-07-25 02:02:50 +00:00
program . set_requires_supervisor ( true ) ;
2019-03-30 03:40:54 +00:00
op ( Action : : None , seq ( " nn _ np " ) ) ;
break ;
2019-04-18 02:21:56 +00:00
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 ;
2019-04-28 19:52:58 +00:00
case Decoder : : TRAPV : {
op ( Action : : None , seq ( " np " ) ) ;
op ( Action : : PerformOperation ) ;
op ( ) ;
} break ;
2019-04-28 19:47:21 +00:00
case Decoder : : CHK : {
2019-06-19 21:00:44 +00:00
program . set_destination ( storage_ , Dn , data_register ) ;
program . set_source ( storage_ , ea_mode , ea_register ) ;
2019-04-28 19:47:21 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
switch ( mode ) {
default : continue ;
case Dn : // CHK Dn, Dn
op ( Action : : None , seq ( " np " ) ) ;
break ;
case Ind : // CHK (An), Dn
case PostInc : // CHK (An)+, Dn
op ( Action : : None , seq ( " nr np " , { a ( ea_register ) } ) ) ;
if ( mode = = PostInc ) {
op ( int ( Action : : Increment2 ) | MicroOp : : SourceMask ) ;
}
break ;
2019-12-17 01:01:19 +00:00
case PreDec : // CHK -(An), Dn
2019-04-28 19:47:21 +00:00
op ( int ( Action : : Decrement2 ) | MicroOp : : SourceMask , seq ( " n nr np " , { a ( ea_register ) } ) ) ;
break ;
case XXXl : // CHK (xxx).l, Dn
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-28 19:47:21 +00:00
case XXXw : // CHK (xxx).w, Dn
case d16An : // CHK (d16, An), Dn
case d16PC : // CHK (d16, PC), Dn
case d8AnXn : // CHK (d8, An, Xn), Dn
case d8PCXn : // CHK (d8, PC, Xn), Dn
2020-01-02 00:11:36 +00:00
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( pseq ( " np nr np " , mode ) , { ea ( 0 ) } ) ) ;
2019-04-28 19:47:21 +00:00
break ;
case Imm : // CHK #, Dn
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
break ;
}
// The nn n here is correct if no exception is issued; otherwise this sequence will
// be replaced.
op ( Action : : PerformOperation , seq ( " nn n " ) ) ;
} break ;
2019-04-15 14:03:52 +00:00
case Decoder : : TST : {
2019-06-19 21:00:44 +00:00
program . set_source ( storage_ , ea_mode , ea_register ) ;
2019-04-15 14:03:52 +00:00
const int mode = combined_mode ( ea_mode , ea_register ) ;
switch ( is_long_word_access ? l ( mode ) : bw ( mode ) ) {
default : continue ;
2019-04-15 20:28:20 +00:00
case bw ( Dn ) : // TST.bw Dn
case l ( Dn ) : // TST.l Dn
2019-04-15 14:03:52 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
2019-04-15 20:28:20 +00:00
case bw ( PreDec ) : // TST.bw -(An)
2019-04-24 17:01:08 +00:00
op ( dec ( ea_register ) | MicroOp : : SourceMask , seq ( " n " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-15 20:28:20 +00:00
case bw ( Ind ) : // TST.bw (An)
case bw ( PostInc ) : // TST.bw (An)+
2019-04-15 14:03:52 +00:00
op ( Action : : None , seq ( " nr " , { a ( ea_register ) } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " np " ) ) ;
if ( mode = = PostInc ) {
2019-04-24 17:01:08 +00:00
op ( inc ( ea_register ) | MicroOp : : SourceMask ) ;
2019-04-15 14:03:52 +00:00
}
break ;
2019-04-15 20:28:20 +00:00
case l ( PreDec ) : // TST.l -(An)
2019-04-15 16:36:08 +00:00
op ( int ( Action : : Decrement4 ) | MicroOp : : SourceMask , seq ( " n " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-15 20:28:20 +00:00
case l ( Ind ) : // TST.l (An)
case l ( PostInc ) : // TST.l (An)+
2019-04-15 14:03:52 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask , seq ( " nR+ nr " , { ea ( 0 ) , ea ( 0 ) } ) ) ;
op ( Action : : PerformOperation , seq ( " np " ) ) ;
if ( mode = = PostInc ) {
op ( int ( Action : : Increment4 ) | MicroOp : : SourceMask ) ;
}
break ;
2019-04-15 20:28:20 +00:00
case bw ( XXXl ) : // TST.bw (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:44:20 +00:00
[[fallthrough]] ;
2019-04-15 20:28:20 +00:00
case bw ( XXXw ) : // TST.bw (xxx).w
2019-04-30 02:37:23 +00:00
case bw ( d16An ) : // TST.bw (d16, An)
case bw ( d8AnXn ) : // TST.bw (d8, An, Xn)
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( pseq ( " np nr " , mode ) , { ea ( 0 ) } , ! is_byte_access ) ) ;
2019-04-15 20:28:20 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
case l ( XXXl ) : // TST.l (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
2020-06-20 03:50:37 +00:00
[[fallthrough]] ;
2019-04-15 20:28:20 +00:00
case l ( XXXw ) : // TST.l (xxx).w
2019-04-30 02:37:23 +00:00
case l ( d16An ) : // TST.l (d16, An)
case l ( d8AnXn ) : // TST.l (d8, An, Xn)
op ( address_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( pseq ( " np nR+ nr " , mode ) , { ea ( 0 ) , ea ( 0 ) } ) ) ;
2019-04-15 20:28:20 +00:00
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
2019-04-15 14:03:52 +00:00
}
} break ;
2019-03-16 23:41:07 +00:00
default :
std : : cerr < < " Unhandled decoder " < < int ( mapping . decoder ) < < std : : endl ;
2019-03-17 02:36:09 +00:00
continue ;
2019-03-16 23:41:07 +00:00
}
2019-03-30 03:13:41 +00:00
// Add a terminating micro operation if necessary.
if ( ! storage_ . all_micro_ops_ . back ( ) . is_terminal ( ) ) {
storage_ . all_micro_ops_ . emplace_back ( ) ;
}
2019-05-06 02:47:54 +00:00
// Ensure that steps that weren't meant to look terminal aren't terminal; also check
// for improperly encoded address calculation-type actions.
2019-04-01 02:34:28 +00:00
for ( auto index = micro_op_start ; index < storage_ . all_micro_ops_ . size ( ) - 1 ; + + index ) {
2019-05-06 02:47:54 +00:00
2019-12-17 03:38:54 +00:00
# ifdef DEBUG
2019-05-06 02:47:54 +00:00
// All of the actions below must also nominate a source and/or destination.
switch ( storage_ . all_micro_ops_ [ index ] . action ) {
default : break ;
case int ( Action : : CalcD16PC ) :
case int ( Action : : CalcD8PCXn ) :
case int ( Action : : CalcD16An ) :
case int ( Action : : CalcD8AnXn ) :
case int ( Action : : AssembleWordAddressFromPrefetch ) :
case int ( Action : : AssembleLongWordAddressFromPrefetch ) :
case int ( Action : : CopyToEffectiveAddress ) :
2019-12-17 03:38:54 +00:00
case int ( Action : : Increment1 ) :
case int ( Action : : Increment2 ) :
case int ( Action : : Increment4 ) :
case int ( Action : : Decrement1 ) :
case int ( Action : : Decrement2 ) :
case int ( Action : : Decrement4 ) :
2019-05-06 02:47:54 +00:00
assert ( false ) ;
}
2019-12-17 03:38:54 +00:00
# endif
2019-05-06 02:47:54 +00:00
2019-04-01 02:34:28 +00:00
if ( storage_ . all_micro_ops_ [ index ] . is_terminal ( ) ) {
2019-07-27 03:20:40 +00:00
storage_ . all_micro_ops_ [ index ] . bus_program = uint16_t ( seq ( " " ) ) ;
2019-04-01 02:34:28 +00:00
}
}
2019-03-17 02:36:09 +00:00
// Install the operation and make a note of where micro-ops begin.
2019-06-19 21:00:44 +00:00
program . operation = operation ;
storage_ . instructions [ instruction ] = program ;
2019-04-30 02:37:23 +00:00
micro_op_pointers [ size_t ( instruction ) ] = size_t ( micro_op_start ) ;
2019-03-17 02:36:09 +00:00
2019-04-18 20:34:48 +00:00
// Don't search further through the list of possibilities, unless this is a debugging build,
// in which case verify there are no double mappings.
# ifndef NDEBUG
+ + hits ;
assert ( hits = = 1 ) ;
# else
2019-03-10 21:27:34 +00:00
break ;
2019-04-18 20:34:48 +00:00
# endif
2019-03-10 21:27:34 +00:00
}
2019-03-16 23:41:07 +00:00
}
2019-04-24 17:01:08 +00:00
# undef inc
# undef dec
2019-03-16 23:41:07 +00:00
}
2019-03-09 05:00:23 +00:00
2019-05-01 19:19:24 +00:00
// Throw in the interrupt program.
const auto interrupt_pointer = storage_ . all_micro_ops_ . size ( ) ;
2019-05-02 19:25:43 +00:00
2019-11-19 04:46:33 +00:00
// WORKAROUND FOR THE 68000 MAIN LOOP. Hopefully temporary.
2019-05-02 19:25:43 +00:00
op ( Action : : None , seq ( " " ) ) ;
// Perform a single write and then a cycle that will obtain an interrupt vector, or else dictate an autovector or a spurious interrupt.
2019-05-03 18:20:59 +00:00
op ( Action : : PrepareINT , seq ( " n nn nw int " , { & storage_ . precomputed_addresses_ [ 0 ] } ) ) ;
2019-05-02 19:25:43 +00:00
// The reset of the standard trap steps occur here; PrepareINT will set them up according to the vector received.
2019-05-03 18:20:59 +00:00
op ( Action : : PrepareINTVector , seq ( " nn n nw nW nV nv np np " , { & storage_ . precomputed_addresses_ [ 1 ] , & storage_ . precomputed_addresses_ [ 2 ] } ) ) ;
2019-05-02 19:25:43 +00:00
// Terminate the sequence.
2019-05-01 19:19:24 +00:00
op ( ) ;
2019-04-12 02:31:17 +00:00
# undef Dn
# undef An
# undef Ind
# undef PostDec
# undef PreDec
# undef d16An
# undef d8AnXn
# undef XXXw
# undef XXXl
# undef d16PC
# undef d8PCXn
# undef Imm
# undef bw
# undef l
# undef source_dest
2019-04-04 01:27:11 +00:00
# undef ea
# undef a
2019-03-21 03:21:02 +00:00
# undef seq
# undef op
2019-03-30 03:13:41 +00:00
# undef pseq
2019-03-21 03:21:02 +00:00
2019-05-01 19:19:24 +00:00
/*!
Iterates through the micro - sequence beginning at @ c start , finalising bus_program
pointers that have been transiently stored as relative to @ c arbitrary_base .
*/
2019-07-25 14:14:36 +00:00
// const auto link_operations = [this](MicroOp *start, BusStep *arbitrary_base) {
// while(!start->is_terminal()) {
// const auto offset = size_t(start->bus_program - arbitrary_base);
// assert(offset >= 0 && offset < storage_.all_bus_steps_.size());
// start->bus_program = &storage_.all_bus_steps_[offset];
// ++start;
// }
// };
2019-05-01 19:19:24 +00:00
2019-03-17 01:47:46 +00:00
// Finalise micro-op and program pointers.
2021-12-23 21:27:54 +00:00
int total_instructions = 0 ;
2019-03-16 23:41:07 +00:00
for ( size_t instruction = 0 ; instruction < 65536 ; + + instruction ) {
if ( micro_op_pointers [ instruction ] ! = std : : numeric_limits < size_t > : : max ( ) ) {
2019-07-25 02:02:50 +00:00
storage_ . instructions [ instruction ] . micro_operations = uint32_t ( micro_op_pointers [ instruction ] ) ;
2021-12-23 21:27:54 +00:00
+ + total_instructions ;
2019-07-25 14:14:36 +00:00
// link_operations(&storage_.all_micro_ops_[micro_op_pointers[instruction]], &arbitrary_base);
2019-03-16 23:41:07 +00:00
}
2019-03-09 05:00:23 +00:00
}
2019-04-30 02:08:16 +00:00
2019-05-01 19:19:24 +00:00
// Link up the interrupt micro ops.
storage_ . interrupt_micro_ops_ = & storage_ . all_micro_ops_ [ interrupt_pointer ] ;
2019-07-25 14:14:36 +00:00
// link_operations(storage_.interrupt_micro_ops_, &arbitrary_base);
2019-05-01 19:19:24 +00:00
2021-12-23 21:27:54 +00:00
std : : cout < < total_instructions < < " total opcodes " < < std : : endl ;
std : : cout < < storage_ . all_bus_steps_ . size ( ) < < " total bus steps; at " < < sizeof ( BusStep ) < < " bytes per bus step implies " < < storage_ . all_bus_steps_ . size ( ) * sizeof ( BusStep ) < < " bytes " < < std : : endl ;
std : : cout < < storage_ . all_micro_ops_ . size ( ) < < " total micro ops; at " < < sizeof ( MicroOp ) < < " bytes per micro-op implies " < < storage_ . all_micro_ops_ . size ( ) * sizeof ( MicroOp ) < < " bytes " < < std : : endl ;
std : : cout < < " (Microcycles being " < < sizeof ( Microcycle ) < < " bytes; ProcessorStorage being " < < sizeof ( ProcessorStorage ) < < " bytes, or " < < sizeof ( ProcessorStorage ) - sizeof ( ProcessorStorage : : instructions ) < < " bytes without the instructions table) " < < std : : endl ;
2019-03-09 05:00:23 +00:00
}
2019-03-16 23:41:07 +00:00
private :
ProcessorStorage & storage_ ;
2019-04-30 02:08:16 +00:00
2019-05-30 16:08:35 +00:00
std : : initializer_list < RegisterPair16 * > : : const_iterator replace_write_values ( BusStep * start , std : : initializer_list < RegisterPair16 * > : : const_iterator value ) {
2019-05-02 19:25:43 +00:00
while ( ! start - > is_terminal ( ) ) {
// Look for any bus step that writes. Then replace its value, and that of the cycle before it.
if ( start - > microcycle . data_select_active ( ) & & ! ( start - > microcycle . operation & Microcycle : : Read ) & & ! ( start - > microcycle . operation & Microcycle : : InterruptAcknowledge ) ) {
start [ 0 ] . microcycle . value = start [ - 1 ] . microcycle . value = * value ;
+ + value ;
}
+ + start ;
}
return value ;
}
2019-06-20 19:10:11 +00:00
struct BusStepOrderer {
2019-04-30 02:08:16 +00:00
bool operator ( ) ( BusStep const & lhs , BusStep const & rhs ) const {
int action_diff = int ( lhs . action ) - int ( rhs . action ) ;
if ( action_diff < 0 ) {
return true ;
}
if ( action_diff > 0 ) {
return false ;
}
return
std : : make_tuple ( lhs . microcycle . value , lhs . microcycle . address , lhs . microcycle . length , lhs . microcycle . operation ) <
std : : make_tuple ( rhs . microcycle . value , rhs . microcycle . address , rhs . microcycle . length , rhs . microcycle . operation ) ;
}
} ;
2019-06-20 19:10:11 +00:00
std : : map < BusStep , std : : vector < size_t > , BusStepOrderer > locations_by_bus_step_ ;
2019-03-16 23:41:07 +00:00
} ;
2019-03-09 05:00:23 +00:00
2019-03-13 02:46:31 +00:00
}
2019-03-09 05:00:23 +00:00
}
2019-03-12 02:47:58 +00:00
2019-12-15 04:52:53 +00:00
CPU : : MC68000 : : ProcessorStorage : : ProcessorStorage ( ) {
2019-03-16 23:41:07 +00:00
ProcessorStorageConstructor constructor ( * this ) ;
2019-03-13 02:46:31 +00:00
2019-03-26 02:54:49 +00:00
// Create the special programs.
2019-03-18 01:57:00 +00:00
const size_t reset_offset = constructor . assemble_program ( " n n n n n nn nF nf nV nv np np " ) ;
2019-04-07 03:21:01 +00:00
2019-03-26 02:54:49 +00:00
const size_t branch_taken_offset = constructor . assemble_program ( " n np np " ) ;
const size_t branch_byte_not_taken_offset = constructor . assemble_program ( " nn np " ) ;
const size_t branch_word_not_taken_offset = constructor . assemble_program ( " nn np np " ) ;
2019-04-16 03:20:36 +00:00
const size_t bsr_offset = constructor . assemble_program ( " np np " ) ;
2019-03-13 02:46:31 +00:00
2019-04-07 03:21:01 +00:00
const size_t dbcc_condition_true_offset = constructor . assemble_program ( " nn np np " ) ;
const size_t dbcc_condition_false_no_branch_offset = constructor . assemble_program ( " n nr np np " , { & dbcc_false_address_ } ) ;
const size_t dbcc_condition_false_branch_offset = constructor . assemble_program ( " n np np " ) ;
2019-04-22 02:54:20 +00:00
// That nr in dbcc_condition_false_no_branch_offset is to look like an np from the wrong address.
2019-04-07 03:21:01 +00:00
2019-04-15 00:02:18 +00:00
// The reads steps needs to be 32 long-word reads plus an overflow word; the writes just the long words.
2019-04-14 18:31:13 +00:00
// Addresses and data sources/targets will be filled in at runtime, so anything will do here.
std : : string movem_reads_pattern , movem_writes_pattern ;
std : : vector < uint32_t * > addresses ;
2019-04-15 00:02:18 +00:00
for ( auto c = 0 ; c < 64 ; + + c ) {
2019-04-14 18:31:13 +00:00
movem_reads_pattern + = " nr " ;
2019-04-15 00:02:18 +00:00
movem_writes_pattern + = " nw " ;
2019-04-14 18:31:13 +00:00
addresses . push_back ( nullptr ) ;
}
2019-04-15 00:02:18 +00:00
movem_reads_pattern + = " nr " ;
addresses . push_back ( nullptr ) ;
2019-06-25 21:41:13 +00:00
const size_t movem_read_offset = constructor . assemble_program ( movem_reads_pattern . c_str ( ) , addresses ) ;
const size_t movem_write_offset = constructor . assemble_program ( movem_writes_pattern . c_str ( ) , addresses ) ;
2019-04-18 02:21:56 +00:00
// Target addresses and values will be filled in by TRAP/illegal too.
2019-04-28 19:47:21 +00:00
const size_t trap_offset = constructor . assemble_program ( " r nw nw nW nV nv np np " , { & precomputed_addresses_ [ 0 ] , & precomputed_addresses_ [ 1 ] , & precomputed_addresses_ [ 2 ] } ) ;
2019-04-30 23:24:22 +00:00
const size_t bus_error_offset =
constructor . assemble_program (
" nn nw nw nW nw nw nw nW nV nv np np " ,
{
& precomputed_addresses_ [ 0 ] ,
& precomputed_addresses_ [ 1 ] ,
& precomputed_addresses_ [ 2 ] ,
& precomputed_addresses_ [ 3 ] ,
& precomputed_addresses_ [ 4 ] ,
& precomputed_addresses_ [ 5 ] ,
& precomputed_addresses_ [ 6 ]
}
) ;
2019-04-14 18:31:13 +00:00
2019-04-29 20:11:01 +00:00
// Chuck in the proper micro-ops for handling an exception.
2019-04-30 23:24:22 +00:00
const auto short_exception_offset = all_micro_ops_ . size ( ) ;
all_micro_ops_ . emplace_back ( ProcessorBase : : MicroOp : : Action : : None ) ;
all_micro_ops_ . emplace_back ( ) ;
const auto long_exception_offset = all_micro_ops_ . size ( ) ;
2019-04-29 20:11:01 +00:00
all_micro_ops_ . emplace_back ( ProcessorBase : : MicroOp : : Action : : None ) ;
all_micro_ops_ . emplace_back ( ) ;
2019-03-16 23:41:07 +00:00
// Install operations.
2019-06-20 19:10:11 +00:00
//#ifndef NDEBUG
2019-04-30 02:08:16 +00:00
const std : : clock_t start = std : : clock ( ) ;
2019-06-20 19:10:11 +00:00
//#endif
2019-03-17 01:47:46 +00:00
constructor . install_instructions ( ) ;
2019-06-20 19:10:11 +00:00
//#ifndef NDEBUG
2019-04-30 02:08:16 +00:00
std : : cout < < " Construction took " < < double ( std : : clock ( ) - start ) / double ( CLOCKS_PER_SEC / 1000 ) < < " ms " < < std : : endl ;
2019-06-20 19:10:11 +00:00
//#endif
2019-03-13 02:46:31 +00:00
2019-03-26 02:54:49 +00:00
// Realise the special programs as direct pointers.
reset_bus_steps_ = & all_bus_steps_ [ reset_offset ] ;
2019-04-07 03:21:01 +00:00
2019-03-26 02:54:49 +00:00
branch_taken_bus_steps_ = & all_bus_steps_ [ branch_taken_offset ] ;
branch_byte_not_taken_bus_steps_ = & all_bus_steps_ [ branch_byte_not_taken_offset ] ;
branch_word_not_taken_bus_steps_ = & all_bus_steps_ [ branch_word_not_taken_offset ] ;
2019-04-16 03:20:36 +00:00
bsr_bus_steps_ = & all_bus_steps_ [ bsr_offset ] ;
2019-03-14 01:08:13 +00:00
2019-04-07 03:21:01 +00:00
dbcc_condition_true_steps_ = & all_bus_steps_ [ dbcc_condition_true_offset ] ;
dbcc_condition_false_no_branch_steps_ = & all_bus_steps_ [ dbcc_condition_false_no_branch_offset ] ;
2019-04-22 02:54:20 +00:00
dbcc_condition_false_no_branch_steps_ [ 1 ] . microcycle . operation | = Microcycle : : IsProgram ;
dbcc_condition_false_no_branch_steps_ [ 2 ] . microcycle . operation | = Microcycle : : IsProgram ;
2019-04-07 03:21:01 +00:00
dbcc_condition_false_branch_steps_ = & all_bus_steps_ [ dbcc_condition_false_branch_offset ] ;
2019-04-18 02:21:56 +00:00
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 ] ;
2020-05-19 03:55:54 +00:00
constructor . replace_write_values ( trap_steps_ , { & program_counter_ . halves . low , & destination_bus_data_ . halves . low , & program_counter_ . halves . high } ) ;
2019-05-02 19:25:43 +00:00
// Fill in the same order of writes for the interrupt micro-ops, though it divides the work differently.
2020-05-19 03:55:54 +00:00
constructor . replace_write_values ( interrupt_micro_ops_ , { & program_counter_ . halves . low , & destination_bus_data_ . halves . low , & program_counter_ . halves . high } ) ;
2019-04-14 18:31:13 +00:00
2019-04-30 23:24:22 +00:00
// Link the bus error exception steps and fill in the proper sources.
bus_error_steps_ = & all_bus_steps_ [ bus_error_offset ] ;
2019-05-02 19:25:43 +00:00
constructor . replace_write_values ( bus_error_steps_ , {
& program_counter_ . halves . low ,
2020-05-19 03:55:54 +00:00
& destination_bus_data_ . halves . low ,
2019-05-02 19:25:43 +00:00
& program_counter_ . halves . high ,
& decoded_instruction_ ,
2020-01-05 04:22:07 +00:00
& effective_address_ [ 1 ] . halves . low ,
2020-05-19 03:55:54 +00:00
& destination_bus_data_ . halves . high ,
2020-01-05 04:22:07 +00:00
& effective_address_ [ 1 ] . halves . high
2019-05-02 19:25:43 +00:00
} ) ;
2019-04-30 23:24:22 +00:00
2019-04-19 00:50:58 +00:00
// Also relink the RTE and RTR bus steps to collect the program counter.
//
// Assumed order of input: PC.h, SR, PC.l (i.e. the opposite of TRAP's output).
for ( const int instruction : { 0x4e73 , 0x4e77 } ) {
2019-07-25 14:14:36 +00:00
auto steps = & all_bus_steps_ [ all_micro_ops_ [ instructions [ instruction ] . micro_operations ] . bus_program ] ;
2019-04-19 00:50:58 +00:00
steps [ 0 ] . microcycle . value = steps [ 1 ] . microcycle . value = & program_counter_ . halves . high ;
steps [ 4 ] . microcycle . value = steps [ 5 ] . microcycle . value = & program_counter_ . halves . low ;
}
2019-04-30 23:24:22 +00:00
// Setup the stop cycle.
stop_cycle_ . length = HalfCycles ( 2 ) ;
2019-04-29 20:11:01 +00:00
// Complete linkage of the exception micro program.
2019-04-30 23:24:22 +00:00
short_exception_micro_ops_ = & all_micro_ops_ [ short_exception_offset ] ;
2019-07-27 03:20:40 +00:00
short_exception_micro_ops_ - > bus_program = uint16_t ( trap_offset ) ;
2019-04-30 23:24:22 +00:00
long_exception_micro_ops_ = & all_micro_ops_ [ long_exception_offset ] ;
2019-07-27 03:20:40 +00:00
long_exception_micro_ops_ - > bus_program = uint16_t ( bus_error_offset ) ;
2019-04-29 20:11:01 +00:00
2019-04-29 17:45:53 +00:00
// Set initial state.
2019-03-26 02:54:49 +00:00
active_step_ = reset_bus_steps_ ;
2019-03-19 02:51:32 +00:00
effective_address_ [ 0 ] = 0 ;
2019-03-16 23:41:07 +00:00
is_supervisor_ = 1 ;
2019-04-24 13:59:54 +00:00
interrupt_level_ = 7 ;
address_ [ 7 ] = 0x00030000 ;
2019-03-12 02:47:58 +00:00
}
2019-03-18 01:57:00 +00:00
void CPU : : MC68000 : : ProcessorStorage : : write_back_stack_pointer ( ) {
stack_pointers_ [ is_supervisor_ ] = address_ [ 7 ] ;
}
void CPU : : MC68000 : : ProcessorStorage : : set_is_supervisor ( bool is_supervisor ) {
const int new_is_supervisor = is_supervisor ? 1 : 0 ;
if ( new_is_supervisor ! = is_supervisor_ ) {
stack_pointers_ [ is_supervisor_ ] = address_ [ 7 ] ;
is_supervisor_ = new_is_supervisor ;
address_ [ 7 ] = stack_pointers_ [ is_supervisor_ ] ;
}
}