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-03-31 03:11:39 +00:00
# include <sstream>
2019-03-13 02:46:31 +00:00
2019-03-16 23:41:07 +00:00
namespace CPU {
namespace MC68000 {
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 ) {
default : return 0 ;
case 0x12 : return int ( Action : : CalcD16PC ) ; // (d16, PC)
case 0x13 : return int ( Action : : CalcD8PCXn ) ; // (d8, PC, Xn)
case 0x05 : return int ( Action : : CalcD16An ) ; // (d16, An)
case 0x06 : return int ( Action : : CalcD8AnXn ) ; // (d8, An, Xn)
}
}
2019-03-25 03:05:57 +00:00
int combined_mode ( int mode , int reg ) {
return ( mode = = 7 ) ? ( 0x10 | reg ) : mode ;
}
2019-03-31 03:11:39 +00:00
# define pseq(x, m) ((((m)&0xff) == 0x06) || (((m)&0xff) == 0x13) ? "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 ;
* 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 ;
* nS : push the MSW of something onto the stack ;
* ns : push the LSW of something onto the stack ;
* 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-04-01 01:13:26 +00:00
* nF : fetch the SSPs MSW ;
* nf : fetch the SSP ' s LSW ;
* _ : hold the reset line active for the usual period .
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 .
p fetches will fill the prefetch queue , attaching an action to both the
step that precedes them and to themselves . The SSP fetches will go straight
to the SSP .
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-03-31 03:11:39 +00:00
size_t assemble_program ( std : : string 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
std : : stringstream stream ( access_pattern ) ;
2019-03-17 01:47:46 +00:00
2019-03-31 03:11:39 +00:00
// Tokenise the access pattern by splitting on spaces.
std : : string token ;
while ( stream > > token ) {
2019-03-16 23:41:07 +00:00
ProcessorBase : : BusStep step ;
2019-03-31 03:11:39 +00:00
// Do nothing (possibly twice).
if ( token = = " n " | | token = = " nn " ) {
steps . push_back ( step ) ;
if ( token . size ( ) = = 2 ) {
2019-03-30 03:40:54 +00:00
steps . push_back ( step ) ;
2019-03-31 03:11:39 +00:00
}
continue ;
}
// Fetch SSP.
if ( token = = " nF " | | token = = " nf " ) {
step . microcycle . length = HalfCycles ( 5 ) ;
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 ( token [ 1 ] ) ? & storage_ . stack_pointers_ [ 1 ] . halves . high : & storage_ . stack_pointers_ [ 1 ] . halves . low ;
steps . push_back ( step ) ;
step . microcycle . length = HalfCycles ( 3 ) ;
step . microcycle . operation = Microcycle : : SelectWord | Microcycle : : Read | Microcycle : : IsProgram ;
step . action = Action : : IncrementEffectiveAddress0 ;
steps . push_back ( step ) ;
continue ;
}
// Fetch exception vector.
if ( token = = " nV " | | token = = " nv " ) {
step . microcycle . length = HalfCycles ( 5 ) ;
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 ( token [ 1 ] ) ? & storage_ . program_counter_ . halves . high : & storage_ . program_counter_ . halves . low ;
steps . push_back ( step ) ;
2019-03-30 03:40:54 +00:00
2019-03-31 03:11:39 +00:00
step . microcycle . length = HalfCycles ( 3 ) ;
step . microcycle . operation | = Microcycle : : SelectWord | Microcycle : : Read | Microcycle : : IsProgram ;
step . action = Action : : IncrementEffectiveAddress0 ;
steps . push_back ( step ) ;
continue ;
2019-03-16 23:41:07 +00:00
}
2019-03-31 03:11:39 +00:00
// Fetch from the program counter into the prefetch queue.
if ( token = = " np " ) {
step . microcycle . length = HalfCycles ( 5 ) ;
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 ) ;
step . microcycle . length = HalfCycles ( 3 ) ;
step . microcycle . operation | = Microcycle : : SelectWord | Microcycle : : Read | Microcycle : : IsProgram ;
step . action = Action : : IncrementProgramCounter ;
steps . push_back ( step ) ;
continue ;
}
// The reset cycle.
if ( token = = " _ " ) {
step . microcycle . length = HalfCycles ( 248 ) ;
step . microcycle . operation = Microcycle : : Reset ;
steps . push_back ( step ) ;
continue ;
}
// A standard read or write.
2019-04-01 01:13:26 +00:00
if ( token = = " nR " | | token = = " nr " | | token = = " nW " | | token = = " nw " | | token = = " nRd " | | token = = " nrd " ) {
const bool is_read = tolower ( token [ 1 ] ) = = ' r ' ;
const bool use_source_storage = is_read & & token . size ( ) ! = 3 ;
RegisterPair32 * scratch_data = use_source_storage ? & storage_ . source_bus_data_ [ 0 ] : & storage_ . destination_bus_data_ [ 0 ] ;
2019-03-31 03:11:39 +00:00
step . microcycle . length = HalfCycles ( 5 ) ;
step . microcycle . operation = Microcycle : : NewAddress | ( is_read ? Microcycle : : Read : 0 ) ;
step . microcycle . address = * address_iterator ;
2019-04-01 01:13:26 +00:00
step . microcycle . value = isupper ( token [ 1 ] ) ? & scratch_data - > halves . high : & scratch_data - > halves . low ;
2019-03-31 03:11:39 +00:00
steps . push_back ( step ) ;
step . microcycle . length = HalfCycles ( 3 ) ;
step . microcycle . operation | = ( read_full_words ? Microcycle : : SelectWord : Microcycle : : SelectByte ) | ( is_read ? Microcycle : : Read : 0 ) ;
if ( token [ 1 ] = = ' R ' ) {
step . action = Action : : IncrementEffectiveAddress0 ;
}
if ( token [ 1 ] = = ' W ' ) {
step . action = Action : : IncrementEffectiveAddress1 ;
}
steps . push_back ( step ) ;
2019-04-01 01:13:26 +00:00
if ( ! isupper ( token [ 1 ] ) ) {
2019-03-31 03:11:39 +00:00
+ + address_iterator ;
}
continue ;
}
std : : cerr < < " MC68000 program builder; Unknown access token " < < token < < std : : endl ;
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.
const auto position = std : : search ( storage_ . all_bus_steps_ . begin ( ) , storage_ . all_bus_steps_ . end ( ) , steps . begin ( ) , steps . end ( ) ) ;
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-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_ ) ) ;
return start ;
2019-03-16 23:41:07 +00:00
}
2019-03-10 21:27:34 +00:00
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 {
Decimal ,
2019-03-30 03:13:41 +00:00
MOVE , // twelve lowest bits are register, mode, mode, register, for destination and source respectively.
2019-03-25 03:05:57 +00:00
MOVEtoSR , // six lowest bits are [mode, register], decoding to MOVE SR
CMPI , // eight lowest bits are [size, mode, register], decoding to CMPI
2019-03-26 02:54:49 +00:00
BRA , // eight lowest bits are ignored, and an 'n np np' is scheduled
Bcc , // twelve lowest bits are ignored, only a PerformAction is scheduled
2019-03-27 02:07:28 +00:00
LEA , // decodes register, mode, register
2019-03-30 03:13:41 +00:00
MOVEq , // decodes just a destination register
2019-04-01 01:13:26 +00:00
RESET , // no further decoding applied, performs reset cycle
JMP , // six lowest bits are [mode, register], decoding to JMP
2019-04-03 01:50:58 +00:00
ADDSUB ,
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 .
*/
const std : : vector < PatternMapping > mappings = {
{ 0xf1f0 , 0x8100 , Operation : : SBCD , Decoder : : Decimal } , // 4-171 (p275)
{ 0xf1f0 , 0xc100 , Operation : : ABCD , Decoder : : Decimal } , // 4-3 (p107)
2019-03-28 01:26:04 +00:00
// {0xf000, 0x8000, Operation::OR, Decoder::RegOpModeReg}, // 4-150 (p226)
// {0xf000, 0xb000, Operation::EOR, Decoder::RegOpModeReg}, // 4-100 (p204)
// {0xf000, 0xc000, Operation::AND, Decoder::RegOpModeReg}, // 4-15 (p119)
2019-03-16 23:41:07 +00:00
2019-03-28 01:26:04 +00:00
// {0xff00, 0x0600, Operation::ADD, Decoder::SizeModeRegisterImmediate}, // 4-9 (p113)
2019-03-16 23:41:07 +00:00
2019-03-28 01:26:04 +00:00
// {0xff00, 0x0600, Operation::ADD, Decoder::DataSizeModeQuick}, // 4-11 (p115)
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
{ 0xffc0 , 0x46c0 , Operation : : MOVEtoSR , Decoder : : MOVEtoSR } , // 6-19 (p473)
2019-03-25 03:05:57 +00:00
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)
{ 0xff00 , 0x6000 , Operation : : BRA , Decoder : : BRA } , // 4-55 (p159)
{ 0xf000 , 0x6000 , Operation : : Bcc , Decoder : : Bcc } , // 4-25 (p129)
2019-03-27 02:07:28 +00:00
{ 0xf1c0 , 0x41c0 , Operation : : MOVEAl , Decoder : : LEA } , // 4-110 (p214)
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-03 01:50:58 +00:00
{ 0xf0c0 , 0x9000 , Operation : : SUBb , Decoder : : ADDSUB } , // 4-174 (p278)
{ 0xf0c0 , 0x9040 , Operation : : SUBw , Decoder : : ADDSUB } , // 4-174 (p278)
{ 0xf0c0 , 0x9080 , Operation : : SUBl , Decoder : : ADDSUB } , // 4-174 (p278)
{ 0xf0c0 , 0xd000 , Operation : : ADDb , Decoder : : ADDSUB } , // 4-4 (p108)
{ 0xf0c0 , 0xd040 , Operation : : ADDw , Decoder : : ADDSUB } , // 4-4 (p108)
{ 0xf0c0 , 0xd080 , Operation : : ADDl , Decoder : : ADDSUB } , // 4-4 (p108)
// {0xf1c0, 0xd0c0, Operation::ADDAw, Decoder::ADDSUB}, // 4-7 (p111)
// {0xf1c0, 0xd1c0, Operation::ADDAl, Decoder::ADDSUB}, // 4-7 (p111)
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.
BusStep arbitrary_base ;
2019-03-21 03:21:02 +00:00
# define op(...) storage_.all_micro_ops_.emplace_back(__VA_ARGS__)
# define seq(...) &arbitrary_base + assemble_program(__VA_ARGS__)
2019-03-16 23:41:07 +00:00
// Perform a linear search of the mappings above for this instruction.
for ( size_t instruction = 0 ; instruction < 65536 ; + + instruction ) {
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-03-25 03:05:57 +00:00
// The following fields are used commonly enough to be worht pulling out here.
const int source_register = instruction & 7 ;
const int source_mode = ( instruction > > 3 ) & 7 ;
2019-03-16 23:41:07 +00:00
switch ( mapping . decoder ) {
2019-04-03 01:50:58 +00:00
case Decoder : : ADDSUB : {
// 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 ) ;
const int data_register = ( instruction > > 9 ) & 7 ;
const int mode = combined_mode ( source_mode , source_register ) ;
const bool is_byte_access = ! ! ( ( instruction > > 6 ) & 3 ) ;
const bool is_long_word_access = ( ( instruction > > 6 ) & 3 ) = = 2 ;
if ( reverse_source_destination ) {
storage_ . instructions [ instruction ] . destination = & storage_ . data_ [ data_register ] ;
storage_ . instructions [ instruction ] . source = & storage_ . source_bus_data_ [ 0 ] ;
storage_ . instructions [ instruction ] . source_address = & storage_ . address_ [ source_register ] ;
// Perform [ADD/SUB].blw <ea>, Dn
switch ( mode | ( is_long_word_access ? 0x100 : 0x000 ) ) {
default : continue ;
case 0x000 : // ADD/SUB.bw Dn, Dn
storage_ . instructions [ instruction ] . source = & storage_ . data_ [ source_register ] ;
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
case 0x100 : // ADD/SUB.l Dn, Dn
storage_ . instructions [ instruction ] . source = & storage_ . data_ [ source_register ] ;
op ( Action : : PerformOperation , seq ( " np nn " ) ) ;
break ;
case 0x001 : // ADD/SUB.bw An, Dn
storage_ . instructions [ instruction ] . source = & storage_ . address_ [ source_register ] ;
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
case 0x101 : // ADD/SUB.l An, Dn
storage_ . instructions [ instruction ] . source = & storage_ . address_ [ source_register ] ;
op ( Action : : PerformOperation , seq ( " np nn " ) ) ;
break ;
case 0x002 : // ADD/SUB.bw (An), Dn
case 0x003 : // ADD/SUB.bw (An)+, Dn
op ( Action : : None , seq ( " nr np " , { & storage_ . address_ [ source_register ] . full } , ! is_byte_access ) ) ;
if ( mode = = 0x03 ) {
op ( int ( is_byte_access ? Action : : Increment1 : Action : : Increment2 ) | MicroOp : : SourceMask ) ;
}
op ( Action : : PerformOperation ) ;
break ;
case 0x102 : // ADD/SUB.l (An), Dn
case 0x103 : // ADD/SUB.l (An)+, Dn
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask , seq ( " nR nr np n " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
if ( mode = = 0x03 ) {
op ( int ( Action : : Increment4 ) | MicroOp : : SourceMask ) ;
}
op ( Action : : PerformOperation ) ;
break ;
case 0x004 : // ADD/SUB.bw -(An), Dn
op ( int ( is_byte_access ? Action : : Decrement1 : Action : : Decrement2 ) | MicroOp : : SourceMask ,
seq ( " n nr np " , { & storage_ . address_ [ source_register ] . full } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x104 : // ADD/SUB.l -(An), Dn
op ( int ( Action : : Decrement4 ) | MicroOp : : SourceMask ,
seq ( " n nR nr np n " , { & storage_ . address_ [ source_register ] . full } ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x010 : // ADD/SUB.bw (xxx).w, Dn
op ( int ( Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np nr np " , { & storage_ . effective_address_ [ 0 ] . full } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x110 : // ADD/SUB.l (xxx).w, Dn
op ( int ( Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np nR nr np n " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x011 : // ADD/SUB.bw (xxx).l, Dn
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np nr np " , { & storage_ . effective_address_ [ 0 ] . full } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x111 : // ADD/SUB.l (xxx).l, Dn
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np nR nr np n " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x012 : // ADD/SUB.bw (d16, PC), Dn
case 0x013 : // ADD/SUB.bw (d8, PC, Xn), Dn
case 0x005 : // ADD/SUB.bw (d16, An), Dn
case 0x006 : // ADD/SUB.bw (d8, An, Xn), Dn
op ( calc_action_for_mode ( mode ) | MicroOp : : SourceMask ,
seq ( pseq ( " np nr np " , mode ) , { & storage_ . effective_address_ [ 0 ] . full } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x112 : // ADD/SUB.l (d16, PC), Dn
case 0x113 : // ADD/SUB.l (d8, PC, Xn), Dn
case 0x105 : // ADD/SUB.l (d16, An), Dn
case 0x106 : // ADD/SUB.l (d8, An, Xn), Dn
op ( calc_action_for_mode ( mode ) | MicroOp : : SourceMask ,
seq ( pseq ( " np nR nr np n " , mode ) , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x014 : // ADD/SUB.bw #, Dn
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x114 : // ADD/SUB.l #, Dn
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np nn " ) ) ;
op ( Action : : PerformOperation ) ;
break ;
}
} else {
storage_ . instructions [ instruction ] . source = & storage_ . data_ [ data_register ] ;
storage_ . instructions [ instruction ] . destination = & storage_ . destination_bus_data_ [ 0 ] ;
storage_ . instructions [ instruction ] . destination_address = & storage_ . address_ [ source_register ] ;
// Perform [ADD/SUB].blw Dn, <ea>
switch ( mode | ( is_long_word_access ? 0x100 : 0x000 ) ) {
default : continue ;
case 0x002 : // ADD/SUB.bw Dn, (An)
case 0x003 : // ADD/SUB.bw Dn, (An)+
op ( Action : : None , seq ( " nr np " , { & storage_ . address_ [ source_register ] . full } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " nw " , { & storage_ . address_ [ source_register ] . full } , ! is_byte_access ) ) ;
if ( mode = = 0x03 ) {
op ( int ( is_byte_access ? Action : : Increment1 : Action : : Increment2 ) | MicroOp : : DestinationMask ) ;
}
break ;
case 0x102 : // ADD/SUB.l Dn, (An)
case 0x103 : // ADD/SUB.l Dn, (An)+
op ( Action : : None , seq ( " nR nr np " , { & storage_ . address_ [ source_register ] . full } ) ) ;
op ( Action : : PerformOperation , seq ( " nw nW " , { & storage_ . address_ [ source_register ] . full } ) ) ;
if ( mode = = 0x03 ) {
op ( int ( Action : : Increment4 ) | MicroOp : : DestinationMask ) ;
}
break ;
case 0x004 : // ADD/SUB.bw Dn, -(An)
// op( int(is_byte_access ? Action::Decrement1 : Action::Decrement2) | MicroOp::SourceMask,
// seq("n nr np", { &storage_.address_[source_register].full }, !is_byte_access));
// op(Action::PerformOperation);
continue ;
case 0x104 : // ADD/SUB.l Dn, -(An)
// op( int(Action::Decrement4) | MicroOp::SourceMask,
// seq("n nR nr np n", { &storage_.address_[source_register].full }));
// op(Action::PerformOperation);
continue ;
case 0x010 : // ADD/SUB.bw Dn, (xxx).w
// op( int(Action::AssembleWordAddressFromPrefetch) | MicroOp::SourceMask,
// seq("np nr np", { &storage_.effective_address_[0].full }, !is_byte_access));
// op(Action::PerformOperation);
continue ;
case 0x110 : // ADD/SUB.l Dn, (xxx).w
// op( int(Action::AssembleWordAddressFromPrefetch) | MicroOp::SourceMask,
// seq("np nR nr np n", { &storage_.effective_address_[0].full }));
// op(Action::PerformOperation);
continue ;
case 0x011 : // ADD/SUB.bw Dn, (xxx).l
// op(Action::None, seq("np"));
// op( int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::SourceMask,
// seq("np nr np", { &storage_.effective_address_[0].full }, !is_byte_access));
// op(Action::PerformOperation);
continue ;
case 0x111 : // ADD/SUB.l Dn, (xxx).l
// op(Action::None, seq("np"));
// op( int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::SourceMask,
// seq("np nR nr np n", { &storage_.effective_address_[0].full }));
// op(Action::PerformOperation);
continue ;
case 0x005 : // ADD/SUB.bw (d16, An), Dn
case 0x006 : // ADD/SUB.bw (d8, An, Xn), Dn
// op( calc_action_for_mode(mode) | MicroOp::SourceMask,
// seq(pseq("np nr np", mode), { &storage_.effective_address_[0].full }, !is_byte_access));
// op(Action::PerformOperation);
continue ;
case 0x105 : // ADD/SUB.l (d16, An), Dn
case 0x106 : // ADD/SUB.l (d8, An, Xn), Dn
// op( calc_action_for_mode(mode) | MicroOp::SourceMask,
// seq(pseq("np nR nr np n", mode), { &storage_.effective_address_[0].full }));
// op(Action::PerformOperation);
continue ;
}
}
} break ;
2019-03-26 02:54:49 +00:00
// This decoder actually decodes nothing; it just schedules a PerformOperation followed by an empty step.
case Decoder : : Bcc : {
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-03-17 03:14:18 +00:00
// Decodes the format used by ABCD and SBCD.
2019-03-16 23:41:07 +00:00
case Decoder : : Decimal : {
2019-04-03 01:50:58 +00:00
const int destination_register = ( instruction > > 9 ) & 7 ;
2019-03-16 23:41:07 +00:00
if ( instruction & 8 ) {
2019-04-01 01:13:26 +00:00
storage_ . instructions [ instruction ] . source = & storage_ . source_bus_data_ [ 0 ] ;
storage_ . instructions [ instruction ] . destination = & storage_ . destination_bus_data_ [ 0 ] ;
2019-04-03 01:50:58 +00:00
storage_ . instructions [ instruction ] . source_address = & storage_ . address_ [ source_register ] ;
storage_ . instructions [ instruction ] . destination_address = & storage_ . address_ [ destination_register ] ;
2019-03-16 23:41:07 +00:00
2019-03-21 03:21:02 +00:00
op ( int ( Action : : Decrement1 ) | MicroOp : : SourceMask | MicroOp : : DestinationMask ,
2019-04-03 01:50:58 +00:00
seq ( " n nr nr np nw " , { & storage_ . address_ [ source_register ] . full , & storage_ . address_ [ destination_register ] . full , & storage_ . address_ [ destination_register ] . full } , false ) ) ;
2019-03-21 03:21:02 +00:00
op ( Action : : PerformOperation ) ;
2019-03-16 23:41:07 +00:00
} else {
2019-04-03 01:50:58 +00:00
storage_ . instructions [ instruction ] . source = & storage_ . data_ [ source_register ] ;
storage_ . instructions [ instruction ] . destination = & storage_ . data_ [ destination_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-03-25 03:05:57 +00:00
case Decoder : : CMPI : {
if ( source_mode = = 1 ) continue ;
2019-03-24 22:20:54 +00:00
2019-03-25 03:05:57 +00:00
const auto destination_mode = source_mode ;
const auto destination_register = source_register ;
2019-04-01 01:13:26 +00:00
storage_ . instructions [ instruction ] . source = & storage_ . source_bus_data_ [ 0 ] ;
2019-03-25 03:05:57 +00:00
storage_ . instructions [ instruction ] . set_destination ( storage_ , destination_mode , destination_register ) ;
const bool is_byte_access = mapping . operation = = Operation : : CMPb ;
const bool is_long_word_access = mapping . operation = = Operation : : CMPl ;
const int mode = ( is_long_word_access ? 0x100 : 0 ) | combined_mode ( destination_mode , destination_register ) ;
switch ( mode ) {
case 0x000 : // CMPI.bw #, Dn
2019-03-30 03:40:54 +00:00
storage_ . instructions [ instruction ] . source = & 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-03-25 03:05:57 +00:00
case 0x100 : // CMPI.l #, Dn
2019-03-30 03:40:54 +00:00
storage_ . instructions [ instruction ] . source = & 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-03-25 03:05:57 +00:00
case 0x002 : // CMPI.bw #, (An)
case 0x003 : // CMPI.bw #, (An)+
2019-04-01 01:13:26 +00:00
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np nrd np " , { & storage_ . address_ [ destination_register ] . full } , ! is_byte_access ) ) ;
2019-04-03 01:50:58 +00:00
if ( mode = = 0x03 ) {
2019-03-25 03:05:57 +00:00
op ( int ( is_byte_access ? Action : : Increment1 : Action : : Increment2 ) | MicroOp : : DestinationMask ) ;
}
op ( Action : : PerformOperation ) ;
break ;
case 0x102 : // CMPI.l #, (An)
case 0x103 : // CMPI.l #, (An)+
2019-03-30 03:13:41 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
2019-04-01 01:13:26 +00:00
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np nRd nrd np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
2019-03-25 03:05:57 +00:00
if ( mode = = 0x103 ) {
op ( int ( Action : : Increment4 ) | MicroOp : : DestinationMask ) ;
}
op ( Action : : PerformOperation ) ;
break ;
case 0x004 : // CMPI.bw #, -(An)
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np n " ) ) ;
2019-04-01 01:13:26 +00:00
op ( int ( is_byte_access ? Action : : Decrement1 : Action : : Decrement1 ) | MicroOp : : DestinationMask , seq ( " nrd np " , { & storage_ . address_ [ destination_register ] . full } ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
case 0x104 : // CMPI.l #, -(An)
op ( int ( Action : : Decrement4 ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np n " ) ) ;
2019-04-01 01:13:26 +00:00
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " nRd nrd np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
case 0x012 : // CMPI.bw #, (d16, PC)
case 0x013 : // CMPI.bw #, (d8, PC, Xn)
case 0x005 : // CMPI.bw #, (d16, An)
case 0x006 : // CMPI.bw #, (d8, An, Xn)
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
2019-03-27 02:07:28 +00:00
op ( calc_action_for_mode ( mode ) | MicroOp : : DestinationMask ,
2019-04-01 01:13:26 +00:00
seq ( pseq ( " nrd np " , mode ) , { & storage_ . effective_address_ [ 1 ] . full } , ! is_byte_access ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
case 0x112 : // CMPI.l #, (d16, PC)
case 0x113 : // CMPI.l #, (d8, PC, Xn)
case 0x105 : // CMPI.l #, (d16, An)
case 0x106 : // 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-01 01:13:26 +00:00
seq ( pseq ( " np nRd nrd np " , mode ) , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
case 0x010 : // CMPI.bw #, (xxx).w
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np " ) ) ;
2019-04-01 01:13:26 +00:00
op ( int ( Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np nrd np " , { & storage_ . effective_address_ [ 1 ] . full } , ! is_byte_access ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
2019-03-24 22:20:54 +00:00
break ;
2019-03-25 03:05:57 +00:00
case 0x110 : // CMPI.l #, (xxx).w
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
2019-04-01 01:13:26 +00:00
op ( int ( Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " nRd nrd np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
case 0x011 : // CMPI.bw #, (xxx).l
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
2019-04-01 01:13:26 +00:00
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np nrd np " , { & storage_ . effective_address_ [ 1 ] . full } , ! is_byte_access ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
case 0x111 : // CMPI.l #, (xxx).l
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
2019-04-01 01:13:26 +00:00
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np nRd nrd np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
2019-03-25 03:05:57 +00:00
op ( Action : : PerformOperation ) ;
break ;
default : continue ;
2019-03-24 22:20:54 +00:00
}
2019-03-25 03:05:57 +00:00
} break ;
2019-04-01 01:13:26 +00:00
case Decoder : : JMP : {
storage_ . instructions [ instruction ] . source = & storage_ . effective_address_ [ 0 ] ;
const int mode = combined_mode ( source_mode , source_register ) ;
switch ( mode ) {
default : continue ;
case 0x02 : // JMP (An)
storage_ . instructions [ instruction ] . source = & storage_ . address_ [ source_register ] ;
op ( Action : : PerformOperation , seq ( " np np " ) ) ;
break ;
case 0x12 : // JMP (d16, PC)
case 0x05 : // JMP (d16, An)
op ( calc_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( " n np np " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x13 : // JMP (d8, PC, Xn)
case 0x06 : // JMP (d8, An, Xn)
op ( calc_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( " n nn np np " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x10 : // JMP (xxx).W
op ( int ( MicroOp : : Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : SourceMask ) ;
op ( Action : : PerformOperation , seq ( " n np np " ) ) ;
break ;
case 0x11 : // JMP (xxx).L
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( MicroOp : : Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : SourceMask ) ;
op ( Action : : PerformOperation , seq ( " np np " ) ) ;
break ;
}
} break ;
2019-03-27 02:07:28 +00:00
case Decoder : : LEA : {
const int destination_register = ( instruction > > 9 ) & 7 ;
storage_ . instructions [ instruction ] . destination = & storage_ . address_ [ destination_register ] ;
const int mode = combined_mode ( source_mode , source_register ) ;
switch ( mode ) {
default : continue ;
case 0x04 :
storage_ . instructions [ instruction ] . source = & storage_ . address_ [ source_register ] ;
break ;
case 0x05 : case 0x06 : case 0x10 :
case 0x11 : case 0x12 : case 0x13 :
storage_ . instructions [ instruction ] . source = & storage_ . effective_address_ [ 0 ] ;
break ;
}
switch ( mode ) {
default : break ;
case 0x04 : // LEA (An), An (i.e. MOVEA)
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
case 0x05 : // LEA (d16, An), An
case 0x12 : // LEA (d16, PC), SR
op ( calc_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x06 : // LEA (d8, An, Xn), SR
case 0x13 : // LEA (d8, PC, Xn), SR
op ( calc_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( " n np n np " ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x10 : // LEA (xxx).W, An
op ( int ( MicroOp : : Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x11 : // LEA (xxx).L, An
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( MicroOp : : Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : SourceMask , seq ( " np np " ) ) ;
op ( Action : : PerformOperation ) ;
break ;
}
} break ;
2019-03-25 03:05:57 +00:00
case Decoder : : MOVEtoSR : {
if ( source_mode = = 1 ) continue ;
storage_ . instructions [ instruction ] . set_source ( storage_ , source_mode , source_register ) ;
2019-03-30 03:40:54 +00:00
storage_ . instructions [ instruction ] . requires_supervisor = true ;
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-03-25 03:05:57 +00:00
const int mode = combined_mode ( source_mode , source_register ) ;
switch ( mode ) {
2019-03-24 22:20:54 +00:00
case 0x00 : // MOVE Dn, SR
op ( Action : : PerformOperation , seq ( " nn np " ) ) ;
break ;
case 0x02 : // MOVE (An), SR
case 0x03 : // MOVE (An)+, SR
op ( Action : : None , seq ( " nr nn nn np " , { & storage_ . address_ [ source_register ] . full } ) ) ;
2019-04-03 01:50:58 +00:00
if ( source_mode = = 0x03 ) {
2019-03-24 22:20:54 +00:00
op ( int ( Action : : Increment2 ) | MicroOp : : SourceMask ) ;
}
op ( Action : : PerformOperation ) ;
break ;
case 0x04 : // MOVE -(An), SR
op ( Action : : Decrement2 , seq ( " n nr nn nn np " , { & storage_ . address_ [ source_register ] . full } ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x12 : // MOVE (d16, PC), SR
case 0x13 : // MOVE (d8, PC, Xn), SR
case 0x05 : // MOVE (d16, An), SR
case 0x06 : // MOVE (d8, An, Xn), SR
2019-03-30 03:13:41 +00:00
op ( calc_action_for_mode ( mode ) | MicroOp : : SourceMask , seq ( pseq ( " np nr nn nn np " , mode ) , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
2019-03-24 22:20:54 +00:00
op ( Action : : PerformOperation ) ;
break ;
case 0x10 : // MOVE (xxx).W, SR
op (
2019-03-25 03:05:57 +00:00
int ( MicroOp : : Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : SourceMask ,
2019-03-27 02:07:28 +00:00
seq ( " np nr nn nn np " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
2019-03-24 22:20:54 +00:00
op ( Action : : PerformOperation ) ;
break ;
case 0x11 : // MOVE (xxx).L, SR
op ( Action : : None , seq ( " np " ) ) ;
2019-03-27 02:07:28 +00:00
op ( int ( MicroOp : : Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : SourceMask , seq ( " np nr " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
2019-03-24 22:20:54 +00:00
op ( Action : : PerformOperation , seq ( " nn nn np " ) ) ;
break ;
case 0x14 : // MOVE #, SR
storage_ . instructions [ instruction ] . source = & storage_ . prefetch_queue_ ;
op ( int ( Action : : PerformOperation ) , seq ( " np nn nn np " ) ) ;
break ;
default : continue ;
}
} break ;
2019-03-30 03:13:41 +00:00
case Decoder : : MOVEq : {
const int destination_register = ( instruction > > 9 ) & 7 ;
storage_ . instructions [ instruction ] . destination = & storage_ . data_ [ destination_register ] ;
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 ;
const int destination_register = ( instruction > > 9 ) & 7 ;
2019-03-17 18:34:16 +00:00
switch ( source_mode ) {
case 0 : // Dn
storage_ . instructions [ instruction ] . source = & storage_ . data_ [ source_register ] ;
break ;
case 1 : // An
storage_ . instructions [ instruction ] . source = & storage_ . address_ [ source_register ] ;
break ;
default : // (An), (An)+, -(An), (d16, An), (d8, An Xn), (xxx).W, (xxx).L
2019-04-01 01:13:26 +00:00
storage_ . instructions [ instruction ] . source = & storage_ . source_bus_data_ [ 0 ] ;
2019-04-03 01:50:58 +00:00
storage_ . instructions [ instruction ] . source_address = & storage_ . source_bus_data_ [ source_register ] ;
2019-03-17 18:34:16 +00:00
break ;
2019-03-17 03:14:18 +00:00
}
2019-03-19 15:53:37 +00:00
switch ( destination_mode ) {
case 0 : // Dn
storage_ . instructions [ instruction ] . destination = & storage_ . data_ [ destination_register ] ;
break ;
case 1 : // An
storage_ . instructions [ instruction ] . destination = & storage_ . address_ [ destination_register ] ;
break ;
default : // (An), (An)+, -(An), (d16, An), (d8, An Xn), (xxx).W, (xxx).L
2019-04-01 01:13:26 +00:00
storage_ . instructions [ instruction ] . destination = & storage_ . destination_bus_data_ [ 0 ] ;
2019-04-03 01:50:58 +00:00
storage_ . instructions [ instruction ] . destination = & storage_ . source_bus_data_ [ destination_register ] ;
2019-03-19 15:53:37 +00:00
break ;
2019-03-17 03:14:18 +00:00
}
2019-03-17 18:34:16 +00:00
const bool is_byte_access = mapping . operation = = Operation : : MOVEb ;
2019-03-19 15:53:37 +00:00
const bool is_long_word_access = mapping . operation = = Operation : : MOVEl ;
2019-03-22 02:30:41 +00:00
// There are no byte moves to address registers.
if ( is_byte_access & & destination_mode = = 1 ) {
continue ;
}
2019-03-30 03:13:41 +00:00
const int decrement_action = int ( is_long_word_access ? Action : : Decrement4 : ( is_byte_access ? Action : : Decrement1 : Action : : Decrement2 ) ) ;
const int increment_action = int ( is_long_word_access ? Action : : Increment4 : ( is_byte_access ? Action : : Increment1 : Action : : Increment2 ) ) ;
2019-03-21 03:21:02 +00:00
// Construct a single word to describe the addressing mode:
//
// 0xssdd, where ss or dd =
// 0n with n a regular addresing mode between 0 and 6; or
// 1n with n being the nominal 'register' where addressing mode is 7.
//
// i.e. (see 4-118 / p.222)
//
// 00 = Dn
// 01 = An
// 02 = (An)
// 03 = (An)+
// 04 = -(An)
// 05 = (d16, An)
// 06 = (d8, An, Xn)
// 10 = (xxx).W
// 11 = (xxx).L
// 12 = (d16, PC)
// 13 = (d8, PC, Xn)
// 14 = #
//
// ... for no reason other than to make the switch below easy to read.
2019-03-30 03:13:41 +00:00
int both_modes =
2019-03-25 03:05:57 +00:00
( combined_mode ( source_mode , source_register ) < < 8 ) |
combined_mode ( destination_mode , destination_register ) |
2019-03-24 01:03:52 +00:00
( is_long_word_access ? 0x10000 : 0 ) ;
2019-03-21 03:21:02 +00:00
2019-03-30 03:13:41 +00:00
// If the move is to an address register, switch the MOVE to a MOVEA and
// pretend it's to a data register; if the move is from an address register
// then just call it a move from a data register.
if ( ( both_modes & 0xff ) = = 0x01 ) {
both_modes & = ~ 0x00ff ;
operation = is_long_word_access ? Operation : : MOVEAl : Operation : : MOVEAw ;
}
if ( ( both_modes & 0xff00 ) = = 0x0100 ) {
both_modes & = ~ 0xff00 ;
}
2019-03-24 01:03:52 +00:00
switch ( both_modes ) {
//
2019-03-30 03:13:41 +00:00
// MOVE <ea>, Dn
2019-03-24 01:03:52 +00:00
//
case 0x10000 : // MOVE.l Dn, Dn
case 0x00000 : // MOVE.bw Dn, Dn
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
2019-03-30 03:13:41 +00:00
case 0x10200 : // MOVE.l (An), Dn
case 0x10300 : // MOVE.l (An)+, Dn
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : SourceMask , seq ( " nR nr np " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
2019-04-03 01:50:58 +00:00
if ( source_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( int ( Action : : Increment4 ) | MicroOp : : SourceMask ) ;
2019-03-24 01:03:52 +00:00
}
2019-03-30 03:13:41 +00:00
op ( Action : : PerformOperation ) ;
2019-03-24 01:03:52 +00:00
break ;
2019-03-30 03:13:41 +00:00
case 0x00200 : // MOVE.bw (An), Dn
case 0x00300 : // MOVE.bw (An)+, Dn
op ( Action : : None , seq ( " nr np " , { & storage_ . address_ [ source_register ] . full } , ! is_byte_access ) ) ;
2019-04-03 01:50:58 +00:00
if ( source_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( int ( is_byte_access ? Action : : Increment1 : Action : : Increment2 ) | MicroOp : : SourceMask ) ;
}
op ( Action : : PerformOperation ) ;
2019-03-24 01:03:52 +00:00
break ;
2019-03-30 03:13:41 +00:00
case 0x10400 : // MOVE.l -(An), Dn
op ( decrement_action | MicroOp : : SourceMask , seq ( " n nR nr np " , { & storage_ . address_ [ source_register ] . full } ) ) ;
op ( Action : : PerformOperation ) ;
2019-03-28 01:26:04 +00:00
break ;
2019-03-24 01:03:52 +00:00
2019-03-30 03:13:41 +00:00
case 0x00400 : // MOVE.bw -(An), Dn
op ( decrement_action | MicroOp : : SourceMask , seq ( " n nr np " , { & storage_ . address_ [ source_register ] . full } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation ) ;
2019-03-28 01:26:04 +00:00
break ;
2019-03-24 01:03:52 +00:00
2019-03-30 03:13:41 +00:00
case 0x10500 : // MOVE.l (d16, An), Dn
case 0x10600 : // MOVE.l (d8, An, Xn), Dn
case 0x11200 : // MOVE.l (d16, PC), Dn
case 0x11300 : // MOVE.l (d8, PC, Xn), Dn
op ( calc_action_for_mode ( both_modes > > 8 ) | MicroOp : : SourceMask ,
seq ( pseq ( " np nR nr np " , both_modes > > 8 ) , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation ) ;
2019-03-28 01:26:04 +00:00
break ;
2019-03-24 01:03:52 +00:00
2019-03-30 03:13:41 +00:00
case 0x00500 : // MOVE.bw (d16, An), Dn
case 0x00600 : // MOVE.bw (d8, An, Xn), Dn
case 0x01200 : // MOVE.bw (d16, PC), Dn
case 0x01300 : // MOVE.bw (d8, PC, Xn), Dn
op ( calc_action_for_mode ( both_modes > > 8 ) | MicroOp : : SourceMask ,
seq ( pseq ( " np nr np " , both_modes > > 8 ) , { & storage_ . effective_address_ [ 0 ] . full } ,
! is_byte_access ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x11000 : // MOVE.l (xxx).W, Dn
op (
int ( MicroOp : : Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np nR nr np " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x01000 : // MOVE.bw (xxx).W, Dn
op (
int ( MicroOp : : Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np nr np " , { & storage_ . effective_address_ [ 0 ] . full } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation ) ;
break ;
case 0x11100 : // MOVE.l (xxx).L, Dn
2019-03-28 01:26:04 +00:00
op ( Action : : None , seq ( " np " ) ) ;
2019-03-30 03:13:41 +00:00
op ( int ( MicroOp : : Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : SourceMask , seq ( " np nR nr " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
case 0x01100 : // MOVE.bw (xxx).L, Dn
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( MicroOp : : Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : SourceMask , seq ( " np nr " , { & storage_ . effective_address_ [ 0 ] . full } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " np " ) ) ;
break ;
case 0x11400 : // MOVE.l #, Dn
storage_ . instructions [ instruction ] . source = & storage_ . prefetch_queue_ ;
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( Action : : PerformOperation ) , seq ( " np np " ) ) ;
break ;
case 0x01400 : // MOVE.bw #, Dn
storage_ . instructions [ instruction ] . source = & storage_ . prefetch_queue_ ;
op ( int ( Action : : PerformOperation ) , seq ( " np np " ) ) ;
2019-03-28 01:26:04 +00:00
break ;
2019-03-24 01:03:52 +00:00
//
2019-03-30 03:13:41 +00:00
// MOVE <ea>, (An)
// MOVE <ea>, (An)+
2019-03-24 01:03:52 +00:00
//
2019-03-30 03:13:41 +00:00
case 0x10002 : // MOVE.l Dn, (An)
case 0x10003 : // MOVE.l Dn, (An)+
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask ) ;
op ( Action : : SetMoveFlagsl , seq ( " nW nw np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
2019-04-03 01:50:58 +00:00
if ( destination_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( increment_action | MicroOp : : DestinationMask ) ;
2019-03-24 01:03:52 +00:00
}
break ;
2019-03-30 03:13:41 +00:00
case 0x00002 : // MOVE.bw Dn, (An)
case 0x00003 : // MOVE.bw Dn, (An)+
op ( is_byte_access ? Action : : SetMoveFlagsb : Action : : SetMoveFlagsw , seq ( " nw np " , { & storage_ . address_ [ destination_register ] . full } , ! is_byte_access ) ) ;
2019-04-03 01:50:58 +00:00
if ( destination_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( increment_action | MicroOp : : DestinationMask ) ;
}
break ;
case 0x10202 : // MOVE.l (An), (An)
case 0x10302 : // MOVE.l (An)+, (An)
case 0x10203 : // MOVE.l (An), (An)+
case 0x10303 : // MOVE.l (An)+, (An)+
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask | MicroOp : : SourceMask ,
seq ( " nR nr " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation , seq ( " nW nw np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
2019-04-03 01:50:58 +00:00
if ( source_mode = = 0x03 | | destination_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op (
increment_action |
2019-04-03 01:50:58 +00:00
( source_mode = = 0x03 ? MicroOp : : SourceMask : 0 ) |
( source_mode = = 0x03 ? MicroOp : : DestinationMask : 0 ) ) ;
2019-03-24 01:03:52 +00:00
}
break ;
2019-03-24 22:20:54 +00:00
case 0x00202 : // MOVE.bw (An), (An)
case 0x00302 : // MOVE.bw (An)+, (An)
case 0x00203 : // MOVE.bw (An), (An)+
case 0x00303 : // MOVE.bw (An)+, (An)+
op ( Action : : None , seq ( " nr " , { & storage_ . address_ [ source_register ] . full } ) ) ;
op ( Action : : PerformOperation , seq ( " nw np " , { & storage_ . address_ [ destination_register ] . full } ) ) ;
2019-04-03 01:50:58 +00:00
if ( source_mode = = 0x03 | | destination_mode = = 0x03 ) {
2019-03-24 22:20:54 +00:00
op (
2019-03-30 03:13:41 +00:00
increment_action |
2019-04-03 01:50:58 +00:00
( source_mode = = 0x03 ? MicroOp : : SourceMask : 0 ) |
( source_mode = = 0x03 ? MicroOp : : DestinationMask : 0 ) ) ;
2019-03-24 22:20:54 +00:00
}
2019-03-28 01:26:04 +00:00
break ;
2019-03-24 22:20:54 +00:00
2019-03-30 03:13:41 +00:00
case 0x10402 : // MOVE.l -(An), (An)
case 0x10403 : // MOVE.l -(An), (An)+
op ( decrement_action | MicroOp : : SourceMask ) ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask | MicroOp : : SourceMask ,
seq ( " n nR nr " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
2019-03-27 02:07:28 +00:00
op ( Action : : PerformOperation , seq ( " nW nw np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
2019-04-03 01:50:58 +00:00
if ( destination_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( increment_action | MicroOp : : DestinationMask ) ;
2019-03-24 22:20:54 +00:00
}
2019-03-28 01:26:04 +00:00
break ;
2019-03-24 01:03:52 +00:00
2019-03-30 03:13:41 +00:00
case 0x00402 : // MOVE.bw -(An), (An)
case 0x00403 : // MOVE.bw -(An), (An)+
op ( decrement_action | MicroOp : : SourceMask , seq ( " n nR nr " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation , seq ( " nW nw np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
2019-04-03 01:50:58 +00:00
if ( destination_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( increment_action | MicroOp : : DestinationMask ) ;
}
break ;
case 0x10502 : // MOVE.bw (d16, An), (An)
case 0x10503 : // MOVE.bw (d16, An), (An)+
case 0x10602 : // MOVE.bw (d8, An, Xn), (An)
case 0x10603 : // MOVE.bw (d8, An, Xn), (An)+
case 0x11202 : // MOVE.bw (d16, PC), (An)
case 0x11203 : // MOVE.bw (d16, PC), (An)+
case 0x11302 : // MOVE.bw (d8, PC, Xn), (An)
case 0x11303 : // MOVE.bw (d8, PC, Xn), (An)+
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask ) ;
op ( calc_action_for_mode ( both_modes > > 8 ) | MicroOp : : SourceMask ,
seq ( pseq ( " np nR nr " , both_modes > > 8 ) , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation ,
seq ( " nW nw np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
2019-04-03 01:50:58 +00:00
if ( destination_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( increment_action | MicroOp : : DestinationMask ) ;
}
break ;
case 0x00502 : // MOVE.bw (d16, An), (An)
case 0x00503 : // MOVE.bw (d16, An), (An)+
case 0x00602 : // MOVE.bw (d8, An, Xn), (An)
case 0x00603 : // MOVE.bw (d8, An, Xn), (An)+
case 0x01202 : // MOVE.bw (d16, PC), (An)
case 0x01203 : // MOVE.bw (d16, PC), (An)+
case 0x01302 : // MOVE.bw (d8, PC, Xn), (An)
case 0x01303 : // MOVE.bw (d8, PC, Xn), (An)+
op ( calc_action_for_mode ( both_modes > > 8 ) | MicroOp : : SourceMask ,
seq ( pseq ( " np nr " , both_modes > > 8 ) , { & storage_ . effective_address_ [ 0 ] . full } ,
! is_byte_access ) ) ;
op ( Action : : PerformOperation ,
seq ( " nw np " , { & storage_ . address_ [ destination_register ] . full } , ! is_byte_access ) ) ;
2019-04-03 01:50:58 +00:00
if ( destination_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( increment_action | MicroOp : : DestinationMask ) ;
}
break ;
case 0x11002 : // MOVE.l (xxx).W, (An)
case 0x11003 : // MOVE.l (xxx).W, (An)+
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask ) ;
op ( int ( MicroOp : : Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np nR nr " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation ,
seq ( " nW nw np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
2019-04-03 01:50:58 +00:00
if ( destination_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( increment_action | MicroOp : : DestinationMask ) ;
}
break ;
case 0x01002 : // MOVE.bw (xxx).W, (An)
case 0x01003 : // MOVE.bw (xxx).W, (An)+
op ( int ( MicroOp : : Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np nr " , { & storage_ . effective_address_ [ 0 ] . full } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation ,
seq ( " nw np " , { & storage_ . address_ [ destination_register ] . full } , ! is_byte_access ) ) ;
2019-04-03 01:50:58 +00:00
if ( destination_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( increment_action | MicroOp : : DestinationMask ) ;
}
break ;
case 0x11102 : // MOVE.l (xxx).l, (An)
case 0x11103 : // MOVE.l (xxx).l, (An)+
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
op ( int ( MicroOp : : Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np nR nr " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation ,
seq ( " nW nw np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
2019-04-03 01:50:58 +00:00
if ( destination_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( increment_action | MicroOp : : DestinationMask ) ;
}
break ;
case 0x01102 : // MOVE.bw (xxx).l, (An)
case 0x01103 : // MOVE.bw (xxx).l, (An)+
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( MicroOp : : Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : SourceMask ,
seq ( " np nr " , { & storage_ . effective_address_ [ 0 ] . full } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation ,
seq ( " nw np " , { & storage_ . address_ [ destination_register ] . full } , ! is_byte_access ) ) ;
2019-04-03 01:50:58 +00:00
if ( destination_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( increment_action | MicroOp : : DestinationMask ) ;
}
break ;
case 0x11402 : // MOVE.l #, (An)
case 0x11403 : // MOVE.l #, (An)+
storage_ . instructions [ instruction ] . source = & storage_ . prefetch_queue_ ;
op ( int ( Action : : CopyToEffectiveAddress ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " np nW nw np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
2019-04-03 01:50:58 +00:00
if ( destination_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( increment_action | MicroOp : : DestinationMask ) ;
}
break ;
case 0x01402 : // MOVE.bw #, (An)
case 0x01403 : // MOVE.bw #, (An)+
storage_ . instructions [ instruction ] . source = & storage_ . prefetch_queue_ ;
op ( Action : : PerformOperation , seq ( " np nw np " , { & storage_ . data_ [ destination_register ] . full } , ! is_byte_access ) ) ;
2019-04-03 01:50:58 +00:00
if ( destination_mode = = 0x03 ) {
2019-03-30 03:13:41 +00:00
op ( increment_action | MicroOp : : DestinationMask ) ;
}
break ;
//
// MOVE <ea>, -(An)
//
case 0x0004 : // MOVE Dn, -(An)
op ( decrement_action | MicroOp : : DestinationMask ,
seq ( " np nw " , { & storage_ . address_ [ destination_register ] . full } , ! is_byte_access ) ) ;
op ( is_byte_access ? Action : : SetMoveFlagsb : Action : : SetMoveFlagsw ) ;
break ;
2019-03-24 01:03:52 +00:00
case 0x0204 : // MOVE (An), -(An)
case 0x0304 : // MOVE (An)+, -(An)
// nr np nw
continue ;
2019-04-01 02:34:28 +00:00
2019-03-30 03:13:41 +00:00
case 0x0404 : // MOVE -(An), -(An)
// n nr np nw
continue ;
2019-04-01 02:34:28 +00:00
2019-03-30 03:13:41 +00:00
case 0x0504 : // MOVE (d16, An), -(An)
case 0x0604 : // MOVE (d8, An, Xn), -(An)
// np nr np nw
// n np nr np nw
continue ;
2019-04-01 02:34:28 +00:00
2019-03-30 03:13:41 +00:00
case 0x1004 : // MOVE (xxx).W, -(An)
// np nr np nw
continue ;
//
2019-04-01 02:34:28 +00:00
// MOVE <ea>, (d16, An)
// MOVE <ea>, (d8, An, Xn)
// MOVE <ea>, (d16, An)
// MOVE <ea>, (d16, An)
2019-03-30 03:13:41 +00:00
//
2019-04-01 02:34:28 +00:00
case 0x0005 : // MOVE Dn, (d16, An)
op ( int ( Action : : CalcD16An ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " nw np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
break ;
2019-03-30 03:13:41 +00:00
2019-04-01 02:34:28 +00:00
case 0x0006 : // MOVE Dn, (d8, An, Xn)
op ( int ( Action : : CalcD8AnXn ) | MicroOp : : DestinationMask , seq ( " n np " ) ) ;
op ( Action : : PerformOperation , seq ( " nw np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
break ;
2019-03-24 01:03:52 +00:00
case 0x0205 : // MOVE (An), (d16, An)
case 0x0305 : // MOVE (An)+, (d16, An)
// nr np nw np
continue ;
case 0x0206 : // MOVE (An), (d8, An, Xn)
case 0x0306 : // MOVE (An)+, (d8, An, Xn)
// nr n np nw np
continue ;
case 0x0405 : // MOVE -(An), (d16, An)
// n nr np nw
continue ;
case 0x0406 : // MOVE -(An), (d8, An, Xn)
// n nr n np nw np
continue ;
case 0x0505 : // MOVE (d16, An), (d16, An)
case 0x0605 : // MOVE (d8, An, Xn), (d16, An)
// np nr np nw np
// n np nr np nw np
continue ;
case 0x0506 : // MOVE (d16, An), (d8, An, Xn)
case 0x0606 : // MOVE (d8, An, Xn), (d8, An, Xn)
// np nr n np nw np
// n np nr n np nw np
continue ;
2019-04-01 02:34:28 +00:00
case 0x1005 : // MOVE (xxx).W, (d16, An)
2019-03-24 01:03:52 +00:00
// np nr np nw np
continue ;
2019-04-01 02:34:28 +00:00
case 0x1006 : // MOVE (xxx).W, (d8, An, Xn)
// np nr n np nw np
2019-03-24 01:03:52 +00:00
continue ;
2019-03-22 02:30:41 +00:00
2019-03-24 01:03:52 +00:00
//
2019-04-01 02:34:28 +00:00
// MOVE <ea>, (xxx).W
2019-03-24 01:03:52 +00:00
//
2019-04-01 02:34:28 +00:00
case 0x0010 : // MOVE Dn, (xxx).W
op ( int ( Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " nw np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
break ;
2019-03-21 03:21:02 +00:00
2019-04-01 02:34:28 +00:00
case 0x0210 : // MOVE (An), (xxx).W
case 0x0310 : // MOVE (An)+, (xxx).W
// nr np nw np
continue ;
2019-03-24 01:03:52 +00:00
2019-04-01 02:34:28 +00:00
case 0x0410 : // MOVE -(An), (xxx).W
// n nr np nw np
continue ;
2019-03-24 01:03:52 +00:00
2019-04-01 02:34:28 +00:00
case 0x0510 : // MOVE (d16, An), (xxx).W
case 0x0610 : // MOVE (d8, An, Xn), (xxx).W
2019-03-24 01:03:52 +00:00
// np nr np nw np
2019-04-01 02:34:28 +00:00
// n np nr np nw np
2019-03-24 01:03:52 +00:00
continue ;
2019-04-01 02:34:28 +00:00
case 0x11410 : // MOVE.l #, (xxx).w
op ( int ( Action : : None ) , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
op ( int ( Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np nW nw np " , { & storage_ . effective_address_ [ 1 ] . full } , ! is_byte_access ) ) ;
op ( Action : : SetMoveFlagsl ) ;
break ;
2019-03-21 03:21:02 +00:00
2019-03-24 01:03:52 +00:00
case 0x1010 : // MOVE (xxx).W, (xxx).W
// np nr np nw np
continue ;
2019-04-01 02:34:28 +00:00
case 0x01410 : // MOVE.bw #, (xxx).w
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
op ( int ( Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np nw np " , { & storage_ . effective_address_ [ 1 ] . full } , ! is_byte_access ) ) ;
op ( is_byte_access ? Action : : SetMoveFlagsb : Action : : SetMoveFlagsw ) ;
break ;
2019-03-24 01:03:52 +00:00
//
2019-04-01 02:34:28 +00:00
// MOVE <ea>, (xxx).L
2019-03-24 01:03:52 +00:00
//
2019-04-01 02:34:28 +00:00
case 0x00011 : // MOVE.bw Dn, (xxx).L
op ( Action : : None , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np " ) ) ;
op ( Action : : PerformOperation , seq ( " nw np " , { & storage_ . effective_address_ [ 1 ] . full } , ! is_byte_access ) ) ;
break ;
2019-03-24 01:03:52 +00:00
2019-04-01 02:34:28 +00:00
case 0x00211 : // MOVE.bw (An), (xxx).L
case 0x00311 : // MOVE.bw (An)+, (xxx).L
op ( Action : : None , seq ( " nr np " , { & storage_ . address_ [ source_register ] . full } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " nw np np " , { & storage_ . prefetch_queue_ . full } ) ) ;
2019-04-03 01:50:58 +00:00
if ( source_mode = = 0x03 ) {
2019-04-01 02:34:28 +00:00
op ( int ( is_byte_access ? Action : : Increment1 : Action : : Increment2 ) | MicroOp : : SourceMask ) ;
}
break ;
2019-03-24 01:03:52 +00:00
2019-04-01 02:34:28 +00:00
case 0x0411 : // MOVE -(An), (xxx).L
// n nr np nw np np
continue ;
2019-03-24 01:03:52 +00:00
2019-04-01 02:34:28 +00:00
case 0x0511 : // MOVE (d16, An), (xxx).L
case 0x0611 : // MOVE (d8, An, Xn), (xxx).L
// np nr np nw np np
// n np nr np nw np np
continue ;
2019-03-24 01:03:52 +00:00
2019-04-01 02:34:28 +00:00
case 0x01011 : // MOVE.bw (xxx).W, (xxx).L
op ( int ( Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : SourceMask , seq ( " np nr " , { & storage_ . effective_address_ [ 0 ] . full } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " nw np np " , { & storage_ . effective_address_ [ 1 ] . full } , ! is_byte_access ) ) ;
continue ;
2019-03-28 01:26:04 +00:00
2019-04-01 02:34:28 +00:00
case 0x01111 : // MOVE.bw (xxx).l, (xxx).l
2019-03-28 01:26:04 +00:00
op ( int ( Action : : None ) , seq ( " np " ) ) ;
2019-04-01 02:34:28 +00:00
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : SourceMask , seq ( " np nr " , { & storage_ . effective_address_ [ 0 ] . full } , ! is_byte_access ) ) ;
op ( Action : : PerformOperation , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " nw np np " , { & storage_ . effective_address_ [ 1 ] . full } , ! is_byte_access ) ) ;
2019-03-28 01:26:04 +00:00
break ;
case 0x01411 : // MOVE.bw #, (xxx).l
op ( int ( Action : : AssembleWordDataFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np np " ) ) ;
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np nw np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
op ( is_byte_access ? Action : : SetMoveFlagsb : Action : : SetMoveFlagsw ) ;
break ;
2019-04-01 02:34:28 +00:00
case 0x11011 : // MOVE.l (xxx).W, (xxx).L
op ( int ( Action : : AssembleWordAddressFromPrefetch ) | MicroOp : : SourceMask , seq ( " np nR nr " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " nW nw np np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
break ;
case 0x11111 : // MOVE.l (xxx).l, (xxx).l
op ( int ( Action : : None ) , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : SourceMask , seq ( " np nR nr " , { & storage_ . effective_address_ [ 0 ] . full } ) ) ;
op ( Action : : PerformOperation , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " nW nw np np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
break ;
case 0x11411 : // MOVE.l #, (xxx).l
op ( int ( Action : : None ) , seq ( " np " ) ) ;
op ( int ( Action : : AssembleLongWordDataFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np np " ) ) ;
op ( int ( Action : : AssembleLongWordAddressFromPrefetch ) | MicroOp : : DestinationMask , seq ( " np nW nw np " , { & storage_ . effective_address_ [ 1 ] . full } ) ) ;
op ( Action : : SetMoveFlagsl ) ;
2019-03-28 01:26:04 +00:00
break ;
2019-03-24 01:03:52 +00:00
//
// Default
//
default :
std : : cerr < < " Unimplemented MOVE " < < std : : hex < < both_modes < < " " < < instruction < < std : : endl ;
// TODO: all other types of mode.
continue ;
2019-03-17 03:14:18 +00:00
}
} break ;
2019-03-30 03:40:54 +00:00
case Decoder : : RESET :
2019-04-01 01:13:26 +00:00
storage_ . instructions [ instruction ] . requires_supervisor = true ;
2019-03-30 03:40:54 +00:00
op ( Action : : None , seq ( " nn _ np " ) ) ;
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-04-01 02:34:28 +00:00
// Ensure that steps that weren't meant to look terminal aren't terminal.
for ( auto index = micro_op_start ; index < storage_ . all_micro_ops_ . size ( ) - 1 ; + + index ) {
if ( storage_ . all_micro_ops_ [ index ] . is_terminal ( ) ) {
storage_ . all_micro_ops_ [ index ] . bus_program = seq ( " " ) ;
}
}
2019-03-17 02:36:09 +00:00
// Install the operation and make a note of where micro-ops begin.
2019-03-22 23:25:53 +00:00
storage_ . instructions [ instruction ] . operation = operation ;
2019-03-17 02:36:09 +00:00
micro_op_pointers [ instruction ] = micro_op_start ;
2019-03-16 23:41:07 +00:00
// Don't search further through the list of possibilities.
2019-03-10 21:27:34 +00:00
break ;
}
2019-03-16 23:41:07 +00:00
}
}
2019-03-09 05:00:23 +00:00
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-03-17 01:47:46 +00:00
// Finalise micro-op and program pointers.
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 ( ) ) {
storage_ . instructions [ instruction ] . micro_operations = & storage_ . all_micro_ops_ [ micro_op_pointers [ instruction ] ] ;
2019-03-17 01:47:46 +00:00
auto operation = storage_ . instructions [ instruction ] . micro_operations ;
while ( ! operation - > is_terminal ( ) ) {
2019-03-17 02:36:09 +00:00
const auto offset = size_t ( operation - > bus_program - & arbitrary_base ) ;
assert ( offset > = 0 & & offset < storage_ . all_bus_steps_ . size ( ) ) ;
operation - > bus_program = & storage_ . all_bus_steps_ [ offset ] ;
2019-03-17 01:47:46 +00:00
+ + operation ;
}
2019-03-16 23:41:07 +00:00
}
2019-03-09 05:00:23 +00:00
}
}
2019-03-16 23:41:07 +00:00
private :
ProcessorStorage & storage_ ;
} ;
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-03-16 23:41:07 +00:00
CPU : : MC68000 : : ProcessorStorage : : ProcessorStorage ( ) {
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-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-03-13 02:46:31 +00:00
2019-03-16 23:41:07 +00:00
// Install operations.
2019-03-17 01:47:46 +00:00
constructor . install_instructions ( ) ;
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 ] ;
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-03-14 01:08:13 +00:00
2019-03-16 23:41:07 +00:00
// Set initial state. Largely TODO.
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-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_ ] ;
}
}