mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-11 14:37:37 +00:00
Implements CLR, NEG, NEGX and NOT.
This commit is contained in:
parent
06a2f59bd0
commit
652f4ebfed
Processors/68000/Implementation
@ -58,6 +58,9 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
active_micro_op_ = active_program_->micro_operations;
|
||||
}
|
||||
|
||||
#define sub_overflow() (source ^ destination) & (destination ^ result)
|
||||
#define add_overflow() ~(source ^ destination) & (destination ^ result)
|
||||
|
||||
switch(active_micro_op_->action) {
|
||||
default:
|
||||
std::cerr << "Unhandled 68000 micro op action " << std::hex << active_micro_op_->action << std::endl;
|
||||
@ -86,7 +89,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
zero_result_ |= result & 0xff;
|
||||
extend_flag_ = carry_flag_ = result & ~0xff;
|
||||
negative_flag_ = result & 0x80;
|
||||
overflow_flag_ = ~(source ^ destination) & (destination ^ result) & 0x80;
|
||||
overflow_flag_ = add_overflow() & 0x80;
|
||||
|
||||
// Store the result.
|
||||
active_program_->destination->halves.low.halves.low = uint8_t(result);
|
||||
@ -101,7 +104,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
zero_result_ = active_program_->destination->halves.low.halves.low = uint8_t(result);
|
||||
extend_flag_ = carry_flag_ = result & ~0xff;
|
||||
negative_flag_ = result & 0x80;
|
||||
overflow_flag_ = ~(source ^ destination) & (destination ^ result) & 0x80;
|
||||
overflow_flag_ = add_overflow() & 0x80;
|
||||
} break;
|
||||
|
||||
case Operation::ADDw: {
|
||||
@ -112,7 +115,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
zero_result_ = active_program_->destination->halves.low.full = uint16_t(result);
|
||||
extend_flag_ = carry_flag_ = result & ~0xffff;
|
||||
negative_flag_ = result & 0x8000;
|
||||
overflow_flag_ = ~(source ^ destination) & (destination ^ result) & 0x8000;
|
||||
overflow_flag_ = add_overflow() & 0x8000;
|
||||
} break;
|
||||
|
||||
case Operation::ADDl: {
|
||||
@ -123,7 +126,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
zero_result_ = active_program_->destination->halves.low.full = uint32_t(result);
|
||||
extend_flag_ = carry_flag_ = result >> 32;
|
||||
negative_flag_ = result & 0x80000000;
|
||||
overflow_flag_ = ~(source ^ destination) & (destination ^ result) & 0x80000000;
|
||||
overflow_flag_ = add_overflow() & 0x80000000;
|
||||
} break;
|
||||
|
||||
case Operation::ADDAw:
|
||||
@ -210,6 +213,25 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
}
|
||||
} break;
|
||||
|
||||
/*
|
||||
CLRs: store 0 to the destination, set the zero flag, and clear
|
||||
negative, overflow and carry.
|
||||
*/
|
||||
case Operation::CLRb:
|
||||
active_program_->destination->halves.low.halves.low = 0;
|
||||
negative_flag_ = overflow_flag_ = carry_flag_ = zero_result_ = 0;
|
||||
break;
|
||||
|
||||
case Operation::CLRw:
|
||||
active_program_->destination->halves.low.full = 0;
|
||||
negative_flag_ = overflow_flag_ = carry_flag_ = zero_result_ = 0;
|
||||
break;
|
||||
|
||||
case Operation::CLRl:
|
||||
active_program_->destination->full = 0;
|
||||
negative_flag_ = overflow_flag_ = carry_flag_ = zero_result_ = 0;
|
||||
break;
|
||||
|
||||
/*
|
||||
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.
|
||||
@ -222,7 +244,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
zero_result_ = result & 0xff;
|
||||
carry_flag_ = result & ~0xff;
|
||||
negative_flag_ = result & 0x80;
|
||||
overflow_flag_ = (source ^ destination) & (destination ^ result) & 0x80;
|
||||
overflow_flag_ = sub_overflow() & 0x80;
|
||||
} break;
|
||||
|
||||
case Operation::CMPw: {
|
||||
@ -233,7 +255,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
zero_result_ = result & 0xffff;
|
||||
carry_flag_ = result & ~0xffff;
|
||||
negative_flag_ = result & 0x8000;
|
||||
overflow_flag_ = (source ^ destination) & (destination ^ result) & 0x8000;
|
||||
overflow_flag_ = sub_overflow() & 0x8000;
|
||||
} break;
|
||||
|
||||
case Operation::CMPl: {
|
||||
@ -244,7 +266,7 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
zero_result_ = uint32_t(result);
|
||||
carry_flag_ = result >> 32;
|
||||
negative_flag_ = result & 0x80000000;
|
||||
overflow_flag_ = (source ^ destination) & (destination ^ result) & 0x80000000;
|
||||
overflow_flag_ = sub_overflow() & 0x80000000;
|
||||
} break;
|
||||
|
||||
// JMP: copies the source to the program counter.
|
||||
@ -310,12 +332,111 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
|
||||
active_program_->source->halves.low.full = get_status();
|
||||
break;
|
||||
|
||||
/*
|
||||
NEGs: negatives the destination, setting the zero,
|
||||
negative, overflow and carry flags appropriate, and extend.
|
||||
*/
|
||||
case Operation::NEGb: {
|
||||
const int source = 0;
|
||||
const int destination = active_program_->destination->halves.low.halves.low;
|
||||
const int result = source - destination;
|
||||
active_program_->destination->halves.low.halves.low = result;
|
||||
|
||||
zero_result_ = result & 0xff;
|
||||
extend_flag_ = carry_flag_ = result & ~0xff;
|
||||
negative_flag_ = result & 0x80;
|
||||
overflow_flag_ = sub_overflow() & 0x80;
|
||||
} break;
|
||||
|
||||
case Operation::NEGw: {
|
||||
const int source = 0;
|
||||
const int destination = active_program_->destination->halves.low.full;
|
||||
const int result = source - destination;
|
||||
active_program_->destination->halves.low.full = result;
|
||||
|
||||
zero_result_ = result & 0xffff;
|
||||
extend_flag_ = carry_flag_ = result & ~0xffff;
|
||||
negative_flag_ = result & 0x8000;
|
||||
overflow_flag_ = sub_overflow() & 0x8000;
|
||||
} break;
|
||||
|
||||
case Operation::NEGl: {
|
||||
const int source = 0;
|
||||
const int destination = active_program_->destination->full;
|
||||
int64_t result = source - destination;
|
||||
active_program_->destination->full = uint32_t(result);
|
||||
|
||||
zero_result_ = uint_fast32_t(result);
|
||||
extend_flag_ = carry_flag_ = result >> 32;
|
||||
negative_flag_ = result & 0x80000000;
|
||||
overflow_flag_ = sub_overflow() & 0x80000000;
|
||||
} break;
|
||||
|
||||
/*
|
||||
NEGXs: NEG, with extend.
|
||||
*/
|
||||
case Operation::NEGXb: {
|
||||
const int source = 0;
|
||||
const int destination = active_program_->destination->halves.low.halves.low;
|
||||
const int result = source - destination - (extend_flag_ ? 1 : 0);
|
||||
active_program_->destination->halves.low.halves.low = result;
|
||||
|
||||
zero_result_ = result & 0xff;
|
||||
extend_flag_ = carry_flag_ = result & ~0xff;
|
||||
negative_flag_ = result & 0x80;
|
||||
overflow_flag_ = sub_overflow() & 0x80;
|
||||
} break;
|
||||
|
||||
case Operation::NEGXw: {
|
||||
const int source = 0;
|
||||
const int destination = active_program_->destination->halves.low.full;
|
||||
const int result = source - destination - (extend_flag_ ? 1 : 0);
|
||||
active_program_->destination->halves.low.full = result;
|
||||
|
||||
zero_result_ = result & 0xffff;
|
||||
extend_flag_ = carry_flag_ = result & ~0xffff;
|
||||
negative_flag_ = result & 0x8000;
|
||||
overflow_flag_ = sub_overflow() & 0x8000;
|
||||
} break;
|
||||
|
||||
case Operation::NEGXl: {
|
||||
const int source = 0;
|
||||
const int destination = active_program_->destination->full;
|
||||
int64_t result = source - destination - (extend_flag_ ? 1 : 0);
|
||||
active_program_->destination->full = result;
|
||||
|
||||
zero_result_ = result;
|
||||
extend_flag_ = carry_flag_ = result >> 32;
|
||||
negative_flag_ = result & 0x80000000;
|
||||
overflow_flag_ = sub_overflow() & 0x80000000;
|
||||
} break;
|
||||
|
||||
/*
|
||||
The no-op.
|
||||
*/
|
||||
case Operation::None:
|
||||
break;
|
||||
|
||||
// NOTs: take the logical inverse, affecting the negative and zero flags.
|
||||
|
||||
case Operation::NOTb:
|
||||
active_program_->destination->halves.low.halves.low ^= 0xff;
|
||||
zero_result_ = active_program_->destination->halves.low.halves.low;
|
||||
negative_flag_ = zero_result_ & 0x80;
|
||||
break;
|
||||
|
||||
case Operation::NOTw:
|
||||
active_program_->destination->halves.low.full ^= 0xffff;
|
||||
zero_result_ = active_program_->destination->halves.low.full;
|
||||
negative_flag_ = zero_result_ & 0x8000;
|
||||
break;
|
||||
|
||||
case Operation::NOTl:
|
||||
active_program_->destination->full ^= 0xffffffff;
|
||||
zero_result_ = active_program_->destination->full;
|
||||
negative_flag_ = zero_result_ & 0x80000000;
|
||||
break;
|
||||
|
||||
/*
|
||||
SBCD subtracts the lowest byte of the source from that of the destination using
|
||||
BCD arithmetic, obeying the extend flag.
|
||||
|
@ -270,6 +270,7 @@ struct ProcessorStorageConstructor {
|
||||
BTSTIMM, // six lowest bits are [mode, register], decoding to BTST #
|
||||
CMP,
|
||||
DBcc, // the low three bits nominate a register; everything else is decoded in real time
|
||||
CLRNEGNEGXNOT,
|
||||
};
|
||||
|
||||
using Operation = ProcessorStorage::Operation;
|
||||
@ -343,6 +344,19 @@ struct ProcessorStorageConstructor {
|
||||
{0xffc0, 0x0800, Operation::BTSTb, Decoder::BTSTIMM}, // 4-63 (p167)
|
||||
|
||||
{0xf0f8, 0x50c8, Operation::DBcc, Decoder::DBcc}, // 4-91 (p195)
|
||||
|
||||
{0xffc0, 0x4200, Operation::CLRb, Decoder::CLRNEGNEGXNOT}, // 4-73 (p177)
|
||||
{0xffc0, 0x4240, Operation::CLRw, Decoder::CLRNEGNEGXNOT}, // 4-73 (p177)
|
||||
{0xffc0, 0x4280, Operation::CLRl, Decoder::CLRNEGNEGXNOT}, // 4-73 (p177)
|
||||
{0xffc0, 0x4400, Operation::NEGb, Decoder::CLRNEGNEGXNOT}, // 4-144 (p248)
|
||||
{0xffc0, 0x4440, Operation::NEGw, Decoder::CLRNEGNEGXNOT}, // 4-144 (p248)
|
||||
{0xffc0, 0x4480, Operation::NEGl, Decoder::CLRNEGNEGXNOT}, // 4-144 (p248)
|
||||
{0xffc0, 0x4000, Operation::NEGXb, Decoder::CLRNEGNEGXNOT}, // 4-146 (p250)
|
||||
{0xffc0, 0x4040, Operation::NEGXw, Decoder::CLRNEGNEGXNOT}, // 4-146 (p250)
|
||||
{0xffc0, 0x4080, Operation::NEGXl, Decoder::CLRNEGNEGXNOT}, // 4-146 (p250)
|
||||
{0xffc0, 0x4600, Operation::NOTb, Decoder::CLRNEGNEGXNOT}, // 4-148 (p250)
|
||||
{0xffc0, 0x4640, Operation::NOTw, Decoder::CLRNEGNEGXNOT}, // 4-148 (p250)
|
||||
{0xffc0, 0x4680, Operation::NOTl, Decoder::CLRNEGNEGXNOT}, // 4-148 (p250)
|
||||
};
|
||||
|
||||
std::vector<size_t> micro_op_pointers(65536, std::numeric_limits<size_t>::max());
|
||||
@ -827,6 +841,99 @@ struct ProcessorStorageConstructor {
|
||||
}
|
||||
} break;
|
||||
|
||||
case Decoder::CLRNEGNEGXNOT: {
|
||||
const bool is_byte_access = !!((instruction >> 6)&3);
|
||||
const bool is_long_word_access = ((instruction >> 6)&3) == 2;
|
||||
|
||||
storage_.instructions[instruction].set_destination(storage_, ea_mode, ea_register);
|
||||
|
||||
const int mode = combined_mode(ea_mode, ea_register);
|
||||
switch((is_long_word_access ? 0x100 : 0x000) | mode) {
|
||||
default: continue;
|
||||
|
||||
case 0x000: // [CLR/NEG/NEGX/NOT].bw Dn
|
||||
case 0x100: // [CLR/NEG/NEGX/NOT].l Dn
|
||||
op(Action::PerformOperation, seq("np"));
|
||||
break;
|
||||
|
||||
case 0x002: // [CLR/NEG/NEGX/NOT].bw (An)
|
||||
case 0x003: // [CLR/NEG/NEGX/NOT].bw (An)+
|
||||
op(Action::None, seq("nrd", { a(ea_register) }, !is_byte_access));
|
||||
op(Action::PerformOperation, seq("np nw", { a(ea_register) }, !is_byte_access));
|
||||
if(ea_mode == 0x03) {
|
||||
op(int(is_byte_access ? Action::Increment1 : Action::Increment2) | MicroOp::DestinationMask);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x102: // [CLR/NEG/NEGX/NOT].l (An)
|
||||
case 0x103: // [CLR/NEG/NEGX/NOT].l (An)+
|
||||
op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask, seq("nRd+ nrd", { ea(1), ea(1) }));
|
||||
op(Action::PerformOperation, seq("np nw- nW", { ea(1), ea(1) }));
|
||||
if(ea_mode == 0x03) {
|
||||
op(int(Action::Increment4) | MicroOp::DestinationMask);
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x004: // [CLR/NEG/NEGX/NOT].bw -(An)
|
||||
op( int(is_byte_access ? Action::Decrement1 : Action::Decrement2) | MicroOp::DestinationMask,
|
||||
seq("nrd", { a(ea_register) }, !is_byte_access));
|
||||
op(Action::PerformOperation, seq("np nw", { a(ea_register) }, !is_byte_access));
|
||||
break;
|
||||
|
||||
case 0x104: // [CLR/NEG/NEGX/NOT].l -(An)
|
||||
op(int(Action::Decrement4) | MicroOp::DestinationMask);
|
||||
op(int(Action::CopyToEffectiveAddress) | MicroOp::DestinationMask,
|
||||
seq("n nRd+ nrd", { ea(1), ea(1) }));
|
||||
op(Action::PerformOperation, seq("np nw- nW", { ea(1), ea(1) }));
|
||||
break;
|
||||
|
||||
case 0x005: // [CLR/NEG/NEGX/NOT].bw (d16, An)
|
||||
case 0x006: // [CLR/NEG/NEGX/NOT].bw (d8, An, Xn)
|
||||
op( calc_action_for_mode(ea_mode) | MicroOp::DestinationMask,
|
||||
seq(pseq("np nrd", ea_mode), { ea(1) },
|
||||
!is_byte_access));
|
||||
op(Action::PerformOperation, seq("np nw", { ea(1) }, !is_byte_access));
|
||||
break;
|
||||
|
||||
case 0x105: // [CLR/NEG/NEGX/NOT].l (d16, An)
|
||||
case 0x106: // [CLR/NEG/NEGX/NOT].l (d8, An, Xn)
|
||||
op( calc_action_for_mode(ea_mode) | MicroOp::DestinationMask,
|
||||
seq(pseq("np nRd+ nrd", ea_mode), { ea(1), ea(1) }));
|
||||
op(Action::PerformOperation, seq("np nw- nW", { ea(1), ea(1) }));
|
||||
break;
|
||||
|
||||
case 0x010: // [CLR/NEG/NEGX/NOT].bw (xxx).w
|
||||
op( int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask,
|
||||
seq("np nrd", { ea(1) }, !is_byte_access));
|
||||
op(Action::PerformOperation,
|
||||
seq("np nw", { ea(1) }, !is_byte_access));
|
||||
break;
|
||||
|
||||
case 0x110: // [CLR/NEG/NEGX/NOT].l (xxx).w
|
||||
op( int(Action::AssembleWordAddressFromPrefetch) | MicroOp::DestinationMask,
|
||||
seq("np nRd+ nrd", { ea(1), ea(1) }));
|
||||
op(Action::PerformOperation,
|
||||
seq("np nw- nW", { ea(1), ea(1) }));
|
||||
break;
|
||||
|
||||
case 0x011: // [CLR/NEG/NEGX/NOT].bw (xxx).l
|
||||
op(Action::None, seq("np"));
|
||||
op( int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask,
|
||||
seq("np nrd", { ea(1) }, !is_byte_access));
|
||||
op(Action::PerformOperation,
|
||||
seq("np nw", { ea(1) }, !is_byte_access));
|
||||
break;
|
||||
|
||||
case 0x111: // [CLR/NEG/NEGX/NOT].l (xxx).l
|
||||
op(Action::None, seq("np"));
|
||||
op( int(Action::AssembleLongWordAddressFromPrefetch) | MicroOp::DestinationMask,
|
||||
seq("np nRd+ nrd", { ea(1), ea(1) }));
|
||||
op(Action::PerformOperation,
|
||||
seq("np nw- nW", { ea(1), ea(1) }));
|
||||
break;
|
||||
}
|
||||
} break;
|
||||
|
||||
case Decoder::CMP: {
|
||||
const auto source_register = (instruction >> 9) & 7;
|
||||
|
||||
|
@ -62,6 +62,11 @@ class ProcessorStorage {
|
||||
JMP,
|
||||
BRA, Bcc,
|
||||
DBcc,
|
||||
|
||||
CLRb, CLRw, CLRl,
|
||||
NEGXb, NEGXw, NEGXl,
|
||||
NEGb, NEGw, NEGl,
|
||||
NOTb, NOTw, NOTl,
|
||||
};
|
||||
|
||||
/*!
|
||||
|
Loading…
x
Reference in New Issue
Block a user