2022-04-28 20:55:47 +00:00
//
// PerformImplementation.hpp
// Clock Signal
//
// Created by Thomas Harte on 28/04/2022.
// Copyright © 2022 Thomas Harte. All rights reserved.
//
# ifndef InstructionSets_M68k_PerformImplementation_h
# define InstructionSets_M68k_PerformImplementation_h
2022-05-11 11:00:35 +00:00
# include "../ExceptionVectors.hpp"
2022-04-28 20:55:47 +00:00
# include <cassert>
# include <cmath>
namespace InstructionSet {
namespace M68k {
# define u_extend16(x) uint32_t(int16_t(x))
# define s_extend16(x) int32_t(int16_t(x))
2022-10-11 02:21:13 +00:00
namespace Primitive {
/// Provides a type alias, @c type, which is an unsigned int bigger than @c IntT.
template < typename IntT > struct BiggerInt { } ;
template < > struct BiggerInt < uint8_t > {
using type = uint16_t ;
} ;
template < > struct BiggerInt < uint16_t > {
using type = uint32_t ;
} ;
template < > struct BiggerInt < uint32_t > {
using type = uint64_t ;
} ;
/// @returns An int of type @c IntT with only the most-significant bit set.
template < typename IntT > constexpr IntT top_bit ( ) {
static_assert ( ! std : : numeric_limits < IntT > : : is_signed ) ;
constexpr IntT max = std : : numeric_limits < IntT > : : max ( ) ;
return max - ( max > > 1 ) ;
}
/// @returns The number of bits in @c IntT.
template < typename IntT > constexpr int bit_count ( ) {
return sizeof ( IntT ) * 8 ;
}
/// @returns An int with the top bit indicating whether overflow occurred when @c source and @c destination
/// were either added (if @c is_add is true) or subtracted (if @c is_add is false) and the result was @c result.
/// All other bits will be clear.
template < bool is_add , typename IntT >
static Status : : FlagT overflow ( IntT source , IntT destination , IntT result ) {
const IntT output_changed = result ^ destination ;
const IntT input_differed = source ^ destination ;
if constexpr ( is_add ) {
return top_bit < IntT > ( ) & output_changed & ~ input_differed ;
} else {
return top_bit < IntT > ( ) & output_changed & input_differed ;
}
}
/// Performs an add or subtract (as per @c is_add) between @c source and @c destination,
/// updating @c status. @c is_extend indicates whether this is an extend operation (e.g. ADDX)
/// or a plain one (e.g. ADD).
template < bool is_add , bool is_extend , typename IntT >
static void add_sub ( IntT source , IntT & destination , Status & status ) {
static_assert ( ! std : : numeric_limits < IntT > : : is_signed ) ;
2022-10-11 14:33:28 +00:00
const IntT extend = ( is_extend & & status . extend_flag ) ? 1 : 0 ;
const IntT result = is_add ?
( destination + source + extend ) :
( destination - source - extend ) ;
2022-10-11 02:21:13 +00:00
// Extend operations can reset the zero flag only; non-extend operations
// can either set it or reset it. Which in the reverse-logic world of
// zero_result means ORing or storing.
if constexpr ( is_extend ) {
2022-10-11 14:33:28 +00:00
status . zero_result | = Status : : FlagT ( result ) ;
2022-10-11 02:21:13 +00:00
} else {
2022-10-11 14:33:28 +00:00
status . zero_result = Status : : FlagT ( result ) ;
2022-10-11 02:21:13 +00:00
}
status . extend_flag =
2022-10-11 14:33:28 +00:00
status . carry_flag = is_add ? result < destination : result > destination ;
2022-10-11 02:21:13 +00:00
status . negative_flag = Status : : FlagT ( result & top_bit < IntT > ( ) ) ;
2022-10-11 14:33:28 +00:00
status . overflow_flag = overflow < is_add > ( source , destination , result ) ;
destination = result ;
2022-10-11 02:21:13 +00:00
}
2022-10-11 16:57:02 +00:00
/// Performs a compare of @c source to @c destination, setting zero, carry, negative and overflow flags.
template < typename IntT >
static void compare ( IntT source , IntT destination , Status & status ) {
const IntT result = destination - source ;
status . zero_result = result ;
status . carry_flag = result > destination ;
status . negative_flag = result & top_bit < IntT > ( ) ;
status . overflow_flag = Primitive : : overflow < false > ( source , destination , result ) ;
}
2022-10-11 15:22:34 +00:00
/// @returns the name of the bit to be used as a mask for BCLR, BCHG, BSET or BTST for
/// @c instruction given @c source.
2022-10-11 14:47:55 +00:00
inline uint32_t mask_bit ( const Preinstruction & instruction , uint32_t source ) {
return source & ( instruction . mode < 1 > ( ) = = AddressingMode : : DataRegisterDirect ? 31 : 7 ) ;
}
2022-10-11 15:22:34 +00:00
/// Performs a BCLR, BCHG or BSET as specified by @c operation and described by @c instruction, @c source and @c destination, updating @c destination and @c status.
/// Also makes an appropriate notification to the @c flow_controller.
2022-10-11 14:47:55 +00:00
template < Operation operation , typename FlowController >
void bit_manipulate ( const Preinstruction & instruction , uint32_t source , uint32_t & destination , Status & status , FlowController & flow_controller ) {
2022-10-11 19:53:11 +00:00
static_assert (
operation = = Operation : : BCLR | |
operation = = Operation : : BCHG | |
operation = = Operation : : BSET ) ;
2022-10-11 14:47:55 +00:00
const auto bit = mask_bit ( instruction , source ) ;
status . zero_result = destination & ( 1 < < bit ) ;
switch ( operation ) {
case Operation : : BCLR : destination & = ~ ( 1 < < bit ) ; break ;
case Operation : : BCHG : destination ^ = ( 1 < < bit ) ; break ;
case Operation : : BSET : destination | = ( 1 < < bit ) ; break ;
}
flow_controller . did_bit_op ( int ( bit ) ) ;
}
2022-10-11 15:22:34 +00:00
/// Sets @c destination to 0, clears the overflow, carry and negative flags, sets the zero flag.
template < typename IntT > void clear ( IntT & destination , Status & status ) {
destination = 0 ;
status . negative_flag = status . overflow_flag = status . carry_flag = status . zero_result = 0 ;
}
2022-10-11 19:53:11 +00:00
template < Operation operation , typename FlowController >
void apply_sr_ccr ( uint16_t source , Status & status , FlowController & flow_controller ) {
static_assert (
operation = = Operation : : ANDItoSR | | operation = = Operation : : ANDItoCCR | |
operation = = Operation : : EORItoSR | | operation = = Operation : : EORItoCCR | |
operation = = Operation : : ORItoSR | | operation = = Operation : : ORItoCCR
) ;
auto sr = status . status ( ) ;
switch ( operation ) {
case Operation : : ANDItoSR : case Operation : : ANDItoCCR :
sr & = source ;
break ;
case Operation : : EORItoSR : case Operation : : EORItoCCR :
sr ^ = source ;
break ;
case Operation : : ORItoSR : case Operation : : ORItoCCR :
sr | = source ;
break ;
}
switch ( operation ) {
case Operation : : ANDItoSR :
case Operation : : EORItoSR :
case Operation : : ORItoSR :
status . set_status ( sr ) ;
flow_controller . did_update_status ( ) ;
break ;
case Operation : : ANDItoCCR :
case Operation : : EORItoCCR :
case Operation : : ORItoCCR :
status . set_ccr ( sr ) ;
break ;
}
}
2022-10-11 20:02:20 +00:00
template < bool is_mulu , typename FlowController >
void multiply ( uint16_t source , uint32_t & destination , Status & status , FlowController & flow_controller ) {
if constexpr ( is_mulu ) {
destination = source * uint16_t ( destination ) ;
} else {
destination = u_extend16 ( source ) * u_extend16 ( uint16_t ( destination ) ) ;
}
status . carry_flag = status . overflow_flag = 0 ;
status . zero_result = destination ;
status . negative_flag = status . zero_result & top_bit < uint32_t > ( ) ;
if constexpr ( is_mulu ) {
flow_controller . did_mulu ( source ) ;
} else {
flow_controller . did_muls ( source ) ;
}
}
2022-10-11 20:16:53 +00:00
template < bool is_divu , bool did_overflow , typename IntT , typename FlowController >
void did_divide ( IntT dividend , IntT divisor , FlowController & flow_controller ) {
if constexpr ( is_divu ) {
flow_controller . template did_divu < did_overflow > ( dividend , divisor ) ;
} else {
flow_controller . template did_divs < did_overflow > ( dividend , divisor ) ;
}
}
template < bool is_divu , typename Int16 , typename Int32 , typename FlowController >
void divide ( uint16_t source , uint32_t & destination , Status & status , FlowController & flow_controller ) {
status . carry_flag = 0 ;
const auto dividend = Int32 ( destination ) ;
const auto divisor = Int32 ( Int16 ( source ) ) ;
if ( ! divisor ) {
status . negative_flag = status . overflow_flag = 0 ;
status . zero_result = 1 ;
flow_controller . raise_exception ( Exception : : IntegerDivideByZero ) ;
did_divide < is_divu , false > ( dividend , divisor , flow_controller ) ;
return ;
}
const auto quotient = int64_t ( dividend ) / int64_t ( divisor ) ;
if ( quotient ! = Int32 ( Int16 ( quotient ) ) ) {
status . overflow_flag = 1 ;
did_divide < is_divu , true > ( dividend , divisor , flow_controller ) ;
return ;
}
const auto remainder = Int16 ( dividend % divisor ) ;
destination = uint32_t ( ( uint32_t ( remainder ) < < 16 ) | uint16_t ( quotient ) ) ;
status . overflow_flag = 0 ;
status . zero_result = Status : : FlagT ( quotient ) ;
status . negative_flag = status . zero_result & 0x8000 ;
did_divide < is_divu , false > ( dividend , divisor , flow_controller ) ;
}
2022-10-11 02:21:13 +00:00
}
2022-04-28 20:55:47 +00:00
template <
Model model ,
2022-05-01 21:39:56 +00:00
typename FlowController ,
Operation operation = Operation : : Undefined
2022-04-30 18:08:51 +00:00
> void perform ( Preinstruction instruction , CPU : : SlicedInt32 & src , CPU : : SlicedInt32 & dest , Status & status , FlowController & flow_controller ) {
2022-04-28 20:55:47 +00:00
2022-05-01 21:39:56 +00:00
switch ( ( operation ! = Operation : : Undefined ) ? operation : instruction . operation ) {
2022-04-28 20:55:47 +00:00
/*
2022-04-29 11:57:02 +00:00
ABCD adds the lowest bytes from the source and destination using BCD arithmetic ,
2022-04-28 20:55:47 +00:00
obeying the extend flag .
*/
case Operation : : ABCD : {
// Pull out the two halves, for simplicity.
2022-04-29 08:51:02 +00:00
const uint8_t source = src . b ;
const uint8_t destination = dest . b ;
2022-05-12 19:18:03 +00:00
const int extend = ( status . extend_flag ? 1 : 0 ) ;
2022-04-28 20:55:47 +00:00
// Perform the BCD add by evaluating the two nibbles separately.
2022-05-12 19:18:03 +00:00
const int unadjusted_result = destination + source + extend ;
int result = ( destination & 0xf ) + ( source & 0xf ) + extend ;
2022-05-12 19:25:01 +00:00
result + =
( destination & 0xf0 ) +
( source & 0xf0 ) +
2022-05-12 20:21:36 +00:00
( ( ( 9 - result ) > > 4 ) & 0x06 ) ; // i.e. ((result > 0x09) ? 0x06 : 0x00)
2022-05-12 19:25:01 +00:00
result + = ( ( 0x9f - result ) > > 4 ) & 0x60 ; // i.e. ((result > 0x9f) ? 0x60 : 0x00)
2022-04-28 20:55:47 +00:00
// Set all flags essentially as if this were normal addition.
2022-05-12 12:19:41 +00:00
status . zero_result | = result & 0xff ;
status . extend_flag = status . carry_flag = uint_fast32_t ( result & ~ 0xff ) ;
status . negative_flag = result & 0x80 ;
status . overflow_flag = ~ unadjusted_result & result & 0x80 ;
2022-04-28 20:55:47 +00:00
// Store the result.
2022-04-29 08:51:02 +00:00
dest . b = uint8_t ( result ) ;
2022-04-28 20:55:47 +00:00
} break ;
// ADD and ADDA add two quantities, the latter sign extending and without setting any flags;
// ADDQ and SUBQ act as ADD and SUB, but taking the second argument from the instruction code.
2022-10-11 02:21:13 +00:00
case Operation : : ADDb : Primitive : : add_sub < true , false > ( src . b , dest . b , status ) ; break ;
case Operation : : SUBb : Primitive : : add_sub < false , false > ( src . b , dest . b , status ) ; break ;
case Operation : : ADDXb : Primitive : : add_sub < true , true > ( src . b , dest . b , status ) ; break ;
case Operation : : SUBXb : Primitive : : add_sub < false , true > ( src . b , dest . b , status ) ; break ;
case Operation : : ADDw : Primitive : : add_sub < true , false > ( src . w , dest . w , status ) ; break ;
case Operation : : SUBw : Primitive : : add_sub < false , false > ( src . w , dest . w , status ) ; break ;
case Operation : : ADDXw : Primitive : : add_sub < true , true > ( src . w , dest . w , status ) ; break ;
case Operation : : SUBXw : Primitive : : add_sub < false , true > ( src . w , dest . w , status ) ; break ;
case Operation : : ADDl : Primitive : : add_sub < true , false > ( src . l , dest . l , status ) ; break ;
case Operation : : SUBl : Primitive : : add_sub < false , false > ( src . l , dest . l , status ) ; break ;
case Operation : : ADDXl : Primitive : : add_sub < true , true > ( src . l , dest . l , status ) ; break ;
case Operation : : SUBXl : Primitive : : add_sub < false , true > ( src . l , dest . l , status ) ; break ;
case Operation : : ADDAw : dest . l + = u_extend16 ( src . w ) ; break ;
case Operation : : ADDAl : dest . l + = src . l ; break ;
case Operation : : SUBAw : dest . l - = u_extend16 ( src . w ) ; break ;
case Operation : : SUBAl : dest . l - = src . l ; break ;
2022-04-28 20:55:47 +00:00
2022-05-05 00:57:22 +00:00
// BTST/BCLR/etc: modulo for the mask depends on whether memory or a data register is the target.
2022-10-11 14:47:55 +00:00
case Operation : : BTST :
status . zero_result = dest . l & ( 1 < < Primitive : : mask_bit ( instruction , src . l ) ) ;
break ;
case Operation : : BCLR : Primitive : : bit_manipulate < Operation : : BCLR > ( instruction , src . l , dest . l , status , flow_controller ) ; break ;
case Operation : : BCHG : Primitive : : bit_manipulate < Operation : : BCHG > ( instruction , src . l , dest . l , status , flow_controller ) ; break ;
case Operation : : BSET : Primitive : : bit_manipulate < Operation : : BSET > ( instruction , src . l , dest . l , status , flow_controller ) ; break ;
2022-05-13 19:08:15 +00:00
2022-04-29 21:12:06 +00:00
case Operation : : Bccb :
2022-05-09 20:19:25 +00:00
flow_controller . template complete_bcc < int8_t > (
status . evaluate_condition ( instruction . condition ( ) ) ,
2022-05-24 15:05:24 +00:00
int8_t ( src . b ) ) ;
2022-05-03 18:45:49 +00:00
break ;
2022-04-29 21:12:06 +00:00
case Operation : : Bccw :
2022-05-09 20:19:25 +00:00
flow_controller . template complete_bcc < int16_t > (
status . evaluate_condition ( instruction . condition ( ) ) ,
2022-05-24 15:05:24 +00:00
int16_t ( src . w ) ) ;
2022-05-03 18:45:49 +00:00
break ;
2022-04-29 21:12:06 +00:00
2022-05-03 18:45:49 +00:00
case Operation : : Bccl :
2022-05-09 20:19:25 +00:00
flow_controller . template complete_bcc < int32_t > (
status . evaluate_condition ( instruction . condition ( ) ) ,
2022-05-24 15:05:24 +00:00
int32_t ( src . l ) ) ;
2022-05-03 18:45:49 +00:00
break ;
2022-04-28 20:55:47 +00:00
2022-05-03 19:32:54 +00:00
case Operation : : BSRb :
2022-05-24 15:05:24 +00:00
flow_controller . bsr ( uint32_t ( int8_t ( src . b ) ) ) ;
2022-05-03 19:32:54 +00:00
break ;
case Operation : : BSRw :
2022-05-24 15:05:24 +00:00
flow_controller . bsr ( uint32_t ( int16_t ( src . w ) ) ) ;
2022-05-03 19:32:54 +00:00
break ;
case Operation : : BSRl :
2022-05-20 16:40:09 +00:00
flow_controller . bsr ( src . l ) ;
2022-05-03 19:32:54 +00:00
break ;
2022-05-09 20:19:25 +00:00
case Operation : : DBcc : {
const bool matched_condition = status . evaluate_condition ( instruction . condition ( ) ) ;
bool overflowed = false ;
2022-04-29 21:12:06 +00:00
2022-05-09 20:19:25 +00:00
// Classify the dbcc.
if ( ! matched_condition ) {
- - src . w ;
overflowed = src . w = = 0xffff ;
2022-04-29 21:12:06 +00:00
}
2022-05-09 20:19:25 +00:00
// Take the branch.
flow_controller . complete_dbcc (
matched_condition ,
overflowed ,
int16_t ( dest . w ) ) ;
} break ;
2022-04-29 21:12:06 +00:00
2022-05-20 15:19:16 +00:00
case Operation : : Scc : {
const bool condition = status . evaluate_condition ( instruction . condition ( ) ) ;
src . b = condition ? 0xff : 0x00 ;
flow_controller . did_scc ( condition ) ;
} break ;
2022-04-29 21:12:06 +00:00
2022-04-28 20:55:47 +00:00
/*
CLRs : store 0 to the destination , set the zero flag , and clear
negative , overflow and carry .
*/
2022-10-11 15:22:34 +00:00
case Operation : : CLRb : Primitive : : clear ( src . b , status ) ; break ;
case Operation : : CLRw : Primitive : : clear ( src . w , status ) ; break ;
case Operation : : CLRl : Primitive : : clear ( src . l , status ) ; break ;
2022-04-28 20:55:47 +00:00
/*
CMP . b , CMP . l and CMP . w : sets the condition flags ( other than extend ) based on a subtraction
of the source from the destination ; the result of the subtraction is not stored .
*/
2022-10-11 16:57:02 +00:00
case Operation : : CMPb : Primitive : : compare ( src . b , dest . b , status ) ; break ;
case Operation : : CMPw : Primitive : : compare ( src . w , dest . w , status ) ; break ;
case Operation : : CMPAw : Primitive : : compare ( u_extend16 ( src . w ) , dest . l , status ) ; break ;
2022-05-03 13:20:02 +00:00
case Operation : : CMPAl :
2022-10-11 16:57:02 +00:00
case Operation : : CMPl : Primitive : : compare ( src . l , dest . l , status ) ; break ;
2022-04-28 20:55:47 +00:00
// JMP: copies EA(0) to the program counter.
2022-04-29 21:12:06 +00:00
case Operation : : JMP :
2022-05-09 20:20:15 +00:00
flow_controller . jmp ( src . l ) ;
2022-04-29 21:12:06 +00:00
break ;
2022-04-28 20:55:47 +00:00
2022-05-03 19:49:55 +00:00
// JSR: jump to EA(0), pushing the current PC to the stack.
case Operation : : JSR :
flow_controller . jsr ( src . l ) ;
break ;
2022-04-28 20:55:47 +00:00
/*
MOVE . b , MOVE . l and MOVE . w : move the least significant byte or word , or the entire long word ,
and set negative , zero , overflow and carry as appropriate .
*/
case Operation : : MOVEb :
2022-05-12 12:19:41 +00:00
status . zero_result = dest . b = src . b ;
status . negative_flag = status . zero_result & 0x80 ;
status . overflow_flag = status . carry_flag = 0 ;
2022-04-28 20:55:47 +00:00
break ;
case Operation : : MOVEw :
2022-05-12 12:19:41 +00:00
status . zero_result = dest . w = src . w ;
status . negative_flag = status . zero_result & 0x8000 ;
status . overflow_flag = status . carry_flag = 0 ;
2022-04-28 20:55:47 +00:00
break ;
case Operation : : MOVEl :
2022-05-12 12:19:41 +00:00
status . zero_result = dest . l = src . l ;
status . negative_flag = status . zero_result & 0x80000000 ;
status . overflow_flag = status . carry_flag = 0 ;
2022-04-28 20:55:47 +00:00
break ;
/*
MOVEA . l : move the entire long word ;
MOVEA . w : move the least significant word and sign extend it .
Neither sets any flags .
*/
case Operation : : MOVEAw :
2022-04-29 08:51:02 +00:00
dest . l = u_extend16 ( src . w ) ;
2022-04-28 20:55:47 +00:00
break ;
case Operation : : MOVEAl :
2022-04-29 08:51:02 +00:00
dest . l = src . l ;
2022-04-28 20:55:47 +00:00
break ;
2022-04-29 21:12:06 +00:00
case Operation : : LEA :
2022-04-30 00:30:48 +00:00
dest . l = src . l ;
2022-04-29 21:12:06 +00:00
break ;
2022-05-09 20:19:25 +00:00
case Operation : : PEA :
flow_controller . pea ( src . l ) ;
break ;
2022-04-28 20:55:47 +00:00
/*
Status word moves and manipulations .
*/
case Operation : : MOVEtoSR :
2022-04-29 08:51:02 +00:00
status . set_status ( src . w ) ;
2022-05-08 01:29:12 +00:00
flow_controller . did_update_status ( ) ;
2022-04-28 20:55:47 +00:00
break ;
case Operation : : MOVEfromSR :
2022-05-06 15:33:57 +00:00
src . w = status . status ( ) ;
2022-04-28 20:55:47 +00:00
break ;
case Operation : : MOVEtoCCR :
2022-04-29 08:51:02 +00:00
status . set_ccr ( src . w ) ;
2022-04-28 20:55:47 +00:00
break ;
2022-05-11 11:52:23 +00:00
case Operation : : MOVEtoUSP :
flow_controller . move_to_usp ( src . l ) ;
break ;
case Operation : : MOVEfromUSP :
flow_controller . move_from_usp ( src . l ) ;
break ;
2022-04-28 20:55:47 +00:00
case Operation : : EXTbtow :
2022-05-04 00:17:36 +00:00
src . w = uint16_t ( int8_t ( src . b ) ) ;
2022-05-12 12:19:41 +00:00
status . overflow_flag = status . carry_flag = 0 ;
status . zero_result = src . w ;
status . negative_flag = status . zero_result & 0x8000 ;
2022-04-28 20:55:47 +00:00
break ;
case Operation : : EXTwtol :
2022-05-04 00:17:36 +00:00
src . l = u_extend16 ( src . w ) ;
2022-05-12 12:19:41 +00:00
status . overflow_flag = status . carry_flag = 0 ;
status . zero_result = src . l ;
status . negative_flag = status . zero_result & 0x80000000 ;
2022-04-28 20:55:47 +00:00
break ;
2022-10-11 19:53:11 +00:00
case Operation : : ANDItoSR : Primitive : : apply_sr_ccr < Operation : : ANDItoSR > ( src . w , status , flow_controller ) ; break ;
case Operation : : EORItoSR : Primitive : : apply_sr_ccr < Operation : : EORItoSR > ( src . w , status , flow_controller ) ; break ;
case Operation : : ORItoSR : Primitive : : apply_sr_ccr < Operation : : ORItoSR > ( src . w , status , flow_controller ) ; break ;
case Operation : : ANDItoCCR : Primitive : : apply_sr_ccr < Operation : : ANDItoCCR > ( src . w , status , flow_controller ) ; break ;
case Operation : : EORItoCCR : Primitive : : apply_sr_ccr < Operation : : EORItoCCR > ( src . w , status , flow_controller ) ; break ;
case Operation : : ORItoCCR : Primitive : : apply_sr_ccr < Operation : : ORItoCCR > ( src . w , status , flow_controller ) ; break ;
2022-04-28 20:55:47 +00:00
/*
Multiplications .
*/
2022-10-11 20:02:20 +00:00
case Operation : : MULU : Primitive : : multiply < true > ( src . w , dest . l , status , flow_controller ) ; break ;
case Operation : : MULS : Primitive : : multiply < false > ( src . w , dest . l , status , flow_controller ) ; break ;
2022-04-28 20:55:47 +00:00
/*
Divisions .
*/
2022-10-11 20:16:53 +00:00
case Operation : : DIVU : Primitive : : divide < true , uint16_t , uint32_t > ( src . w , dest . l , status , flow_controller ) ; break ;
case Operation : : DIVS : Primitive : : divide < false , int16_t , int32_t > ( src . w , dest . l , status , flow_controller ) ; break ;
2022-04-28 20:55:47 +00:00
// TRAP, which is a nicer form of ILLEGAL.
2022-04-29 18:43:30 +00:00
case Operation : : TRAP :
2022-05-24 15:05:24 +00:00
flow_controller . template raise_exception < false > ( int ( src . l + Exception : : TrapBase ) ) ;
2022-04-29 18:43:30 +00:00
break ;
2022-04-28 20:55:47 +00:00
2022-04-29 18:43:30 +00:00
case Operation : : TRAPV : {
2022-05-12 12:19:41 +00:00
if ( status . overflow_flag ) {
2022-05-11 11:00:35 +00:00
flow_controller . template raise_exception < false > ( Exception : : TRAPV ) ;
2022-04-29 18:43:30 +00:00
}
} break ;
2022-04-28 20:55:47 +00:00
case Operation : : CHK : {
2022-04-29 08:51:02 +00:00
const bool is_under = s_extend16 ( dest . w ) < 0 ;
const bool is_over = s_extend16 ( dest . w ) > s_extend16 ( src . w ) ;
2022-04-28 20:55:47 +00:00
2022-05-12 12:19:41 +00:00
status . overflow_flag = status . carry_flag = 0 ;
status . zero_result = dest . w ;
2022-04-28 20:55:47 +00:00
// Test applied for N:
//
// if Dn < 0, set negative flag;
// otherwise, if Dn > <ea>, reset negative flag.
2022-05-12 12:19:41 +00:00
if ( is_over ) status . negative_flag = 0 ;
if ( is_under ) status . negative_flag = 1 ;
2022-04-28 20:55:47 +00:00
// No exception is the default course of action; deviate only if an
// exception is necessary.
2022-05-10 00:58:51 +00:00
flow_controller . did_chk ( is_under , is_over ) ;
2022-04-28 20:55:47 +00:00
if ( is_under | | is_over ) {
2022-05-11 11:00:35 +00:00
flow_controller . template raise_exception < false > ( Exception : : CHK ) ;
2022-04-28 20:55:47 +00:00
}
} break ;
/*
NEGs : negatives the destination , setting the zero ,
negative , overflow and carry flags appropriate , and extend .
NB : since the same logic as SUB is used to calculate overflow ,
and SUB calculates ` destination - source ` , the NEGs deliberately
label ' source ' and ' destination ' differently from Motorola .
*/
case Operation : : NEGb : {
const int destination = 0 ;
2022-05-06 15:33:57 +00:00
const int source = src . b ;
2022-04-28 20:55:47 +00:00
const auto result = destination - source ;
2022-05-06 15:33:57 +00:00
src . b = uint8_t ( result ) ;
2022-04-28 20:55:47 +00:00
2022-05-12 12:19:41 +00:00
status . zero_result = result & 0xff ;
2022-05-12 15:42:33 +00:00
status . extend_flag = status . carry_flag = Status : : FlagT ( result & ~ 0xff ) ;
2022-05-12 12:19:41 +00:00
status . negative_flag = result & 0x80 ;
2022-10-11 02:21:13 +00:00
status . overflow_flag = Primitive : : overflow < false > ( uint8_t ( source ) , uint8_t ( destination ) , uint8_t ( result ) ) ;
2022-04-28 20:55:47 +00:00
} break ;
case Operation : : NEGw : {
const int destination = 0 ;
2022-05-06 15:33:57 +00:00
const int source = src . w ;
2022-04-28 20:55:47 +00:00
const auto result = destination - source ;
2022-05-06 15:33:57 +00:00
src . w = uint16_t ( result ) ;
2022-04-28 20:55:47 +00:00
2022-05-12 12:19:41 +00:00
status . zero_result = result & 0xffff ;
2022-05-12 15:42:33 +00:00
status . extend_flag = status . carry_flag = Status : : FlagT ( result & ~ 0xffff ) ;
2022-05-12 12:19:41 +00:00
status . negative_flag = result & 0x8000 ;
2022-10-11 02:21:13 +00:00
status . overflow_flag = Primitive : : overflow < false > ( uint16_t ( source ) , uint16_t ( destination ) , uint16_t ( result ) ) ;
2022-04-28 20:55:47 +00:00
} break ;
case Operation : : NEGl : {
const uint64_t destination = 0 ;
2022-05-06 15:33:57 +00:00
const uint64_t source = src . l ;
2022-04-28 20:55:47 +00:00
const auto result = destination - source ;
2022-05-06 15:33:57 +00:00
src . l = uint32_t ( result ) ;
2022-04-28 20:55:47 +00:00
2022-05-12 12:19:41 +00:00
status . zero_result = uint_fast32_t ( result ) ;
status . extend_flag = status . carry_flag = result > > 32 ;
status . negative_flag = result & 0x80000000 ;
2022-10-11 02:21:13 +00:00
status . overflow_flag = Primitive : : overflow < false > ( uint32_t ( source ) , uint32_t ( destination ) , uint32_t ( result ) ) ;
2022-04-28 20:55:47 +00:00
} break ;
/*
NEGXs : NEG , with extend .
*/
case Operation : : NEGXb : {
2022-05-06 15:33:57 +00:00
const int source = src . b ;
2022-04-28 20:55:47 +00:00
const int destination = 0 ;
2022-05-12 12:19:41 +00:00
const auto result = destination - source - ( status . extend_flag ? 1 : 0 ) ;
2022-05-06 15:33:57 +00:00
src . b = uint8_t ( result ) ;
2022-04-28 20:55:47 +00:00
2022-05-12 12:19:41 +00:00
status . zero_result | = result & 0xff ;
2022-05-12 15:42:33 +00:00
status . extend_flag = status . carry_flag = Status : : FlagT ( result & ~ 0xff ) ;
2022-05-12 12:19:41 +00:00
status . negative_flag = result & 0x80 ;
2022-10-11 02:21:13 +00:00
status . overflow_flag = Primitive : : overflow < false > ( uint8_t ( source ) , uint8_t ( destination ) , uint8_t ( result ) ) ;
2022-04-28 20:55:47 +00:00
} break ;
case Operation : : NEGXw : {
2022-05-06 15:33:57 +00:00
const int source = src . w ;
2022-04-28 20:55:47 +00:00
const int destination = 0 ;
2022-05-12 12:19:41 +00:00
const auto result = destination - source - ( status . extend_flag ? 1 : 0 ) ;
2022-05-06 15:33:57 +00:00
src . w = uint16_t ( result ) ;
2022-04-28 20:55:47 +00:00
2022-05-12 12:19:41 +00:00
status . zero_result | = result & 0xffff ;
2022-05-12 15:42:33 +00:00
status . extend_flag = status . carry_flag = Status : : FlagT ( result & ~ 0xffff ) ;
2022-05-12 12:19:41 +00:00
status . negative_flag = result & 0x8000 ;
2022-10-11 02:21:13 +00:00
status . overflow_flag = Primitive : : overflow < false > ( uint16_t ( source ) , uint16_t ( destination ) , uint16_t ( result ) ) ;
2022-04-28 20:55:47 +00:00
} break ;
case Operation : : NEGXl : {
2022-05-06 15:33:57 +00:00
const uint64_t source = src . l ;
2022-04-28 20:55:47 +00:00
const uint64_t destination = 0 ;
2022-05-12 12:19:41 +00:00
const auto result = destination - source - ( status . extend_flag ? 1 : 0 ) ;
2022-05-06 15:33:57 +00:00
src . l = uint32_t ( result ) ;
2022-04-28 20:55:47 +00:00
2022-05-12 12:19:41 +00:00
status . zero_result | = uint_fast32_t ( result ) ;
status . extend_flag = status . carry_flag = result > > 32 ;
status . negative_flag = result & 0x80000000 ;
2022-10-11 02:21:13 +00:00
status . overflow_flag = Primitive : : overflow < false > ( uint32_t ( source ) , uint32_t ( destination ) , uint32_t ( result ) ) ;
2022-04-28 20:55:47 +00:00
} break ;
/*
The no - op .
*/
2022-04-29 21:12:06 +00:00
case Operation : : NOP : break ;
2022-04-28 20:55:47 +00:00
/*
LINK and UNLINK help with stack frames , allowing a certain
amount of stack space to be allocated or deallocated .
*/
2022-05-04 12:26:11 +00:00
case Operation : : LINKw :
2022-05-24 15:05:24 +00:00
flow_controller . link ( instruction , uint32_t ( int16_t ( dest . w ) ) ) ;
2022-05-04 12:26:11 +00:00
break ;
2022-04-29 18:43:30 +00:00
2022-05-04 12:26:11 +00:00
case Operation : : UNLINK :
flow_controller . unlink ( src . l ) ;
break ;
2022-04-28 20:55:47 +00:00
/*
TAS : sets zero and negative depending on the current value of the destination ,
2022-05-06 16:18:56 +00:00
and sets the high bit , using a specialised atomic bus cycle .
2022-04-28 20:55:47 +00:00
*/
case Operation : : TAS :
2022-05-06 16:23:04 +00:00
flow_controller . tas ( instruction , src . l ) ;
2022-04-28 20:55:47 +00:00
break ;
/*
Bitwise operators : AND , OR and EOR . All three clear the overflow and carry flags ,
and set zero and negative appropriately .
*/
# define op_and(x, y) x &= y
# define op_or(x, y) x |= y
# define op_eor(x, y) x ^= y
# define bitwise(source, dest, sign_mask, operator) \
operator ( dest , source ) ; \
2022-05-12 12:19:41 +00:00
status . overflow_flag = status . carry_flag = 0 ; \
status . zero_result = dest ; \
status . negative_flag = dest & sign_mask ;
2022-04-28 20:55:47 +00:00
# define andx(source, dest, sign_mask) bitwise(source, dest, sign_mask, op_and)
# define eorx(source, dest, sign_mask) bitwise(source, dest, sign_mask, op_eor)
# define orx(source, dest, sign_mask) bitwise(source, dest, sign_mask, op_or)
2022-04-29 08:51:02 +00:00
# define op_bwl(name, op) \
case Operation : : name # # b : op ( src . b , dest . b , 0x80 ) ; break ; \
case Operation : : name # # w : op ( src . w , dest . w , 0x8000 ) ; break ; \
case Operation : : name # # l : op ( src . l , dest . l , 0x80000000 ) ; break ;
2022-04-28 20:55:47 +00:00
op_bwl ( AND , andx ) ;
op_bwl ( EOR , eorx ) ;
op_bwl ( OR , orx ) ;
# undef op_bwl
# undef orx
# undef eorx
# undef andx
# undef bitwise
# undef op_eor
# undef op_or
# undef op_and
// NOTs: take the logical inverse, affecting the negative and zero flags.
case Operation : : NOTb :
2022-05-06 15:33:57 +00:00
src . b ^ = 0xff ;
2022-05-12 12:19:41 +00:00
status . zero_result = src . b ;
status . negative_flag = status . zero_result & 0x80 ;
status . overflow_flag = status . carry_flag = 0 ;
2022-04-28 20:55:47 +00:00
break ;
case Operation : : NOTw :
2022-05-06 15:33:57 +00:00
src . w ^ = 0xffff ;
2022-05-12 12:19:41 +00:00
status . zero_result = src . w ;
status . negative_flag = status . zero_result & 0x8000 ;
status . overflow_flag = status . carry_flag = 0 ;
2022-04-28 20:55:47 +00:00
break ;
case Operation : : NOTl :
2022-05-06 15:33:57 +00:00
src . l ^ = 0xffffffff ;
2022-05-12 12:19:41 +00:00
status . zero_result = src . l ;
status . negative_flag = status . zero_result & 0x80000000 ;
status . overflow_flag = status . carry_flag = 0 ;
2022-04-28 20:55:47 +00:00
break ;
2022-05-12 19:18:03 +00:00
# define sbcd(d) \
const int extend = ( status . extend_flag ? 1 : 0 ) ; \
const int unadjusted_result = destination - source - extend ; \
\
const int top = ( destination & 0xf0 ) - ( source & 0xf0 ) - ( 0x60 & ( unadjusted_result > > 4 ) ) ; \
\
int result = ( destination & 0xf ) - ( source & 0xf ) - extend ; \
const int low_adjustment = 0x06 & ( result > > 4 ) ; \
status . extend_flag = status . carry_flag = Status : : FlagT ( \
( unadjusted_result - low_adjustment ) & 0x300 \
) ; \
result = result + top - low_adjustment ; \
\
/* Store the result. */ \
d = uint8_t ( result ) ; \
\
/* Set all remaining flags essentially as if this were normal subtraction. */ \
status . zero_result | = d ; \
status . negative_flag = result & 0x80 ; \
status . overflow_flag = unadjusted_result & ~ result & 0x80 ; \
2022-04-28 20:55:47 +00:00
/*
SBCD subtracts the lowest byte of the source from that of the destination using
BCD arithmetic , obeying the extend flag .
*/
case Operation : : SBCD : {
2022-04-29 08:51:02 +00:00
const uint8_t source = src . b ;
const uint8_t destination = dest . b ;
2022-05-02 16:57:45 +00:00
sbcd ( dest . b ) ;
2022-04-28 20:55:47 +00:00
} break ;
/*
2022-05-02 16:57:45 +00:00
NBCD is like SBCD except that the result is 0 - source rather than
2022-04-28 20:55:47 +00:00
destination - source .
*/
case Operation : : NBCD : {
2022-05-02 16:57:45 +00:00
const uint8_t source = src . b ;
2022-04-28 20:55:47 +00:00
const uint8_t destination = 0 ;
2022-05-02 16:57:45 +00:00
sbcd ( src . b ) ;
2022-04-28 20:55:47 +00:00
} break ;
2022-05-02 11:45:07 +00:00
# undef sbcd
2022-04-28 20:55:47 +00:00
// EXG and SWAP exchange/swap words or long words.
case Operation : : EXG : {
2022-04-29 08:51:02 +00:00
const auto temporary = src . l ;
src . l = dest . l ;
dest . l = temporary ;
2022-04-28 20:55:47 +00:00
} break ;
case Operation : : SWAP : {
2022-05-04 00:17:36 +00:00
uint16_t * const words = reinterpret_cast < uint16_t * > ( & src . l ) ;
2022-04-29 08:51:02 +00:00
const auto temporary = words [ 0 ] ;
words [ 0 ] = words [ 1 ] ;
words [ 1 ] = temporary ;
2022-04-28 20:55:47 +00:00
2022-05-12 12:19:41 +00:00
status . zero_result = src . l ;
status . negative_flag = temporary & 0x8000 ;
status . overflow_flag = status . carry_flag = 0 ;
2022-04-28 20:55:47 +00:00
} break ;
/*
Shifts and rotates .
*/
2022-05-12 12:19:41 +00:00
# define set_neg_zero(v, m) \
2022-05-12 15:42:33 +00:00
status . zero_result = Status : : FlagT ( v ) ; \
status . negative_flag = status . zero_result & Status : : FlagT ( m ) ;
2022-04-28 20:55:47 +00:00
# define set_neg_zero_overflow(v, m) \
set_neg_zero ( v , m ) ; \
2022-05-12 15:42:33 +00:00
status . overflow_flag = ( Status : : FlagT ( value ) ^ status . zero_result ) & Status : : FlagT ( m ) ;
2022-04-28 20:55:47 +00:00
2022-06-02 00:30:51 +00:00
# define decode_shift_count(type) \
2022-05-09 15:26:01 +00:00
int shift_count = src . l & 63 ; \
2022-06-02 00:30:51 +00:00
flow_controller . template did_shift < type > ( shift_count ) ;
2022-04-28 20:55:47 +00:00
2022-05-04 23:44:59 +00:00
# define set_flags_w(t) set_flags(src.w, 0x8000, t)
2022-04-28 20:55:47 +00:00
# define asl(destination, size) {\
2022-06-02 00:30:51 +00:00
decode_shift_count ( decltype ( destination ) ) ; \
2022-04-28 20:55:47 +00:00
const auto value = destination ; \
\
if ( ! shift_count ) { \
2022-05-12 12:19:41 +00:00
status . carry_flag = status . overflow_flag = 0 ; \
2022-04-28 20:55:47 +00:00
} else { \
destination = ( shift_count < size ) ? decltype ( destination ) ( value < < shift_count ) : 0 ; \
2022-05-12 15:42:33 +00:00
status . extend_flag = status . carry_flag = Status : : FlagT ( value ) & Status : : FlagT ( ( 1u < < ( size - 1 ) ) > > ( shift_count - 1 ) ) ; \
2022-04-28 20:55:47 +00:00
\
2022-05-12 12:19:41 +00:00
if ( shift_count > = size ) status . overflow_flag = value & & ( value ! = decltype ( value ) ( - 1 ) ) ; \
2022-04-28 20:55:47 +00:00
else { \
const auto mask = decltype ( destination ) ( 0xffffffff < < ( size - shift_count ) ) ; \
2022-05-12 12:19:41 +00:00
status . overflow_flag = mask & value & & ( ( mask & value ) ! = mask ) ; \
2022-04-28 20:55:47 +00:00
} \
} \
\
set_neg_zero ( destination , 1 < < ( size - 1 ) ) ; \
}
case Operation : : ASLm : {
2022-05-04 23:44:59 +00:00
const auto value = src . w ;
src . w = uint16_t ( value < < 1 ) ;
2022-05-12 12:19:41 +00:00
status . extend_flag = status . carry_flag = value & 0x8000 ;
2022-05-04 23:44:59 +00:00
set_neg_zero_overflow ( src . w , 0x8000 ) ;
2022-04-28 20:55:47 +00:00
} break ;
2022-05-09 15:26:01 +00:00
case Operation : : ASLb : asl ( dest . b , 8 ) ; break ;
case Operation : : ASLw : asl ( dest . w , 16 ) ; break ;
case Operation : : ASLl : asl ( dest . l , 32 ) ; break ;
2022-04-28 20:55:47 +00:00
# define asr(destination, size) {\
2022-06-02 00:30:51 +00:00
decode_shift_count ( decltype ( destination ) ) ; \
2022-04-28 20:55:47 +00:00
const auto value = destination ; \
\
if ( ! shift_count ) { \
2022-05-12 12:19:41 +00:00
status . carry_flag = 0 ; \
2022-04-28 20:55:47 +00:00
} else { \
destination = ( shift_count < size ) ? \
decltype ( destination ) ( \
( value > > shift_count ) | \
( ( value & decltype ( value ) ( 1 < < ( size - 1 ) ) ? 0xffffffff : 0x000000000 ) < < ( size - shift_count ) ) \
) : \
decltype ( destination ) ( \
( value & decltype ( value ) ( 1 < < ( size - 1 ) ) ) ? 0xffffffff : 0x000000000 \
) ; \
2022-05-12 15:42:33 +00:00
status . extend_flag = status . carry_flag = Status : : FlagT ( value ) & Status : : FlagT ( 1 < < ( shift_count - 1 ) ) ; \
2022-04-28 20:55:47 +00:00
} \
\
set_neg_zero_overflow ( destination , 1 < < ( size - 1 ) ) ; \
}
case Operation : : ASRm : {
2022-05-04 23:44:59 +00:00
const auto value = src . w ;
src . w = ( value & 0x8000 ) | ( value > > 1 ) ;
2022-05-12 12:19:41 +00:00
status . extend_flag = status . carry_flag = value & 1 ;
2022-05-04 23:44:59 +00:00
set_neg_zero_overflow ( src . w , 0x8000 ) ;
2022-04-28 20:55:47 +00:00
} break ;
2022-05-09 15:26:01 +00:00
case Operation : : ASRb : asr ( dest . b , 8 ) ; break ;
case Operation : : ASRw : asr ( dest . w , 16 ) ; break ;
case Operation : : ASRl : asr ( dest . l , 32 ) ; break ;
2022-04-28 20:55:47 +00:00
# undef set_neg_zero_overflow
# define set_neg_zero_overflow(v, m) \
set_neg_zero ( v , m ) ; \
2022-05-12 12:19:41 +00:00
status . overflow_flag = 0 ;
2022-04-28 20:55:47 +00:00
# undef set_flags
# define set_flags(v, m, t) \
2022-05-12 12:19:41 +00:00
status . zero_result = v ; \
status . negative_flag = status . zero_result & ( m ) ; \
status . overflow_flag = 0 ; \
status . carry_flag = value & ( t ) ;
2022-04-28 20:55:47 +00:00
# define lsl(destination, size) {\
2022-06-02 00:30:51 +00:00
decode_shift_count ( decltype ( destination ) ) ; \
2022-04-28 20:55:47 +00:00
const auto value = destination ; \
\
if ( ! shift_count ) { \
2022-05-12 12:19:41 +00:00
status . carry_flag = 0 ; \
2022-04-28 20:55:47 +00:00
} else { \
destination = ( shift_count < size ) ? decltype ( destination ) ( value < < shift_count ) : 0 ; \
2022-05-12 15:42:33 +00:00
status . extend_flag = status . carry_flag = Status : : FlagT ( value ) & Status : : FlagT ( ( 1u < < ( size - 1 ) ) > > ( shift_count - 1 ) ) ; \
2022-04-28 20:55:47 +00:00
} \
\
set_neg_zero_overflow ( destination , 1 < < ( size - 1 ) ) ; \
}
case Operation : : LSLm : {
2022-05-04 23:44:59 +00:00
const auto value = src . w ;
src . w = uint16_t ( value < < 1 ) ;
2022-05-12 12:19:41 +00:00
status . extend_flag = status . carry_flag = value & 0x8000 ;
2022-05-04 23:44:59 +00:00
set_neg_zero_overflow ( src . w , 0x8000 ) ;
2022-04-28 20:55:47 +00:00
} break ;
2022-05-09 15:26:01 +00:00
case Operation : : LSLb : lsl ( dest . b , 8 ) ; break ;
case Operation : : LSLw : lsl ( dest . w , 16 ) ; break ;
case Operation : : LSLl : lsl ( dest . l , 32 ) ; break ;
2022-04-28 20:55:47 +00:00
# define lsr(destination, size) {\
2022-06-02 00:30:51 +00:00
decode_shift_count ( decltype ( destination ) ) ; \
2022-04-28 20:55:47 +00:00
const auto value = destination ; \
\
if ( ! shift_count ) { \
2022-05-12 12:19:41 +00:00
status . carry_flag = 0 ; \
2022-04-28 20:55:47 +00:00
} else { \
destination = ( shift_count < size ) ? ( value > > shift_count ) : 0 ; \
2022-05-12 15:42:33 +00:00
status . extend_flag = status . carry_flag = value & Status : : FlagT ( 1 < < ( shift_count - 1 ) ) ; \
2022-04-28 20:55:47 +00:00
} \
\
set_neg_zero_overflow ( destination , 1 < < ( size - 1 ) ) ; \
}
case Operation : : LSRm : {
2022-05-04 23:44:59 +00:00
const auto value = src . w ;
src . w = value > > 1 ;
2022-05-12 12:19:41 +00:00
status . extend_flag = status . carry_flag = value & 1 ;
2022-05-04 23:44:59 +00:00
set_neg_zero_overflow ( src . w , 0x8000 ) ;
2022-04-28 20:55:47 +00:00
} break ;
2022-05-09 15:26:01 +00:00
case Operation : : LSRb : lsr ( dest . b , 8 ) ; break ;
case Operation : : LSRw : lsr ( dest . w , 16 ) ; break ;
case Operation : : LSRl : lsr ( dest . l , 32 ) ; break ;
2022-04-28 20:55:47 +00:00
# define rol(destination, size) { \
2022-06-02 00:30:51 +00:00
decode_shift_count ( decltype ( destination ) ) ; \
2022-04-28 20:55:47 +00:00
const auto value = destination ; \
\
if ( ! shift_count ) { \
2022-05-12 12:19:41 +00:00
status . carry_flag = 0 ; \
2022-04-28 20:55:47 +00:00
} else { \
shift_count & = ( size - 1 ) ; \
destination = decltype ( destination ) ( \
( value < < shift_count ) | \
( value > > ( size - shift_count ) ) \
) ; \
2022-05-12 15:42:33 +00:00
status . carry_flag = Status : : FlagT ( destination & 1 ) ; \
2022-04-28 20:55:47 +00:00
} \
\
set_neg_zero_overflow ( destination , 1 < < ( size - 1 ) ) ; \
}
case Operation : : ROLm : {
2022-05-04 23:44:59 +00:00
const auto value = src . w ;
src . w = uint16_t ( ( value < < 1 ) | ( value > > 15 ) ) ;
2022-05-12 12:19:41 +00:00
status . carry_flag = src . w & 1 ;
2022-05-04 23:44:59 +00:00
set_neg_zero_overflow ( src . w , 0x8000 ) ;
2022-04-28 20:55:47 +00:00
} break ;
2022-05-09 15:26:01 +00:00
case Operation : : ROLb : rol ( dest . b , 8 ) ; break ;
case Operation : : ROLw : rol ( dest . w , 16 ) ; break ;
case Operation : : ROLl : rol ( dest . l , 32 ) ; break ;
2022-04-28 20:55:47 +00:00
# define ror(destination, size) { \
2022-06-02 00:30:51 +00:00
decode_shift_count ( decltype ( destination ) ) ; \
2022-04-28 20:55:47 +00:00
const auto value = destination ; \
\
if ( ! shift_count ) { \
2022-05-12 12:19:41 +00:00
status . carry_flag = 0 ; \
2022-04-28 20:55:47 +00:00
} else { \
shift_count & = ( size - 1 ) ; \
destination = decltype ( destination ) ( \
( value > > shift_count ) | \
( value < < ( size - shift_count ) ) \
) ; \
2022-05-12 15:42:33 +00:00
status . carry_flag = destination & Status : : FlagT ( 1 < < ( size - 1 ) ) ; \
2022-04-28 20:55:47 +00:00
} \
\
set_neg_zero_overflow ( destination , 1 < < ( size - 1 ) ) ; \
}
case Operation : : RORm : {
2022-05-04 23:44:59 +00:00
const auto value = src . w ;
src . w = uint16_t ( ( value > > 1 ) | ( value < < 15 ) ) ;
2022-05-12 12:19:41 +00:00
status . carry_flag = src . w & 0x8000 ;
2022-05-04 23:44:59 +00:00
set_neg_zero_overflow ( src . w , 0x8000 ) ;
2022-04-28 20:55:47 +00:00
} break ;
2022-05-09 15:26:01 +00:00
case Operation : : RORb : ror ( dest . b , 8 ) ; break ;
case Operation : : RORw : ror ( dest . w , 16 ) ; break ;
case Operation : : RORl : ror ( dest . l , 32 ) ; break ;
2022-04-28 20:55:47 +00:00
# define roxl(destination, size) { \
2022-06-02 00:30:51 +00:00
decode_shift_count ( decltype ( destination ) ) ; \
2022-05-09 15:26:01 +00:00
\
2022-04-28 20:55:47 +00:00
shift_count % = ( size + 1 ) ; \
2022-05-12 12:19:41 +00:00
uint64_t compound = uint64_t ( destination ) | ( status . extend_flag ? ( 1ull < < size ) : 0 ) ; \
2022-04-28 20:55:47 +00:00
compound = \
( compound < < shift_count ) | \
( compound > > ( size + 1 - shift_count ) ) ; \
2022-05-12 15:42:33 +00:00
status . carry_flag = status . extend_flag = Status : : FlagT ( ( compound > > size ) & 1 ) ; \
2022-04-28 20:55:47 +00:00
destination = decltype ( destination ) ( compound ) ; \
\
set_neg_zero_overflow ( destination , 1 < < ( size - 1 ) ) ; \
}
case Operation : : ROXLm : {
2022-05-04 23:44:59 +00:00
const auto value = src . w ;
2022-05-12 12:19:41 +00:00
src . w = uint16_t ( ( value < < 1 ) | ( status . extend_flag ? 0x0001 : 0x0000 ) ) ;
status . extend_flag = value & 0x8000 ;
2022-04-28 20:55:47 +00:00
set_flags_w ( 0x8000 ) ;
} break ;
2022-05-09 15:26:01 +00:00
case Operation : : ROXLb : roxl ( dest . b , 8 ) ; break ;
case Operation : : ROXLw : roxl ( dest . w , 16 ) ; break ;
case Operation : : ROXLl : roxl ( dest . l , 32 ) ; break ;
2022-04-28 20:55:47 +00:00
# define roxr(destination, size) { \
2022-06-02 00:30:51 +00:00
decode_shift_count ( decltype ( destination ) ) ; \
2022-04-28 20:55:47 +00:00
\
shift_count % = ( size + 1 ) ; \
2022-05-12 12:19:41 +00:00
uint64_t compound = uint64_t ( destination ) | ( status . extend_flag ? ( 1ull < < size ) : 0 ) ; \
2022-04-28 20:55:47 +00:00
compound = \
( compound > > shift_count ) | \
( compound < < ( size + 1 - shift_count ) ) ; \
2022-05-12 15:42:33 +00:00
status . carry_flag = status . extend_flag = Status : : FlagT ( ( compound > > size ) & 1 ) ; \
2022-04-28 20:55:47 +00:00
destination = decltype ( destination ) ( compound ) ; \
\
set_neg_zero_overflow ( destination , 1 < < ( size - 1 ) ) ; \
}
case Operation : : ROXRm : {
2022-05-04 23:44:59 +00:00
const auto value = src . w ;
2022-05-12 12:19:41 +00:00
src . w = ( value > > 1 ) | ( status . extend_flag ? 0x8000 : 0x0000 ) ;
status . extend_flag = value & 0x0001 ;
2022-04-28 20:55:47 +00:00
set_flags_w ( 0x0001 ) ;
} break ;
2022-05-09 15:26:01 +00:00
case Operation : : ROXRb : roxr ( dest . b , 8 ) ; break ;
case Operation : : ROXRw : roxr ( dest . w , 16 ) ; break ;
case Operation : : ROXRl : roxr ( dest . l , 32 ) ; break ;
2022-04-28 20:55:47 +00:00
# undef roxr
# undef roxl
# undef ror
# undef rol
# undef asr
# undef lsr
# undef lsl
# undef asl
# undef set_flags
# undef decode_shift_count
# undef set_flags_w
# undef set_neg_zero_overflow
2022-05-02 11:45:07 +00:00
# undef set_neg_zero
2022-04-28 20:55:47 +00:00
2022-05-05 13:00:33 +00:00
case Operation : : MOVEPl :
2022-05-05 16:27:36 +00:00
flow_controller . template movep < uint32_t > ( instruction , src . l , dest . l ) ;
2022-05-05 13:00:33 +00:00
break ;
case Operation : : MOVEPw :
2022-05-05 16:27:36 +00:00
flow_controller . template movep < uint16_t > ( instruction , src . l , dest . l ) ;
2022-05-05 13:00:33 +00:00
break ;
2022-05-06 13:45:06 +00:00
case Operation : : MOVEMtoRl :
flow_controller . template movem_toR < uint32_t > ( instruction , src . l , dest . l ) ;
2022-05-05 16:42:57 +00:00
break ;
2022-05-06 13:45:06 +00:00
case Operation : : MOVEMtoMl :
flow_controller . template movem_toM < uint32_t > ( instruction , src . l , dest . l ) ;
break ;
case Operation : : MOVEMtoRw :
flow_controller . template movem_toR < uint16_t > ( instruction , src . l , dest . l ) ;
break ;
case Operation : : MOVEMtoMw :
flow_controller . template movem_toM < uint16_t > ( instruction , src . l , dest . l ) ;
2022-05-05 16:42:57 +00:00
break ;
2022-04-28 20:55:47 +00:00
/*
RTE and RTR share an implementation .
*/
2022-05-06 16:30:49 +00:00
case Operation : : RTR :
flow_controller . rtr ( ) ;
break ;
2022-04-29 21:12:06 +00:00
2022-05-06 16:30:49 +00:00
case Operation : : RTE :
flow_controller . rte ( ) ;
break ;
case Operation : : RTS :
flow_controller . rts ( ) ;
break ;
2022-04-28 20:55:47 +00:00
/*
TSTs : compare to zero .
*/
case Operation : : TSTb :
2022-05-12 12:19:41 +00:00
status . carry_flag = status . overflow_flag = 0 ;
status . zero_result = src . b ;
status . negative_flag = status . zero_result & 0x80 ;
2022-04-28 20:55:47 +00:00
break ;
case Operation : : TSTw :
2022-05-12 12:19:41 +00:00
status . carry_flag = status . overflow_flag = 0 ;
status . zero_result = src . w ;
status . negative_flag = status . zero_result & 0x8000 ;
2022-04-28 20:55:47 +00:00
break ;
case Operation : : TSTl :
2022-05-12 12:19:41 +00:00
status . carry_flag = status . overflow_flag = 0 ;
status . zero_result = src . l ;
status . negative_flag = status . zero_result & 0x80000000 ;
2022-04-28 20:55:47 +00:00
break ;
2022-04-29 18:43:30 +00:00
case Operation : : STOP :
status . set_status ( src . w ) ;
2022-05-08 01:29:12 +00:00
flow_controller . did_update_status ( ) ;
2022-04-29 18:43:30 +00:00
flow_controller . stop ( ) ;
break ;
2022-04-28 20:55:47 +00:00
2022-05-11 11:52:23 +00:00
case Operation : : RESET :
flow_controller . reset ( ) ;
break ;
2022-04-28 20:55:47 +00:00
/*
Development period debugging .
*/
default :
assert ( false ) ;
break ;
}
# undef u_extend16
# undef s_extend16
}
}
}
# endif /* InstructionSets_M68k_PerformImplementation_h */