mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-23 20:29:42 +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. */
|
||||
if(!cycle.data_select_active()) return HalfCycles(0);
|
||||
|
||||
// TODO: byte accesses to the odd addresses shouldn't obey logic below.
|
||||
advance_time(HalfCycles(2));
|
||||
update_audio();
|
||||
|
||||
if(cycle.operation & Microcycle::Read) {
|
||||
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));
|
||||
} else {
|
||||
if(address == 0x7fc400) {
|
||||
ay_.set_control_lines(GI::AY38910::BC1);
|
||||
ay_.set_data_input(cycle.value->halves.low);
|
||||
ay_.set_control_lines(GI::AY38910::ControlLines(0));
|
||||
} else {
|
||||
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:
|
||||
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) {
|
||||
const uint8_t value = 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;
|
||||
}
|
||||
cycle.set_value8_low(mfp_->read(int(address)));
|
||||
} else {
|
||||
if(cycle.operation & Microcycle::SelectByte) {
|
||||
mfp_->write(int(address), cycle.value->halves.low);
|
||||
} else {
|
||||
mfp_->write(int(address), cycle.value->halves.high);
|
||||
}
|
||||
mfp_->write(int(address), cycle.value8_low());
|
||||
}
|
||||
break;
|
||||
|
||||
@ -483,19 +463,9 @@ class ConcreteMachine:
|
||||
if(!cycle.data_select_active()) return HalfCycles(0);
|
||||
|
||||
if(cycle.operation & Microcycle::Read) {
|
||||
const uint8_t value = 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;
|
||||
}
|
||||
cycle.set_value16(video_->read(int(address)));
|
||||
} else {
|
||||
if(cycle.operation & Microcycle::SelectByte) {
|
||||
video_->write(int(address), uint16_t(cycle.value->halves.low << cycle.byte_shift()));
|
||||
} else {
|
||||
video_->write(int(address), cycle.value->full);
|
||||
}
|
||||
video_->write(int(address), cycle.value16());
|
||||
}
|
||||
break;
|
||||
|
||||
@ -506,21 +476,10 @@ class ConcreteMachine:
|
||||
if(!cycle.data_select_active()) return HalfCycles(0);
|
||||
|
||||
const auto acia_ = (address < 0x7ffe02) ? &keyboard_acia_ : &midi_acia_;
|
||||
|
||||
if(cycle.operation & Microcycle::Read) {
|
||||
const uint8_t value = (*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;
|
||||
}
|
||||
cycle.set_value8_high((*acia_)->read(int(address)));
|
||||
} else {
|
||||
if(cycle.operation & Microcycle::SelectByte) {
|
||||
(*acia_)->write(int(address), cycle.value->halves.low);
|
||||
} else {
|
||||
(*acia_)->write(int(address), cycle.value->halves.high);
|
||||
}
|
||||
(*acia_)->write(int(address), cycle.value8_high());
|
||||
}
|
||||
} break;
|
||||
|
||||
@ -529,21 +488,9 @@ class ConcreteMachine:
|
||||
if(!cycle.data_select_active()) return HalfCycles(0);
|
||||
|
||||
if(cycle.operation & Microcycle::Read) {
|
||||
const auto value = dma_->read(int(address));
|
||||
if(cycle.operation & Microcycle::SelectWord) {
|
||||
cycle.value->full = value;
|
||||
} else {
|
||||
cycle.value->halves.low = uint8_t(value >> cycle.byte_shift());
|
||||
}
|
||||
cycle.set_value16(dma_->read(int(address)));
|
||||
} else {
|
||||
if(cycle.operation & Microcycle::SelectWord) {
|
||||
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())
|
||||
));
|
||||
}
|
||||
dma_->write(int(address), cycle.value16());
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -222,18 +222,18 @@ HalfCycles Video::get_next_sequence_point() {
|
||||
|
||||
// MARK: - IO dispatch
|
||||
|
||||
uint8_t Video::read(int address) {
|
||||
uint16_t Video::read(int address) {
|
||||
LOG("[Video] read " << PADHEX(2) << (address & 0x3f));
|
||||
address &= 0x3f;
|
||||
switch(address) {
|
||||
default:
|
||||
break;
|
||||
case 0x00: return uint8_t(base_address_ >> 16);
|
||||
case 0x01: return uint8_t(base_address_ >> 8);
|
||||
case 0x02: return uint8_t(current_address_ >> 16);
|
||||
case 0x03: return uint8_t(current_address_ >> 8);
|
||||
case 0x04: return uint8_t(current_address_);
|
||||
case 0x30: return video_mode_ | 0xfc;
|
||||
case 0x00: return uint16_t(0xff00 | (base_address_ >> 16));
|
||||
case 0x01: return uint16_t(0xff00 | (base_address_ >> 8));
|
||||
case 0x02: return uint16_t(0xff00 | (current_address_ >> 16));
|
||||
case 0x03: return uint16_t(0xff00 | (current_address_ >> 8));
|
||||
case 0x04: return uint16_t(0xff00 | (current_address_));
|
||||
case 0x30: return video_mode_ | 0xfcff;
|
||||
}
|
||||
return 0xff;
|
||||
}
|
||||
@ -245,11 +245,11 @@ void Video::write(int address, uint16_t value) {
|
||||
default: break;
|
||||
|
||||
// Start address.
|
||||
case 0x00: base_address_ = (base_address_ & 0x00ffff) | (value << 16); break;
|
||||
case 0x01: base_address_ = (base_address_ & 0xff00ff) | (value << 8); break;
|
||||
case 0x00: base_address_ = (base_address_ & 0x00ffff) | ((value & 0xff) << 16); break;
|
||||
case 0x01: base_address_ = (base_address_ & 0xff00ff) | ((value & 0xff) << 8); break;
|
||||
|
||||
// Mode.
|
||||
case 0x30: video_mode_ = uint8_t(value); break;
|
||||
case 0x30: video_mode_ = value; break;
|
||||
|
||||
// Palette.
|
||||
case 0x20: case 0x21: case 0x22: case 0x23:
|
||||
|
@ -41,7 +41,7 @@ class Video {
|
||||
|
||||
void set_ram(uint16_t *);
|
||||
|
||||
uint8_t read(int address);
|
||||
uint16_t read(int address);
|
||||
void write(int address, uint16_t value);
|
||||
|
||||
private:
|
||||
@ -58,7 +58,7 @@ class Video {
|
||||
int x = 0, y = 0;
|
||||
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;
|
||||
}
|
||||
|
||||
/*!
|
||||
@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
|
||||
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_;
|
||||
|
||||
#ifdef LOG_TRACE
|
||||
static bool should_log = true;
|
||||
static bool should_log = false;
|
||||
#endif
|
||||
|
||||
// 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;
|
||||
|
||||
case ExecutionState::BeginInterrupt:
|
||||
#ifdef LOG_TRACE
|
||||
should_log = true;
|
||||
#endif
|
||||
active_program_ = nullptr;
|
||||
active_micro_op_ = interrupt_micro_ops_;
|
||||
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.
|
||||
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;
|
||||
|
||||
case int_type(MicroOp::Action::CopyNextWord):
|
||||
|
Loading…
Reference in New Issue
Block a user