1
0
mirror of https://github.com/TomHarte/CLK.git synced 2026-04-19 02:22:39 +00:00

Improve consts, indentation.

This commit is contained in:
Thomas Harte
2025-04-22 22:42:13 -04:00
parent b1582d33c0
commit e78c1bbec9
10 changed files with 257 additions and 258 deletions
+7 -7
View File
@@ -15,7 +15,7 @@ using namespace Enterprise::Dave;
Audio::Audio(Concurrency::AsyncTaskQueue<false> &audio_queue) :
audio_queue_(audio_queue) {}
void Audio::write(uint16_t address, uint8_t value) {
void Audio::write(uint16_t address, const uint8_t value) {
address &= 0x1f;
audio_queue_.enqueue([address, value, this] {
switch(address) {
@@ -62,13 +62,13 @@ void Audio::write(uint16_t address, uint8_t value) {
});
}
void Audio::set_sample_volume_range(int16_t range) {
void Audio::set_sample_volume_range(const int16_t range) {
audio_queue_.enqueue([range, this] {
volume_ = range / (63*4);
});
}
void Audio::update_channel(int c) {
void Audio::update_channel(const int c) {
auto output = channels_[c].output & 1;
channels_[c].output <<= 1;
if(channels_[c].sync) {
@@ -100,7 +100,7 @@ void Audio::update_channel(int c) {
}
template <Outputs::Speaker::Action action>
void Audio::apply_samples(std::size_t number_of_samples, Outputs::Speaker::StereoSample *target) {
void Audio::apply_samples(const std::size_t number_of_samples, Outputs::Speaker::StereoSample *const target) {
Outputs::Speaker::StereoSample output_level;
size_t c = 0;
@@ -216,7 +216,7 @@ uint8_t TimedInterruptSource::get_new_interrupts() {
return result;
}
void TimedInterruptSource::write(uint16_t address, uint8_t value) {
void TimedInterruptSource::write(uint16_t address, const uint8_t value) {
address &= 0x1f;
switch(address) {
default: break;
@@ -240,7 +240,7 @@ void TimedInterruptSource::write(uint16_t address, uint8_t value) {
}
}
void TimedInterruptSource::update_channel(int c, bool is_linked, int decrement) {
void TimedInterruptSource::update_channel(const int c, const bool is_linked, const int decrement) {
if(channels_[c].sync) {
channels_[c].value = channels_[c].reload;
} else {
@@ -273,7 +273,7 @@ void TimedInterruptSource::update_channel(int c, bool is_linked, int decrement)
}
}
void TimedInterruptSource::run_for(Cycles duration) {
void TimedInterruptSource::run_for(const Cycles duration) {
// Determine total number of ticks.
run_length_ += duration;
const Cycles cycles = run_length_.divide(global_divider_);
+120 -120
View File
@@ -27,93 +27,93 @@ enum class Interrupt: uint8_t {
Models the audio-production subset of Dave's behaviour.
*/
class Audio: public Outputs::Speaker::BufferSource<Audio, true> {
public:
Audio(Concurrency::AsyncTaskQueue<false> &audio_queue);
public:
Audio(Concurrency::AsyncTaskQueue<false> &audio_queue);
/// Modifies an register in the audio range; only the low 4 bits are
/// used for register decoding so it's assumed that the caller has
/// already identified this write as being to an audio register.
void write(uint16_t address, uint8_t value);
/// Modifies an register in the audio range; only the low 4 bits are
/// used for register decoding so it's assumed that the caller has
/// already identified this write as being to an audio register.
void write(uint16_t address, uint8_t value);
// MARK: - SampleSource.
void set_sample_volume_range(int16_t range);
template <Outputs::Speaker::Action action>
void apply_samples(std::size_t number_of_samples, Outputs::Speaker::StereoSample *target);
// MARK: - SampleSource.
void set_sample_volume_range(int16_t range);
template <Outputs::Speaker::Action action>
void apply_samples(std::size_t number_of_samples, Outputs::Speaker::StereoSample *target);
private:
Concurrency::AsyncTaskQueue<false> &audio_queue_;
private:
Concurrency::AsyncTaskQueue<false> &audio_queue_;
// Global divider (i.e. 8MHz/12Mhz switch).
uint8_t global_divider_;
uint8_t global_divider_reload_ = 2;
// Global divider (i.e. 8MHz/12Mhz switch).
uint8_t global_divider_;
uint8_t global_divider_reload_ = 2;
// Tone channels.
struct Channel {
// User-set values.
uint16_t reload = 0;
bool high_pass = false;
bool ring_modulate = false;
enum class Distortion {
None = 0,
FourBit = 1,
FiveBit = 2,
SevenBit = 3,
} distortion = Distortion::None;
uint8_t amplitude[2]{};
bool sync = false;
// Tone channels.
struct Channel {
// User-set values.
uint16_t reload = 0;
bool high_pass = false;
bool ring_modulate = false;
enum class Distortion {
None = 0,
FourBit = 1,
FiveBit = 2,
SevenBit = 3,
} distortion = Distortion::None;
uint8_t amplitude[2]{};
bool sync = false;
// Current state.
uint16_t count = 0;
int output = 0;
} channels_[3];
void update_channel(int);
// Current state.
uint16_t count = 0;
int output = 0;
} channels_[3];
void update_channel(int);
// Noise channel.
struct Noise {
// User-set values.
uint8_t amplitude[2]{};
enum class Frequency {
DivideByFour,
ToneChannel0,
ToneChannel1,
ToneChannel2,
} frequency = Frequency::DivideByFour;
enum class Polynomial {
SeventeenBit,
FifteenBit,
ElevenBit,
NineBit
} polynomial = Polynomial::SeventeenBit;
bool swap_polynomial = false;
bool low_pass = false;
bool high_pass = false;
bool ring_modulate = false;
// Noise channel.
struct Noise {
// User-set values.
uint8_t amplitude[2]{};
enum class Frequency {
DivideByFour,
ToneChannel0,
ToneChannel1,
ToneChannel2,
} frequency = Frequency::DivideByFour;
enum class Polynomial {
SeventeenBit,
FifteenBit,
ElevenBit,
NineBit
} polynomial = Polynomial::SeventeenBit;
bool swap_polynomial = false;
bool low_pass = false;
bool high_pass = false;
bool ring_modulate = false;
// Current state.
int count = 0;
int output = 0;
bool final_output = false;
} noise_;
void update_noise();
// Current state.
int count = 0;
int output = 0;
bool final_output = false;
} noise_;
void update_noise();
bool use_direct_output_[2]{};
bool use_direct_output_[2]{};
// Global volume, per SampleSource obligations.
int16_t volume_ = 0;
// Global volume, per SampleSource obligations.
int16_t volume_ = 0;
// Polynomials that are always running.
Numeric::LFSRv<0xc> poly4_;
Numeric::LFSRv<0x14> poly5_;
Numeric::LFSRv<0x60> poly7_;
// Polynomials that are always running.
Numeric::LFSRv<0xc> poly4_;
Numeric::LFSRv<0x14> poly5_;
Numeric::LFSRv<0x60> poly7_;
// The selectable, noise-related polynomial.
Numeric::LFSRv<0x110> poly9_;
Numeric::LFSRv<0x500> poly11_;
Numeric::LFSRv<0x6000> poly15_;
Numeric::LFSRv<0x12000> poly17_;
// The selectable, noise-related polynomial.
Numeric::LFSRv<0x110> poly9_;
Numeric::LFSRv<0x500> poly11_;
Numeric::LFSRv<0x6000> poly15_;
Numeric::LFSRv<0x12000> poly17_;
// Current state of the active polynomials.
uint8_t poly_state_[4];
// Current state of the active polynomials.
uint8_t poly_state_[4];
};
/*!
@@ -122,62 +122,62 @@ class Audio: public Outputs::Speaker::BufferSource<Audio, true> {
1 Hz interrupt.
*/
class TimedInterruptSource {
public:
/// Modifies an register in the audio range; only the low 4 bits are
/// used for register decoding so it's assumed that the caller has
/// already identified this write as being to an audio register.
void write(uint16_t address, uint8_t value);
public:
/// Modifies an register in the audio range; only the low 4 bits are
/// used for register decoding so it's assumed that the caller has
/// already identified this write as being to an audio register.
void write(uint16_t address, uint8_t value);
/// Returns a bitmask of interrupts that have become active since
/// the last time this method was called; flags are as defined in
/// @c Enterprise::Dave::Interrupt
uint8_t get_new_interrupts();
/// Returns a bitmask of interrupts that have become active since
/// the last time this method was called; flags are as defined in
/// @c Enterprise::Dave::Interrupt
uint8_t get_new_interrupts();
/// Returns the current high or low states of the inputs that trigger
/// the interrupts modelled here, as a bit mask compatible with that
/// exposed by Dave as the register at 0xb4.
uint8_t get_divider_state();
/// Returns the current high or low states of the inputs that trigger
/// the interrupts modelled here, as a bit mask compatible with that
/// exposed by Dave as the register at 0xb4.
uint8_t get_divider_state();
/// Advances the interrupt source.
void run_for(Cycles);
/// Advances the interrupt source.
void run_for(Cycles);
/// @returns The amount of time from now until the earliest that
/// @c get_new_interrupts() _might_ have new interrupts to report.
Cycles next_sequence_point() const;
/// @returns The amount of time from now until the earliest that
/// @c get_new_interrupts() _might_ have new interrupts to report.
Cycles next_sequence_point() const;
private:
static constexpr Cycles clock_rate{250000};
static constexpr Cycles half_clock_rate{125000};
private:
static constexpr Cycles clock_rate{250000};
static constexpr Cycles half_clock_rate{125000};
// Global divider (i.e. 8MHz/12Mhz switch).
Cycles global_divider_ = Cycles(2);
Cycles run_length_;
// Global divider (i.e. 8MHz/12Mhz switch).
Cycles global_divider_ = Cycles(2);
Cycles run_length_;
// Interrupts that have fired since get_new_interrupts()
// was last called.
uint8_t interrupts_ = 0;
// Interrupts that have fired since get_new_interrupts()
// was last called.
uint8_t interrupts_ = 0;
// A counter for the 1Hz interrupt.
int two_second_counter_ = 0;
// A counter for the 1Hz interrupt.
int two_second_counter_ = 0;
// A counter specific to the 1kHz and 50Hz timers, if in use.
enum class InterruptRate {
OnekHz,
FiftyHz,
ToneGenerator0,
ToneGenerator1,
} rate_ = InterruptRate::OnekHz;
bool programmable_level_ = false;
// A counter specific to the 1kHz and 50Hz timers, if in use.
enum class InterruptRate {
OnekHz,
FiftyHz,
ToneGenerator0,
ToneGenerator1,
} rate_ = InterruptRate::OnekHz;
bool programmable_level_ = false;
// A local duplicate of the counting state of the first two audio
// channels, maintained in case either of those is used as an
// interrupt source.
struct Channel {
int value = 100, reload = 100;
bool sync = false;
bool level = false;
} channels_[2];
void update_channel(int c, bool is_linked, int decrement);
// A local duplicate of the counting state of the first two audio
// channels, maintained in case either of those is used as an
// interrupt source.
struct Channel {
int value = 100, reload = 100;
bool sync = false;
bool level = false;
} channels_[2];
void update_channel(int c, bool is_linked, int decrement);
};
}
+4 -4
View File
@@ -17,7 +17,7 @@ EXDos::EXDos() : WD1770(P1770) {
set_control_register(0x00);
}
void EXDos::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, size_t drive) {
void EXDos::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, const size_t drive) {
get_drive(drive).set_disk(disk);
disk_did_change_ = true;
}
@@ -38,7 +38,7 @@ void EXDos::set_disk(std::shared_ptr<Storage::Disk::Disk> disk, size_t drive) {
// b1 interrupt request from WD1770
// b0 drive ready
void EXDos::set_control_register(uint8_t control) {
void EXDos::set_control_register(const uint8_t control) {
if(control & 0x40) disk_did_change_ = false;
set_is_double_density(!(control & 0x20));
@@ -67,11 +67,11 @@ uint8_t EXDos::get_control_register() {
return status;
}
void EXDos::set_motor_on(bool on) {
void EXDos::set_motor_on(const bool on) {
get_drive().set_motor_on(on);
}
void EXDos::set_activity_observer(Activity::Observer *observer) {
void EXDos::set_activity_observer(Activity::Observer *const observer) {
for_all_drives([observer] (Storage::Disk::Drive &drive, size_t index) {
drive.set_activity_observer(observer, "Drive " + std::to_string(index+1), true);
});
+9 -10
View File
@@ -14,20 +14,19 @@
namespace Enterprise {
class EXDos final : public WD::WD1770 {
public:
EXDos();
public:
EXDos();
void set_disk(std::shared_ptr<Storage::Disk::Disk> disk, size_t drive);
void set_disk(std::shared_ptr<Storage::Disk::Disk>, const size_t drive);
void set_control_register(uint8_t control);
uint8_t get_control_register();
void set_control_register(uint8_t);
uint8_t get_control_register();
void set_activity_observer(Activity::Observer *observer);
void set_activity_observer(Activity::Observer *);
private:
bool disk_did_change_ = false;
void set_motor_on(bool on) override;
private:
bool disk_did_change_ = false;
void set_motor_on(bool) override;
};
}
+10 -10
View File
@@ -261,7 +261,7 @@ public:
}
// MARK: - Z80::BusHandler.
forceinline void advance_nick(HalfCycles duration) {
forceinline void advance_nick(const HalfCycles duration) {
if(nick_ += duration) {
const auto nick = nick_.last_valid();
const bool nick_interrupt_line = nick->get_interrupt_line();
@@ -558,7 +558,7 @@ public:
return penalty;
}
void flush_output(int outputs) final {
void flush_output(const int outputs) final {
if(outputs & Output::Video) {
nick_.flush();
}
@@ -613,7 +613,7 @@ if(offset >= location && offset < location + source.size() / 0x4000) { \
page<slot>(nullptr, nullptr);
}
template <size_t slot> void page(const uint8_t *read, uint8_t *write) {
template <size_t slot> void page(const uint8_t *const read, uint8_t *const write) {
read_pointers_[slot] = read ? read - (slot * 0x4000) : nullptr;
write_pointers_[slot] = write ? write - (slot * 0x4000) : nullptr;
}
@@ -629,7 +629,7 @@ if(offset >= location && offset < location + source.size() / 0x4000) { \
bool is_video_[4]{};
// MARK: - ScanProducer
void set_scan_target(Outputs::Display::ScanTarget *scan_target) override {
void set_scan_target(Outputs::Display::ScanTarget *const scan_target) override {
nick_.last_valid()->set_scan_target(scan_target);
}
@@ -637,7 +637,7 @@ if(offset >= location && offset < location + source.size() / 0x4000) { \
return nick_.last_valid()->get_scaled_scan_status();
}
void set_display_type(Outputs::Display::DisplayType display_type) final {
void set_display_type(const Outputs::Display::DisplayType display_type) final {
nick_.last_valid()->set_display_type(display_type);
}
@@ -664,7 +664,7 @@ if(offset >= location && offset < location + source.size() / 0x4000) { \
uint8_t active_key_line_ = 0;
std::array<uint8_t, 10> key_lines_;
void set_key_state(uint16_t key, bool is_pressed) final {
void set_key_state(const uint16_t key, const bool is_pressed) final {
if(is_pressed) {
key_lines_[key >> 8] &= ~uint8_t(key);
} else {
@@ -689,7 +689,7 @@ if(offset >= location && offset < location + source.size() / 0x4000) { \
}
}
bool can_type(char c) const final {
bool can_type(const char c) const final {
return Utility::TypeRecipient<CharacterMapper>::can_type(c);
}
@@ -710,11 +710,11 @@ if(offset >= location && offset < location + source.size() / 0x4000) { \
// MARK: - Interrupts
uint8_t interrupt_mask_ = 0x00, interrupt_state_ = 0x00;
void set_interrupts(uint8_t mask, HalfCycles offset = HalfCycles(0)) {
void set_interrupts(const uint8_t mask, const HalfCycles offset = HalfCycles(0)) {
interrupt_state_ |= uint8_t(mask);
update_interrupts(offset);
}
void update_interrupts(HalfCycles offset = HalfCycles(0)) {
void update_interrupts(const HalfCycles offset = HalfCycles(0)) {
z80_.set_interrupt_line((interrupt_state_ >> 1) & interrupt_mask_, offset);
}
@@ -743,7 +743,7 @@ if(offset >= location && offset < location + source.size() / 0x4000) { \
EXDos exdos_;
// MARK: - Activity Source
void set_activity_observer([[maybe_unused]] Activity::Observer *observer) final {
void set_activity_observer([[maybe_unused]] Activity::Observer *const observer) final {
if constexpr (has_disk_controller) {
exdos_.set_activity_observer(observer);
}
+6 -2
View File
@@ -32,7 +32,9 @@ struct Machine {
friend Configurable::DisplayOption<Options>;
public:
Options(Configurable::OptionsType type) :
Configurable::DisplayOption<Options>(type == Configurable::OptionsType::UserFriendly ? Configurable::Display::RGB : Configurable::Display::CompositeColour) {}
Configurable::DisplayOption<Options>(
type == Configurable::OptionsType::UserFriendly ?
Configurable::Display::RGB : Configurable::Display::CompositeColour) {}
private:
Options() : Options(Configurable::OptionsType::UserFriendly) {}
@@ -40,7 +42,9 @@ struct Machine {
friend Reflection::StructImpl<Options>;
void declare_fields() {
declare_display_option();
limit_enum(&output, Configurable::Display::RGB, Configurable::Display::CompositeColour, Configurable::Display::CompositeMonochrome, -1);
limit_enum(&output,
Configurable::Display::RGB, Configurable::Display::CompositeColour,
Configurable::Display::CompositeMonochrome, -1);
}
};
};
+2 -2
View File
@@ -10,7 +10,7 @@
using namespace Enterprise;
uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) const {
uint16_t KeyboardMapper::mapped_key_for_key(const Inputs::Keyboard::Key key) const {
#define BIND(source, dest) case Inputs::Keyboard::Key::source: return uint16_t(Key::dest)
switch(key) {
default: break;
@@ -73,7 +73,7 @@ uint16_t KeyboardMapper::mapped_key_for_key(Inputs::Keyboard::Key key) const {
return MachineTypes::MappedKeyboardMachine::KeyNotMapped;
}
const uint16_t *CharacterMapper::sequence_for_character(char character) const {
const uint16_t *CharacterMapper::sequence_for_character(const char character) const {
#define KEYS(x) {uint16_t(x), MachineTypes::MappedKeyboardMachine::KeyEndSequence}
#define SHIFT(x) {uint16_t(Key::LeftShift), uint16_t(x), MachineTypes::MappedKeyboardMachine::KeyEndSequence}
#define _ {MachineTypes::MappedKeyboardMachine::KeyNotMapped}
+2 -6
View File
@@ -13,8 +13,6 @@
namespace Enterprise {
#define KeyCode(line, mask) (line << 8) | mask
enum class Key: uint16_t {
N = 0x0000 | 0x01, Backslash = 0x0000 | 0x02, B = 0x0000 | 0x04, C = 0x0000 | 0x08,
V = 0x0000 | 0x10, X = 0x0000 | 0x20, Z = 0x0000 | 0x40, LeftShift = 0x0000 | 0x80,
@@ -50,14 +48,12 @@ enum class Key: uint16_t {
OpenSquareBracket = 0x0900 | 0x20
};
#undef KeyCode
struct KeyboardMapper: public MachineTypes::MappedKeyboardMachine::KeyboardMapper {
uint16_t mapped_key_for_key(Inputs::Keyboard::Key key) const final;
uint16_t mapped_key_for_key(Inputs::Keyboard::Key) const final;
};
struct CharacterMapper: public ::Utility::CharacterMapper {
const uint16_t *sequence_for_character(char character) const override;
const uint16_t *sequence_for_character(char) const override;
};
}
+12 -12
View File
@@ -12,7 +12,7 @@
namespace {
uint16_t mapped_colour(uint8_t source) {
uint16_t mapped_colour(const uint8_t source) {
// On the Enterprise, red and green are 3-bit quantities; blue is a 2-bit quantity.
int red = ((source&0x01) << 2) | ((source&0x08) >> 2) | ((source&0x40) >> 6);
int green = ((source&0x02) << 1) | ((source&0x10) >> 3) | ((source&0x80) >> 7);
@@ -46,7 +46,7 @@ uint16_t mapped_colour(uint8_t source) {
using namespace Enterprise;
Nick::Nick(const uint8_t *ram) :
Nick::Nick(const uint8_t *const ram) :
crt_(57*16, 16, Outputs::Display::Type::PAL50, Outputs::Display::InputDataType::Red4Green4Blue4),
ram_(ram) {
@@ -57,7 +57,7 @@ Nick::Nick(const uint8_t *ram) :
crt_.set_visible_area(Outputs::Display::Rect(0.05f, 0.05f, 0.9f, 0.9f));
}
void Nick::write(uint16_t address, uint8_t value) {
void Nick::write(const uint16_t address, const uint8_t value) {
switch(address & 3) {
case 0:
// Ignored: everything to do with external colour.
@@ -95,7 +95,7 @@ uint8_t Nick::read() {
return last_read_;
}
Cycles Nick::get_time_until_z80_slot(Cycles after_period) const {
Cycles Nick::get_time_until_z80_slot(const Cycles after_period) const {
// Place Z80 accesses in the first six cycles in each sixteen-cycle window.
// That models video accesses as being the final ten. Which has the net effect
// of responding to the line parameter table interrupt flag as soon as it's
@@ -111,8 +111,8 @@ Cycles Nick::get_time_until_z80_slot(Cycles after_period) const {
}
}
void Nick::run_for(Cycles duration) {
constexpr int line_length = 912;
void Nick::run_for(const Cycles duration) {
static constexpr int line_length = 912;
#define add_window(x) \
line_data_pointer_[0] += is_sync_or_pixels_ * line_data_per_column_increments_[0] * (x); \
@@ -437,7 +437,7 @@ void Nick::run_for(Cycles duration) {
}
void Nick::set_output_type(OutputType type, bool force_flush) {
void Nick::set_output_type(const OutputType type, const bool force_flush) {
if(type == output_type_ && !force_flush) {
return;
}
@@ -480,7 +480,7 @@ Cycles Nick::next_sequence_point() const {
// MARK: - CRT passthroughs.
void Nick::set_scan_target(Outputs::Display::ScanTarget *scan_target) {
void Nick::set_scan_target(Outputs::Display::ScanTarget *const scan_target) {
crt_.set_scan_target(scan_target);
}
@@ -488,7 +488,7 @@ Outputs::Display::ScanStatus Nick::get_scaled_scan_status() const {
return crt_.get_scaled_scan_status();
}
void Nick::set_display_type(Outputs::Display::DisplayType display_type) {
void Nick::set_display_type(const Outputs::Display::DisplayType display_type) {
first_pixel_window_ = display_type == Outputs::Display::DisplayType::RGB ? 8 : 10;
crt_.set_display_type(display_type);
}
@@ -526,7 +526,7 @@ Outputs::Display::DisplayType Nick::get_display_type() const {
target[0] = mapped_colour(x); \
++target
template <int bpp, bool is_lpixel> void Nick::output_pixel(uint16_t *target, int columns) const {
template <int bpp, bool is_lpixel> void Nick::output_pixel(uint16_t *target, const int columns) const {
static_assert(bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8);
int index = 0;
@@ -576,7 +576,7 @@ template <int bpp, bool is_lpixel> void Nick::output_pixel(uint16_t *target, int
}
}
template <int bpp, int index_bits> void Nick::output_character(uint16_t *target, int columns) const {
template <int bpp, int index_bits> void Nick::output_character(uint16_t *target, const int columns) const {
static_assert(bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8);
for(int c = 0; c < columns; c++) {
@@ -605,7 +605,7 @@ template <int bpp, int index_bits> void Nick::output_character(uint16_t *target,
}
}
template <int bpp> void Nick::output_attributed(uint16_t *target, int columns) const {
template <int bpp> void Nick::output_attributed(uint16_t *target, const int columns) const {
static_assert(bpp == 1 || bpp == 2 || bpp == 4 || bpp == 8);
for(int c = 0; c < columns; c++) {
+85 -85
View File
@@ -15,108 +15,108 @@
namespace Enterprise {
class Nick {
public:
Nick(const uint8_t *ram);
public:
Nick(const uint8_t *ram);
/// Writes to a Nick register; only the low two bits are decoded.
void write(uint16_t address, uint8_t value);
/// Writes to a Nick register; only the low two bits are decoded.
void write(uint16_t address, uint8_t value);
/// Reads from the Nick range. Nobody seems to be completely clear what
/// this should return; I've set it up to return the last fetched video or mode
/// line byte during periods when those things are being fetched, 0xff at all
/// other times. Including during refresh, since I don't know what addresses
/// are generated then.
///
/// This likely isn't accurate, but is the most accurate guess I could make.
uint8_t read();
/// Reads from the Nick range. Nobody seems to be completely clear what
/// this should return; I've set it up to return the last fetched video or mode
/// line byte during periods when those things are being fetched, 0xff at all
/// other times. Including during refresh, since I don't know what addresses
/// are generated then.
///
/// This likely isn't accurate, but is the most accurate guess I could make.
uint8_t read();
void run_for(Cycles);
Cycles get_time_until_z80_slot(Cycles after_period) const;
void run_for(Cycles);
Cycles get_time_until_z80_slot(Cycles after_period) const;
void set_scan_target(Outputs::Display::ScanTarget *scan_target);
Outputs::Display::ScanStatus get_scaled_scan_status() const;
void set_scan_target(Outputs::Display::ScanTarget *);
Outputs::Display::ScanStatus get_scaled_scan_status() const;
/// @returns The amount of time until the next potential change in interrupt output.
Cycles next_sequence_point() const;
/// @returns The amount of time until the next potential change in interrupt output.
Cycles next_sequence_point() const;
/*!
@returns The current state of the interrupt line @c true for active;
@c false for inactive.
*/
inline bool get_interrupt_line() const {
return interrupt_line_;
}
/*!
@returns The current state of the interrupt line @c true for active;
@c false for inactive.
*/
inline bool get_interrupt_line() const {
return interrupt_line_;
}
/// Sets the type of output.
void set_display_type(Outputs::Display::DisplayType);
/// Sets the type of output.
void set_display_type(Outputs::Display::DisplayType);
/// Gets the type of output.
Outputs::Display::DisplayType get_display_type() const;
/// Gets the type of output.
Outputs::Display::DisplayType get_display_type() const;
private:
Outputs::CRT::CRT crt_;
const uint8_t *const ram_;
private:
Outputs::CRT::CRT crt_;
const uint8_t *const ram_;
// CPU-provided state.
uint8_t line_parameter_control_ = 0xc0;
uint16_t line_parameter_base_ = 0x0000;
uint16_t border_colour_ = 0;
// CPU-provided state.
uint8_t line_parameter_control_ = 0xc0;
uint16_t line_parameter_base_ = 0x0000;
uint16_t border_colour_ = 0;
// Ephemerals, related to current video position.
int horizontal_counter_ = 0;
uint16_t line_parameter_pointer_ = 0x0000;
bool should_reload_line_parameters_ = true;
uint16_t line_data_pointer_[2];
uint16_t start_line_data_pointer_[2];
mutable uint8_t last_read_ = 0xff;
// Ephemerals, related to current video position.
int horizontal_counter_ = 0;
uint16_t line_parameter_pointer_ = 0x0000;
bool should_reload_line_parameters_ = true;
uint16_t line_data_pointer_[2];
uint16_t start_line_data_pointer_[2];
mutable uint8_t last_read_ = 0xff;
// Current mode line parameters.
uint8_t lines_remaining_ = 0x00;
uint8_t two_colour_mask_ = 0xff;
int left_margin_ = 0, right_margin_ = 0;
const uint16_t *alt_ind_palettes[4] = {palette_, palette_, palette_, palette_};
enum class Mode {
Vsync,
Pixel,
Attr,
CH256,
CH128,
CH64,
Unused,
LPixel,
} mode_ = Mode::Vsync;
bool is_sync_or_pixels_ = false;
int bpp_ = 0;
int column_size_ = 0;
bool interrupt_line_ = true;
int line_data_per_column_increments_[2] = {0, 0};
bool vres_ = false;
bool reload_line_parameter_pointer_ = false;
// Current mode line parameters.
uint8_t lines_remaining_ = 0x00;
uint8_t two_colour_mask_ = 0xff;
int left_margin_ = 0, right_margin_ = 0;
const uint16_t *alt_ind_palettes[4] = {palette_, palette_, palette_, palette_};
enum class Mode {
Vsync,
Pixel,
Attr,
CH256,
CH128,
CH64,
Unused,
LPixel,
} mode_ = Mode::Vsync;
bool is_sync_or_pixels_ = false;
int bpp_ = 0;
int column_size_ = 0;
bool interrupt_line_ = true;
int line_data_per_column_increments_[2] = {0, 0};
bool vres_ = false;
bool reload_line_parameter_pointer_ = false;
// The destination for new pixels.
static constexpr int allocation_size = 336;
static_assert((allocation_size % 16) == 0, "Allocation size must be a multiple of 16");
uint16_t *pixel_pointer_ = nullptr, *allocated_pointer_ = nullptr;
// The destination for new pixels.
static constexpr int allocation_size = 336;
static_assert((allocation_size % 16) == 0, "Allocation size must be a multiple of 16");
uint16_t *pixel_pointer_ = nullptr, *allocated_pointer_ = nullptr;
// Output transitions.
enum class OutputType {
Sync, Blank, Pixels, Border, ColourBurst
};
void set_output_type(OutputType, bool force_flush = false);
int output_duration_ = 0;
OutputType output_type_ = OutputType::Sync;
// Output transitions.
enum class OutputType {
Sync, Blank, Pixels, Border, ColourBurst
};
void set_output_type(OutputType, bool force_flush = false);
int output_duration_ = 0;
OutputType output_type_ = OutputType::Sync;
// Current palette.
uint16_t palette_[16]{};
// Current palette.
uint16_t palette_[16]{};
// The first column with pixels on it; will be either 8 or 10 depending
// on whether the colour burst is meaningful to the current display type.
int first_pixel_window_ = 10;
// The first column with pixels on it; will be either 8 or 10 depending
// on whether the colour burst is meaningful to the current display type.
int first_pixel_window_ = 10;
// Specific outputters.
template <int bpp, bool is_lpixel> void output_pixel(uint16_t *target, int columns) const;
template <int bpp, int index_bits> void output_character(uint16_t *target, int columns) const;
template <int bpp> void output_attributed(uint16_t *target, int columns) const;
// Specific outputters.
template <int bpp, bool is_lpixel> void output_pixel(uint16_t *target, int columns) const;
template <int bpp, int index_bits> void output_character(uint16_t *target, int columns) const;
template <int bpp> void output_attributed(uint16_t *target, int columns) const;
};
}