mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-25 03:32:01 +00:00
Attempts to regularise data bus access.
This commit is contained in:
parent
75e34b4215
commit
c070f2100c
@ -398,23 +398,21 @@ class ConcreteMachine:
|
|||||||
case 0x7fc401: /* PSG: write to write register. */
|
case 0x7fc401: /* PSG: write to write register. */
|
||||||
if(!cycle.data_select_active()) return HalfCycles(0);
|
if(!cycle.data_select_active()) return HalfCycles(0);
|
||||||
|
|
||||||
// TODO: byte accesses to the odd addresses shouldn't obey logic below.
|
|
||||||
advance_time(HalfCycles(2));
|
advance_time(HalfCycles(2));
|
||||||
update_audio();
|
update_audio();
|
||||||
|
|
||||||
if(cycle.operation & Microcycle::Read) {
|
if(cycle.operation & Microcycle::Read) {
|
||||||
ay_.set_control_lines(GI::AY38910::ControlLines(GI::AY38910::BC2 | GI::AY38910::BC1));
|
ay_.set_control_lines(GI::AY38910::ControlLines(GI::AY38910::BC2 | GI::AY38910::BC1));
|
||||||
cycle.value->halves.low = ay_.get_data_output();
|
cycle.set_value8_high(ay_.get_data_output());
|
||||||
ay_.set_control_lines(GI::AY38910::ControlLines(0));
|
ay_.set_control_lines(GI::AY38910::ControlLines(0));
|
||||||
} else {
|
} else {
|
||||||
if(address == 0x7fc400) {
|
if(address == 0x7fc400) {
|
||||||
ay_.set_control_lines(GI::AY38910::BC1);
|
ay_.set_control_lines(GI::AY38910::BC1);
|
||||||
ay_.set_data_input(cycle.value->halves.low);
|
|
||||||
ay_.set_control_lines(GI::AY38910::ControlLines(0));
|
|
||||||
} else {
|
} else {
|
||||||
ay_.set_control_lines(GI::AY38910::ControlLines(GI::AY38910::BC2 | GI::AY38910::BDIR));
|
ay_.set_control_lines(GI::AY38910::ControlLines(GI::AY38910::BC2 | GI::AY38910::BDIR));
|
||||||
ay_.set_data_input(cycle.value->halves.low);
|
|
||||||
ay_.set_control_lines(GI::AY38910::ControlLines(0));
|
|
||||||
}
|
}
|
||||||
|
ay_.set_data_input(cycle.value8_high());
|
||||||
|
ay_.set_control_lines(GI::AY38910::ControlLines(0));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -441,28 +439,10 @@ class ConcreteMachine:
|
|||||||
case 0x7ffd1c: case 0x7ffd1d: case 0x7ffd1e: case 0x7ffd1f:
|
case 0x7ffd1c: case 0x7ffd1d: case 0x7ffd1e: case 0x7ffd1f:
|
||||||
if(!cycle.data_select_active()) return HalfCycles(0);
|
if(!cycle.data_select_active()) return HalfCycles(0);
|
||||||
|
|
||||||
// The lower data lines aren't connected.
|
|
||||||
if(!cycle.upper_data_select()) {
|
|
||||||
if(cycle.operation & Microcycle::Read) {
|
|
||||||
cycle.value->halves.low = 0xff;
|
|
||||||
}
|
|
||||||
return HalfCycles(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(cycle.operation & Microcycle::Read) {
|
if(cycle.operation & Microcycle::Read) {
|
||||||
const uint8_t value = mfp_->read(int(address));
|
cycle.set_value8_low(mfp_->read(int(address)));
|
||||||
if(cycle.operation & Microcycle::SelectByte) {
|
|
||||||
cycle.value->halves.low = value;
|
|
||||||
} else {
|
|
||||||
cycle.value->halves.high = value;
|
|
||||||
cycle.value->halves.low = 0xff;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if(cycle.operation & Microcycle::SelectByte) {
|
mfp_->write(int(address), cycle.value8_low());
|
||||||
mfp_->write(int(address), cycle.value->halves.low);
|
|
||||||
} else {
|
|
||||||
mfp_->write(int(address), cycle.value->halves.high);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -483,19 +463,9 @@ class ConcreteMachine:
|
|||||||
if(!cycle.data_select_active()) return HalfCycles(0);
|
if(!cycle.data_select_active()) return HalfCycles(0);
|
||||||
|
|
||||||
if(cycle.operation & Microcycle::Read) {
|
if(cycle.operation & Microcycle::Read) {
|
||||||
const uint8_t value = video_->read(int(address));
|
cycle.set_value16(video_->read(int(address)));
|
||||||
if(cycle.operation & Microcycle::SelectByte) {
|
|
||||||
cycle.value->halves.low = value;
|
|
||||||
} else {
|
|
||||||
cycle.value->halves.high = value;
|
|
||||||
cycle.value->halves.low = 0xff;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if(cycle.operation & Microcycle::SelectByte) {
|
video_->write(int(address), cycle.value16());
|
||||||
video_->write(int(address), uint16_t(cycle.value->halves.low << cycle.byte_shift()));
|
|
||||||
} else {
|
|
||||||
video_->write(int(address), cycle.value->full);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -506,21 +476,10 @@ class ConcreteMachine:
|
|||||||
if(!cycle.data_select_active()) return HalfCycles(0);
|
if(!cycle.data_select_active()) return HalfCycles(0);
|
||||||
|
|
||||||
const auto acia_ = (address < 0x7ffe02) ? &keyboard_acia_ : &midi_acia_;
|
const auto acia_ = (address < 0x7ffe02) ? &keyboard_acia_ : &midi_acia_;
|
||||||
|
|
||||||
if(cycle.operation & Microcycle::Read) {
|
if(cycle.operation & Microcycle::Read) {
|
||||||
const uint8_t value = (*acia_)->read(int(address));
|
cycle.set_value8_high((*acia_)->read(int(address)));
|
||||||
if(cycle.operation & Microcycle::SelectByte) {
|
|
||||||
cycle.value->halves.low = value;
|
|
||||||
} else {
|
|
||||||
cycle.value->halves.high = value;
|
|
||||||
cycle.value->halves.low = 0xff;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if(cycle.operation & Microcycle::SelectByte) {
|
(*acia_)->write(int(address), cycle.value8_high());
|
||||||
(*acia_)->write(int(address), cycle.value->halves.low);
|
|
||||||
} else {
|
|
||||||
(*acia_)->write(int(address), cycle.value->halves.high);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
@ -529,21 +488,9 @@ class ConcreteMachine:
|
|||||||
if(!cycle.data_select_active()) return HalfCycles(0);
|
if(!cycle.data_select_active()) return HalfCycles(0);
|
||||||
|
|
||||||
if(cycle.operation & Microcycle::Read) {
|
if(cycle.operation & Microcycle::Read) {
|
||||||
const auto value = dma_->read(int(address));
|
cycle.set_value16(dma_->read(int(address)));
|
||||||
if(cycle.operation & Microcycle::SelectWord) {
|
|
||||||
cycle.value->full = value;
|
|
||||||
} else {
|
|
||||||
cycle.value->halves.low = uint8_t(value >> cycle.byte_shift());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if(cycle.operation & Microcycle::SelectWord) {
|
dma_->write(int(address), cycle.value16());
|
||||||
dma_->write(int(address), cycle.value->full);
|
|
||||||
} else {
|
|
||||||
dma_->write(int(address), uint16_t(
|
|
||||||
(cycle.value->halves.low << cycle.byte_shift()) |
|
|
||||||
(0xff00 >> cycle.byte_shift())
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -222,18 +222,18 @@ HalfCycles Video::get_next_sequence_point() {
|
|||||||
|
|
||||||
// MARK: - IO dispatch
|
// MARK: - IO dispatch
|
||||||
|
|
||||||
uint8_t Video::read(int address) {
|
uint16_t Video::read(int address) {
|
||||||
LOG("[Video] read " << PADHEX(2) << (address & 0x3f));
|
LOG("[Video] read " << PADHEX(2) << (address & 0x3f));
|
||||||
address &= 0x3f;
|
address &= 0x3f;
|
||||||
switch(address) {
|
switch(address) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case 0x00: return uint8_t(base_address_ >> 16);
|
case 0x00: return uint16_t(0xff00 | (base_address_ >> 16));
|
||||||
case 0x01: return uint8_t(base_address_ >> 8);
|
case 0x01: return uint16_t(0xff00 | (base_address_ >> 8));
|
||||||
case 0x02: return uint8_t(current_address_ >> 16);
|
case 0x02: return uint16_t(0xff00 | (current_address_ >> 16));
|
||||||
case 0x03: return uint8_t(current_address_ >> 8);
|
case 0x03: return uint16_t(0xff00 | (current_address_ >> 8));
|
||||||
case 0x04: return uint8_t(current_address_);
|
case 0x04: return uint16_t(0xff00 | (current_address_));
|
||||||
case 0x30: return video_mode_ | 0xfc;
|
case 0x30: return video_mode_ | 0xfcff;
|
||||||
}
|
}
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
@ -245,11 +245,11 @@ void Video::write(int address, uint16_t value) {
|
|||||||
default: break;
|
default: break;
|
||||||
|
|
||||||
// Start address.
|
// Start address.
|
||||||
case 0x00: base_address_ = (base_address_ & 0x00ffff) | (value << 16); break;
|
case 0x00: base_address_ = (base_address_ & 0x00ffff) | ((value & 0xff) << 16); break;
|
||||||
case 0x01: base_address_ = (base_address_ & 0xff00ff) | (value << 8); break;
|
case 0x01: base_address_ = (base_address_ & 0xff00ff) | ((value & 0xff) << 8); break;
|
||||||
|
|
||||||
// Mode.
|
// Mode.
|
||||||
case 0x30: video_mode_ = uint8_t(value); break;
|
case 0x30: video_mode_ = value; break;
|
||||||
|
|
||||||
// Palette.
|
// Palette.
|
||||||
case 0x20: case 0x21: case 0x22: case 0x23:
|
case 0x20: case 0x21: case 0x22: case 0x23:
|
||||||
|
@ -41,7 +41,7 @@ class Video {
|
|||||||
|
|
||||||
void set_ram(uint16_t *);
|
void set_ram(uint16_t *);
|
||||||
|
|
||||||
uint8_t read(int address);
|
uint16_t read(int address);
|
||||||
void write(int address, uint16_t value);
|
void write(int address, uint16_t value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -58,7 +58,7 @@ class Video {
|
|||||||
int x = 0, y = 0;
|
int x = 0, y = 0;
|
||||||
void output_border(int duration);
|
void output_border(int duration);
|
||||||
|
|
||||||
uint8_t video_mode_ = 0;
|
uint16_t video_mode_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -193,6 +193,75 @@ struct Microcycle {
|
|||||||
return (address ? (*address) & 0x00fffffe : 0) >> 1;
|
return (address ? (*address) & 0x00fffffe : 0) >> 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@returns the value on the data bus — all 16 bits, with any inactive lines
|
||||||
|
(as er the upper and lower data selects) being represented by 1s. Assumes
|
||||||
|
this is a write cycle.
|
||||||
|
*/
|
||||||
|
forceinline uint16_t value16() const {
|
||||||
|
if(operation & SelectWord) return value->full;
|
||||||
|
const auto shift = byte_shift();
|
||||||
|
return uint16_t((value->halves.low << shift) | (0xff00 >> shift));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@returns the value currently on the high 8 lines of the data bus if any;
|
||||||
|
@c 0xff otherwise. Assumes this is a write cycle.
|
||||||
|
*/
|
||||||
|
forceinline uint8_t value8_high() const {
|
||||||
|
if(operation & SelectWord) {
|
||||||
|
return uint8_t(value->full >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint8_t(value->halves.low | (0xff00 >> ((*address & 1) << 3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
@returns the value currently on the low 8 lines of the data bus if any;
|
||||||
|
@c 0xff otherwise. Assumes this is a write cycle.
|
||||||
|
*/
|
||||||
|
forceinline uint8_t value8_low() const {
|
||||||
|
if(operation & SelectWord) {
|
||||||
|
return uint8_t(value->full);
|
||||||
|
}
|
||||||
|
|
||||||
|
return uint8_t(value->halves.low | (0x00ff << ((*address & 1) << 3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Sets to @c value the 8- or 16-bit portion of the supplied value that is
|
||||||
|
currently being read. Assumes this is a read cycle.
|
||||||
|
*/
|
||||||
|
forceinline void set_value16(uint16_t v) const {
|
||||||
|
if(operation & Microcycle::SelectWord) {
|
||||||
|
value->full = v;
|
||||||
|
} else {
|
||||||
|
value->halves.low = uint8_t(v >> byte_shift());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Equivalent to set_value16((v << 8) | 0x00ff).
|
||||||
|
*/
|
||||||
|
forceinline void set_value8_high(uint8_t v) const {
|
||||||
|
if(operation & Microcycle::SelectWord) {
|
||||||
|
value->full = uint16_t(0x00ff | (v << 8));
|
||||||
|
} else {
|
||||||
|
value->halves.low = uint8_t(v | (0xff00 >> ((*address & 1) << 3)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Equivalent to set_value16((v) | 0xff00).
|
||||||
|
*/
|
||||||
|
forceinline void set_value8_low(uint8_t v) const {
|
||||||
|
if(operation & Microcycle::SelectWord) {
|
||||||
|
value->full = 0xff00 | v;
|
||||||
|
} else {
|
||||||
|
value->halves.low = uint8_t(v | (0x00ff << ((*address & 1) << 3)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@returns the same value as word_address() for any Microcycle with the NewAddress or
|
@returns the same value as word_address() for any Microcycle with the NewAddress or
|
||||||
SameAddress flags set; undefined behaviour otherwise.
|
SameAddress flags set; undefined behaviour otherwise.
|
||||||
|
@ -70,7 +70,7 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
const HalfCycles remaining_duration = duration + half_cycles_left_to_run_;
|
const HalfCycles remaining_duration = duration + half_cycles_left_to_run_;
|
||||||
|
|
||||||
#ifdef LOG_TRACE
|
#ifdef LOG_TRACE
|
||||||
static bool should_log = true;
|
static bool should_log = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This loop counts upwards rather than downwards because it simplifies calculation of
|
// This loop counts upwards rather than downwards because it simplifies calculation of
|
||||||
@ -241,6 +241,9 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
case ExecutionState::BeginInterrupt:
|
case ExecutionState::BeginInterrupt:
|
||||||
|
#ifdef LOG_TRACE
|
||||||
|
should_log = true;
|
||||||
|
#endif
|
||||||
active_program_ = nullptr;
|
active_program_ = nullptr;
|
||||||
active_micro_op_ = interrupt_micro_ops_;
|
active_micro_op_ = interrupt_micro_ops_;
|
||||||
execution_state_ = ExecutionState::Executing;
|
execution_state_ = ExecutionState::Executing;
|
||||||
@ -1997,6 +2000,8 @@ template <class T, bool dtack_is_implicit, bool signal_will_perform> void Proces
|
|||||||
|
|
||||||
// Otherwise, the vector is whatever we were just told it is.
|
// Otherwise, the vector is whatever we were just told it is.
|
||||||
effective_address_[0].full = uint32_t(source_bus_data_[0].halves.low.halves.low << 2);
|
effective_address_[0].full = uint32_t(source_bus_data_[0].halves.low.halves.low << 2);
|
||||||
|
|
||||||
|
printf("Interrupt vector: %06x\n", effective_address_[0].full);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case int_type(MicroOp::Action::CopyNextWord):
|
case int_type(MicroOp::Action::CopyNextWord):
|
||||||
|
Loading…
Reference in New Issue
Block a user