1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-26 23:52:26 +00:00

Implements MOVEM to M with an implicit type conversion.

This commit is contained in:
Thomas Harte 2019-04-14 20:53:27 -04:00
parent 1003e70b5e
commit 325af677d3

View File

@ -354,34 +354,75 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
MOVEM: multi-word moves. MOVEM: multi-word moves.
*/ */
#define setup_movem(words_per_reg) \ #define setup_movem(words_per_reg, base) \
/* Count the number of long words to move. */ \ /* Count the number of long words to move. */ \
size_t total_to_move = 0; \ size_t total_to_move = 0; \
auto mask = next_word_; \ auto mask = next_word_; \
while(mask) { \ while(mask) { \
total_to_move += mask&1; \ total_to_move += mask&1; \
mask >>= 1; \ mask >>= 1; \
} \ } \
\ \
/* Twice that many words plus one will need to be moved */ \ /* Twice that many words plus one will need to be moved */ \
bus_program = movem_reads_steps_ + (64 - total_to_move*words_per_reg)*2; \ bus_program = base + (64 - total_to_move*words_per_reg)*2; \
\ \
/* Fill in the proper addresses and targets. */ \ /* Fill in the proper addresses and targets. */ \
const auto mode = (decoded_instruction_ >> 3) & 7; \ const auto mode = (decoded_instruction_ >> 3) & 7; \
uint32_t start_address; \ uint32_t start_address; \
if(mode <= 4) { \ if(mode <= 4) { \
start_address = active_program_->source_address->full; \ start_address = active_program_->destination_address->full; \
} else { \ } else { \
start_address = effective_address_[1].full; \ start_address = effective_address_[1].full; \
} \ } \
\ \
auto step = bus_program; \ auto step = bus_program; \
uint32_t *address_storage = movem_addresses_; \ uint32_t *address_storage = movem_addresses_; \
mask = next_word_; \ mask = next_word_; \
int offset = 0; int offset = 0;
#define write_address_sequence_long(address_step, offset_step, l, h) \
while(mask) { \
if(mask&1) { \
address_storage[0] = start_address; \
address_storage[1] = start_address + address_step; \
\
step[0].microcycle.address = step[1].microcycle.address = address_storage; \
step[2].microcycle.address = step[3].microcycle.address = address_storage + 1; \
\
const auto target = (offset > 7) ? &address_[offset&7] : &data_[offset]; \
step[h].microcycle.value = step[h+1].microcycle.value = &target->halves.high; \
step[l].microcycle.value = step[l+1].microcycle.value = &target->halves.low; \
\
start_address += address_step*2; \
address_storage += 2; \
step += 4; \
} \
mask >>= 1; \
offset += offset_step; \
}
#define write_address_sequence_word(address_step, offset_step) \
while(mask) { \
if(mask&1) { \
address_storage[0] = start_address; \
\
step[0].microcycle.address = step[1].microcycle.address = address_storage; \
\
const auto target = (offset > 7) ? &address_[offset&7] : &data_[offset]; \
step[0].microcycle.value = step[1].microcycle.value = &target->halves.low; \
\
start_address += address_step; \
++ address_storage; \
step += 2; \
} \
mask >>= 1; \
offset += offset_step; \
}
case Operation::MOVEMtoRl: { case Operation::MOVEMtoRl: {
setup_movem(2); setup_movem(2, movem_reads_steps_);
// Everything for move to registers is based on an incrementing // Everything for move to registers is based on an incrementing
// address; per M68000PRM: // address; per M68000PRM:
@ -389,26 +430,11 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
// "[If using the postincrement addressing mode then] the incremented address // "[If using the postincrement addressing mode then] the incremented address
// register contains the address of the last operand loaded plus the operand length. // register contains the address of the last operand loaded plus the operand length.
// If the addressing register is also loaded from memory, the memory value is ignored // If the addressing register is also loaded from memory, the memory value is ignored
// and the register is written with the postincre- mented effective address." // and the register is written with the postincremented effective address."
while(mask) { //
if(mask&1) { // The latter part is dealt with by MicroOp::Action::MOVEMtoRComplete, which also
address_storage[0] = start_address; // does any necessary sign extension.
address_storage[1] = start_address + 2; write_address_sequence_long(2, 1, 0, 2);
step[0].microcycle.address = step[1].microcycle.address = address_storage;
step[2].microcycle.address = step[3].microcycle.address = address_storage + 1;
const auto target = (offset > 7) ? &address_[offset&7] : &data_[offset];
step[0].microcycle.value = step[1].microcycle.value = &target->halves.high;
step[2].microcycle.value = step[3].microcycle.value = &target->halves.low;
start_address += 4;
address_storage += 2;
step += 4;
}
mask >>= 1;
++offset;
}
// MOVEM to R always reads one word too many. // MOVEM to R always reads one word too many.
address_storage[0] = start_address; address_storage[0] = start_address;
@ -418,24 +444,8 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
} break; } break;
case Operation::MOVEMtoRw: { case Operation::MOVEMtoRw: {
setup_movem(1); setup_movem(1, movem_reads_steps_);
write_address_sequence_word(2, 1);
while(mask) {
if(mask&1) {
address_storage[0] = start_address;
step[0].microcycle.address = step[1].microcycle.address = address_storage;
const auto target = (offset > 7) ? &address_[offset&7] : &data_[offset];
step[0].microcycle.value = step[1].microcycle.value = &target->halves.low;
start_address += 2;
++ address_storage;
step += 2;
}
mask >>= 1;
++offset;
}
// MOVEM to R always reads one word too many. // MOVEM to R always reads one word too many.
address_storage[0] = start_address; address_storage[0] = start_address;
@ -445,14 +455,43 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
} break; } break;
case Operation::MOVEMtoMl: { case Operation::MOVEMtoMl: {
setup_movem(2); setup_movem(2, movem_writes_steps_);
// MOVEM to M counts downwards and enumerates the registers in reverse order
// if subject to the predecrementing mode; otherwise it counts upwards and
// operates exactly as does MOVEM to R.
//
// Note also: "The MC68000 and MC68010 write the initial register value
// (not decremented) [when writing a register that is providing
// pre-decrementing addressing]."
//
// Hence the decrementing register (if any) is updated
// by MicroOp::Action::MOVEMtoMComplete.
if(mode == 4) {
offset = 15;
start_address -= 2;
write_address_sequence_long(-2, -1, 2, 0);
movem_final_address_ = start_address;
} else {
write_address_sequence_long(2, 1, 0, 2);
}
} break; } break;
case Operation::MOVEMtoMw: { case Operation::MOVEMtoMw: {
setup_movem(1); setup_movem(1, movem_writes_steps_);
if(mode == 4) {
offset = 15;
start_address -= 2;
write_address_sequence_word(-2, -1);
} else {
write_address_sequence_word(2, 1);
}
} break; } break;
#undef setup_movem #undef setup_movem
#undef write_address_sequence_long
#undef write_address_sequence_word
/* /*
NEGs: negatives the destination, setting the zero, NEGs: negatives the destination, setting the zero,
@ -753,6 +792,14 @@ template <class T, bool dtack_is_implicit> void Processor<T, dtack_is_implicit>:
} }
} break; } break;
case int(MicroOp::Action::MOVEMtoMComplete): {
const auto mode = (decoded_instruction_ >> 3) & 7;
if(mode == 4) {
const auto reg = decoded_instruction_ & 7;
address_[reg] = movem_final_address_;
}
} break;
case int(MicroOp::Action::CopyNextWord): case int(MicroOp::Action::CopyNextWord):
next_word_ = prefetch_queue_.halves.low.full; next_word_ = prefetch_queue_.halves.low.full;
break; break;