mirror of
https://github.com/TomHarte/CLK.git
synced 2024-09-06 05:54:28 +00:00
Merge pull request #258 from TomHarte/UndefinedBehaviour
Corrects large swathes of undefined behaviour
This commit is contained in:
commit
57ee09dffb
@ -161,7 +161,7 @@ class HalfCycles: public WrappedInt<HalfCycles> {
|
|||||||
inline HalfCycles(int l) : WrappedInt<HalfCycles>(l) {}
|
inline HalfCycles(int l) : WrappedInt<HalfCycles>(l) {}
|
||||||
inline HalfCycles() : WrappedInt<HalfCycles>() {}
|
inline HalfCycles() : WrappedInt<HalfCycles>() {}
|
||||||
|
|
||||||
inline HalfCycles(const Cycles cycles) : WrappedInt<HalfCycles>(cycles.as_int() << 1) {}
|
inline HalfCycles(const Cycles cycles) : WrappedInt<HalfCycles>(cycles.as_int() * 2) {}
|
||||||
inline HalfCycles(const HalfCycles &half_cycles) : WrappedInt<HalfCycles>(half_cycles.length_) {}
|
inline HalfCycles(const HalfCycles &half_cycles) : WrappedInt<HalfCycles>(half_cycles.length_) {}
|
||||||
|
|
||||||
/// @returns The number of whole cycles completely covered by this span of half cycles.
|
/// @returns The number of whole cycles completely covered by this span of half cycles.
|
||||||
|
@ -18,12 +18,12 @@ namespace Motorola {
|
|||||||
namespace CRTC {
|
namespace CRTC {
|
||||||
|
|
||||||
struct BusState {
|
struct BusState {
|
||||||
bool display_enable;
|
bool display_enable = false;
|
||||||
bool hsync;
|
bool hsync = false;
|
||||||
bool vsync;
|
bool vsync = false;
|
||||||
bool cursor;
|
bool cursor = false;
|
||||||
uint16_t refresh_address;
|
uint16_t refresh_address = 0;
|
||||||
uint16_t row_address;
|
uint16_t row_address = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BusHandler {
|
class BusHandler {
|
||||||
@ -167,8 +167,8 @@ template <class T> class CRTC6845 {
|
|||||||
private:
|
private:
|
||||||
inline void perform_bus_cycle_phase1() {
|
inline void perform_bus_cycle_phase1() {
|
||||||
// Skew theory of operation: keep a history of the last three states, and apply whichever is selected.
|
// Skew theory of operation: keep a history of the last three states, and apply whichever is selected.
|
||||||
character_is_visible_shifter_ = (character_is_visible_shifter_ << 1) | static_cast<int>(character_is_visible_);
|
character_is_visible_shifter_ = (character_is_visible_shifter_ << 1) | static_cast<unsigned int>(character_is_visible_);
|
||||||
bus_state_.display_enable = (character_is_visible_shifter_ & display_skew_mask_) && line_is_visible_;
|
bus_state_.display_enable = (static_cast<int>(character_is_visible_shifter_) & display_skew_mask_) && line_is_visible_;
|
||||||
bus_handler_.perform_bus_cycle_phase1(bus_state_);
|
bus_handler_.perform_bus_cycle_phase1(bus_state_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -248,25 +248,25 @@ template <class T> class CRTC6845 {
|
|||||||
T &bus_handler_;
|
T &bus_handler_;
|
||||||
BusState bus_state_;
|
BusState bus_state_;
|
||||||
|
|
||||||
uint8_t registers_[18];
|
uint8_t registers_[18] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||||
uint8_t dummy_register_;
|
uint8_t dummy_register_ = 0;
|
||||||
int selected_register_;
|
int selected_register_ = 0;
|
||||||
|
|
||||||
uint8_t character_counter_;
|
uint8_t character_counter_ = 0;
|
||||||
uint8_t line_counter_;
|
uint8_t line_counter_ = 0;
|
||||||
|
|
||||||
bool character_is_visible_, line_is_visible_;
|
bool character_is_visible_ = false, line_is_visible_ = false;
|
||||||
|
|
||||||
int hsync_counter_;
|
int hsync_counter_ = 0;
|
||||||
int vsync_counter_;
|
int vsync_counter_ = 0;
|
||||||
bool is_in_adjustment_period_;
|
bool is_in_adjustment_period_ = false;
|
||||||
|
|
||||||
uint16_t line_address_;
|
uint16_t line_address_ = 0;
|
||||||
uint16_t end_of_line_address_;
|
uint16_t end_of_line_address_ = 0;
|
||||||
uint8_t status_;
|
uint8_t status_ = 0;
|
||||||
|
|
||||||
int display_skew_mask_ = 1;
|
int display_skew_mask_ = 1;
|
||||||
int character_is_visible_shifter_ = 0;
|
unsigned int character_is_visible_shifter_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -79,14 +79,7 @@ namespace {
|
|||||||
|
|
||||||
i8272::i8272(BusHandler &bus_handler, Cycles clock_rate) :
|
i8272::i8272(BusHandler &bus_handler, Cycles clock_rate) :
|
||||||
Storage::Disk::MFMController(clock_rate),
|
Storage::Disk::MFMController(clock_rate),
|
||||||
bus_handler_(bus_handler),
|
bus_handler_(bus_handler) {
|
||||||
main_status_(0),
|
|
||||||
interesting_event_mask_((int)Event8272::CommandByte),
|
|
||||||
resume_point_(0),
|
|
||||||
delay_time_(0),
|
|
||||||
head_timers_running_(0),
|
|
||||||
expects_input_(false),
|
|
||||||
drives_seeking_(0) {
|
|
||||||
posit_event((int)Event8272::CommandByte);
|
posit_event((int)Event8272::CommandByte);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,15 +50,15 @@ class i8272: public Storage::Disk::MFMController {
|
|||||||
std::unique_ptr<BusHandler> allocated_bus_handler_;
|
std::unique_ptr<BusHandler> allocated_bus_handler_;
|
||||||
|
|
||||||
// Status registers.
|
// Status registers.
|
||||||
uint8_t main_status_;
|
uint8_t main_status_ = 0;
|
||||||
uint8_t status_[3];
|
uint8_t status_[3] = {0, 0, 0};
|
||||||
|
|
||||||
// A buffer for accumulating the incoming command, and one for accumulating the result.
|
// A buffer for accumulating the incoming command, and one for accumulating the result.
|
||||||
std::vector<uint8_t> command_;
|
std::vector<uint8_t> command_;
|
||||||
std::vector<uint8_t> result_stack_;
|
std::vector<uint8_t> result_stack_;
|
||||||
uint8_t input_;
|
uint8_t input_ = 0;
|
||||||
bool has_input_;
|
bool has_input_ = false;
|
||||||
bool expects_input_;
|
bool expects_input_ = false;
|
||||||
|
|
||||||
// Event stream: the 8272-specific events, plus the current event state.
|
// Event stream: the 8272-specific events, plus the current event state.
|
||||||
enum class Event8272: int {
|
enum class Event8272: int {
|
||||||
@ -68,41 +68,37 @@ class i8272: public Storage::Disk::MFMController {
|
|||||||
NoLongerReady = (1 << 6)
|
NoLongerReady = (1 << 6)
|
||||||
};
|
};
|
||||||
void posit_event(int type);
|
void posit_event(int type);
|
||||||
int interesting_event_mask_;
|
int interesting_event_mask_ = (int)Event8272::CommandByte;
|
||||||
int resume_point_;
|
int resume_point_ = 0;
|
||||||
bool is_access_command_;
|
bool is_access_command_ = false;
|
||||||
|
|
||||||
// The counter used for ::Timer events.
|
// The counter used for ::Timer events.
|
||||||
int delay_time_;
|
int delay_time_ = 0;
|
||||||
|
|
||||||
// The connected drives.
|
// The connected drives.
|
||||||
struct Drive {
|
struct Drive {
|
||||||
uint8_t head_position;
|
uint8_t head_position = 0;
|
||||||
|
|
||||||
// Seeking: persistent state.
|
// Seeking: persistent state.
|
||||||
enum Phase {
|
enum Phase {
|
||||||
NotSeeking,
|
NotSeeking,
|
||||||
Seeking,
|
Seeking,
|
||||||
CompletedSeeking
|
CompletedSeeking
|
||||||
} phase;
|
} phase = NotSeeking;
|
||||||
bool did_seek;
|
bool did_seek = false;
|
||||||
bool seek_failed;
|
bool seek_failed = false;
|
||||||
|
|
||||||
// Seeking: transient state.
|
// Seeking: transient state.
|
||||||
int step_rate_counter;
|
int step_rate_counter = 0;
|
||||||
int steps_taken;
|
int steps_taken = 0;
|
||||||
int target_head_position; // either an actual number, or -1 to indicate to step until track zero
|
int target_head_position = 0; // either an actual number, or -1 to indicate to step until track zero
|
||||||
|
|
||||||
// Head state.
|
// Head state.
|
||||||
int head_unload_delay[2];
|
int head_unload_delay[2] = {0, 0};
|
||||||
bool head_is_loaded[2];
|
bool head_is_loaded[2] = {false, false};
|
||||||
|
|
||||||
Drive() :
|
|
||||||
head_position(0), phase(NotSeeking),
|
|
||||||
head_is_loaded{false, false},
|
|
||||||
head_unload_delay{0, 0} {};
|
|
||||||
} drives_[4];
|
} drives_[4];
|
||||||
int drives_seeking_;
|
int drives_seeking_ = 0;
|
||||||
|
|
||||||
/// @returns @c true if the selected drive, which is number @c drive, can stop seeking.
|
/// @returns @c true if the selected drive, which is number @c drive, can stop seeking.
|
||||||
bool seek_is_satisfied(int drive);
|
bool seek_is_satisfied(int drive);
|
||||||
@ -115,22 +111,22 @@ class i8272: public Storage::Disk::MFMController {
|
|||||||
bool is_executing_ = false;
|
bool is_executing_ = false;
|
||||||
|
|
||||||
// A count of head unload timers currently running.
|
// A count of head unload timers currently running.
|
||||||
int head_timers_running_;
|
int head_timers_running_ = 0;
|
||||||
|
|
||||||
// Transient storage and counters used while reading the disk.
|
// Transient storage and counters used while reading the disk.
|
||||||
uint8_t header_[6];
|
uint8_t header_[6] = {0, 0, 0, 0, 0, 0};
|
||||||
int distance_into_section_;
|
int distance_into_section_ = 0;
|
||||||
int index_hole_count_, index_hole_limit_;
|
int index_hole_count_ = 0, index_hole_limit_ = 0;
|
||||||
|
|
||||||
// Keeps track of the drive and head in use during commands.
|
// Keeps track of the drive and head in use during commands.
|
||||||
int active_drive_;
|
int active_drive_ = 0;
|
||||||
int active_head_;
|
int active_head_ = 0;
|
||||||
|
|
||||||
// Internal registers.
|
// Internal registers.
|
||||||
uint8_t cylinder_, head_, sector_, size_;
|
uint8_t cylinder_ = 0, head_ = 0, sector_ = 0, size_ = 0;
|
||||||
|
|
||||||
// Master switch on not performing any work.
|
// Master switch on not performing any work.
|
||||||
bool is_sleeping_;
|
bool is_sleeping_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -155,18 +155,8 @@ class AYDeferrer {
|
|||||||
class CRTCBusHandler {
|
class CRTCBusHandler {
|
||||||
public:
|
public:
|
||||||
CRTCBusHandler(uint8_t *ram, InterruptTimer &interrupt_timer) :
|
CRTCBusHandler(uint8_t *ram, InterruptTimer &interrupt_timer) :
|
||||||
cycles_(0),
|
|
||||||
was_enabled_(false),
|
|
||||||
was_sync_(false),
|
|
||||||
pixel_data_(nullptr),
|
|
||||||
pixel_pointer_(nullptr),
|
|
||||||
was_hsync_(false),
|
|
||||||
ram_(ram),
|
ram_(ram),
|
||||||
interrupt_timer_(interrupt_timer),
|
interrupt_timer_(interrupt_timer) {
|
||||||
pixel_divider_(1),
|
|
||||||
mode_(2),
|
|
||||||
next_mode_(2),
|
|
||||||
cycles_into_hsync_(0) {
|
|
||||||
establish_palette_hits();
|
establish_palette_hits();
|
||||||
build_mode_table();
|
build_mode_table();
|
||||||
}
|
}
|
||||||
@ -217,7 +207,7 @@ class CRTCBusHandler {
|
|||||||
// collect some more pixels if output is ongoing
|
// collect some more pixels if output is ongoing
|
||||||
if(!is_sync && state.display_enable) {
|
if(!is_sync && state.display_enable) {
|
||||||
if(!pixel_data_) {
|
if(!pixel_data_) {
|
||||||
pixel_pointer_ = pixel_data_ = crt_->allocate_write_area(320);
|
pixel_pointer_ = pixel_data_ = crt_->allocate_write_area(320, 8);
|
||||||
}
|
}
|
||||||
if(pixel_pointer_) {
|
if(pixel_pointer_) {
|
||||||
// the CPC shuffles output lines as:
|
// the CPC shuffles output lines as:
|
||||||
@ -500,19 +490,19 @@ class CRTCBusHandler {
|
|||||||
return mapping[colour];
|
return mapping[colour];
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int cycles_;
|
unsigned int cycles_ = 0;
|
||||||
|
|
||||||
bool was_enabled_, was_sync_, was_hsync_, was_vsync_;
|
bool was_enabled_ = false, was_sync_ = false, was_hsync_ = false, was_vsync_ = false;
|
||||||
int cycles_into_hsync_;
|
int cycles_into_hsync_ = 0;
|
||||||
|
|
||||||
std::shared_ptr<Outputs::CRT::CRT> crt_;
|
std::shared_ptr<Outputs::CRT::CRT> crt_;
|
||||||
uint8_t *pixel_data_, *pixel_pointer_;
|
uint8_t *pixel_data_ = nullptr, *pixel_pointer_ = nullptr;
|
||||||
|
|
||||||
uint8_t *ram_;
|
uint8_t *ram_ = nullptr;
|
||||||
|
|
||||||
int next_mode_, mode_;
|
int next_mode_ = 2, mode_ = 2;
|
||||||
|
|
||||||
unsigned int pixel_divider_;
|
unsigned int pixel_divider_ = 1;
|
||||||
uint16_t mode0_output_[256];
|
uint16_t mode0_output_[256];
|
||||||
uint32_t mode1_output_[256];
|
uint32_t mode1_output_[256];
|
||||||
uint64_t mode2_output_[256];
|
uint64_t mode2_output_[256];
|
||||||
@ -522,9 +512,9 @@ class CRTCBusHandler {
|
|||||||
std::vector<uint8_t> mode1_palette_hits_[4];
|
std::vector<uint8_t> mode1_palette_hits_[4];
|
||||||
std::vector<uint8_t> mode3_palette_hits_[4];
|
std::vector<uint8_t> mode3_palette_hits_[4];
|
||||||
|
|
||||||
int pen_;
|
int pen_ = 0;
|
||||||
uint8_t palette_[16];
|
uint8_t palette_[16];
|
||||||
uint8_t border_;
|
uint8_t border_ = 0;
|
||||||
|
|
||||||
InterruptTimer &interrupt_timer_;
|
InterruptTimer &interrupt_timer_;
|
||||||
};
|
};
|
||||||
|
@ -106,7 +106,7 @@ void VideoOutput::output_pixels(unsigned int number_of_cycles) {
|
|||||||
if(!initial_output_target_ || divider != current_output_divider_) {
|
if(!initial_output_target_ || divider != current_output_divider_) {
|
||||||
if(current_output_target_) crt_->output_data((unsigned int)((current_output_target_ - initial_output_target_) * current_output_divider_), current_output_divider_);
|
if(current_output_target_) crt_->output_data((unsigned int)((current_output_target_ - initial_output_target_) * current_output_divider_), current_output_divider_);
|
||||||
current_output_divider_ = divider;
|
current_output_divider_ = divider;
|
||||||
initial_output_target_ = current_output_target_ = crt_->allocate_write_area(640 / current_output_divider_);
|
initial_output_target_ = current_output_target_ = crt_->allocate_write_area(640 / current_output_divider_, 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define get_pixel() \
|
#define get_pixel() \
|
||||||
|
@ -90,13 +90,8 @@ void CRT::update_gamma() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
CRT::CRT(unsigned int common_output_divisor, unsigned int buffer_depth) :
|
CRT::CRT(unsigned int common_output_divisor, unsigned int buffer_depth) :
|
||||||
is_receiving_sync_(false),
|
|
||||||
common_output_divisor_(common_output_divisor),
|
common_output_divisor_(common_output_divisor),
|
||||||
is_writing_composite_run_(false),
|
openGL_output_builder_(buffer_depth) {}
|
||||||
delegate_(nullptr),
|
|
||||||
frames_since_last_delegate_call_(0),
|
|
||||||
openGL_output_builder_(buffer_depth),
|
|
||||||
is_alernate_line_(false) {}
|
|
||||||
|
|
||||||
CRT::CRT( unsigned int cycles_per_line,
|
CRT::CRT( unsigned int cycles_per_line,
|
||||||
unsigned int common_output_divisor,
|
unsigned int common_output_divisor,
|
||||||
|
@ -33,12 +33,12 @@ class CRT {
|
|||||||
|
|
||||||
// the incoming clock lengths will be multiplied by something to give at least 1000
|
// the incoming clock lengths will be multiplied by something to give at least 1000
|
||||||
// sample points per line
|
// sample points per line
|
||||||
unsigned int time_multiplier_;
|
unsigned int time_multiplier_ = 1;
|
||||||
const unsigned int common_output_divisor_;
|
const unsigned int common_output_divisor_ = 1;
|
||||||
|
|
||||||
// the two flywheels regulating scanning
|
// the two flywheels regulating scanning
|
||||||
std::unique_ptr<Flywheel> horizontal_flywheel_, vertical_flywheel_;
|
std::unique_ptr<Flywheel> horizontal_flywheel_, vertical_flywheel_;
|
||||||
uint16_t vertical_flywheel_output_divider_;
|
uint16_t vertical_flywheel_output_divider_ = 1;
|
||||||
|
|
||||||
struct Scan {
|
struct Scan {
|
||||||
enum Type {
|
enum Type {
|
||||||
@ -53,11 +53,11 @@ class CRT {
|
|||||||
};
|
};
|
||||||
void output_scan(const Scan *scan);
|
void output_scan(const Scan *scan);
|
||||||
|
|
||||||
uint8_t colour_burst_phase_, colour_burst_amplitude_, colour_burst_phase_adjustment_;
|
uint8_t colour_burst_phase_ = 0, colour_burst_amplitude_ = 30, colour_burst_phase_adjustment_ = 0;
|
||||||
bool is_writing_composite_run_;
|
bool is_writing_composite_run_ = false;
|
||||||
|
|
||||||
unsigned int phase_denominator_, phase_numerator_, colour_cycle_numerator_;
|
unsigned int phase_denominator_ = 1, phase_numerator_ = 1, colour_cycle_numerator_ = 1;
|
||||||
bool is_alernate_line_, phase_alternates_;
|
bool is_alernate_line_ = false, phase_alternates_ = false;
|
||||||
|
|
||||||
// the outer entry point for dispatching output_sync, output_blank, output_level and output_data
|
// the outer entry point for dispatching output_sync, output_blank, output_level and output_data
|
||||||
void advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bool vsync_requested, const Scan::Type type);
|
void advance_cycles(unsigned int number_of_cycles, bool hsync_requested, bool vsync_requested, const Scan::Type type);
|
||||||
@ -76,8 +76,8 @@ class CRT {
|
|||||||
} output_run_;
|
} output_run_;
|
||||||
|
|
||||||
// the delegate
|
// the delegate
|
||||||
Delegate *delegate_;
|
Delegate *delegate_ = nullptr;
|
||||||
unsigned int frames_since_last_delegate_call_;
|
unsigned int frames_since_last_delegate_call_ = 0;
|
||||||
|
|
||||||
// queued tasks for the OpenGL queue; performed before the next draw
|
// queued tasks for the OpenGL queue; performed before the next draw
|
||||||
std::mutex function_mutex_;
|
std::mutex function_mutex_;
|
||||||
@ -88,16 +88,16 @@ class CRT {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// sync counter, for determining vertical sync
|
// sync counter, for determining vertical sync
|
||||||
bool is_receiving_sync_; // true if the CRT is currently receiving sync (i.e. this is for edge triggering of horizontal sync)
|
bool is_receiving_sync_ = false; // true if the CRT is currently receiving sync (i.e. this is for edge triggering of horizontal sync)
|
||||||
bool is_accumulating_sync_; // true if a sync level has triggered the suspicion that a vertical sync might be in progress
|
bool is_accumulating_sync_ = false; // true if a sync level has triggered the suspicion that a vertical sync might be in progress
|
||||||
bool is_refusing_sync_; // true once a vertical sync has been detected, until a prolonged period of non-sync has ended suspicion of an ongoing vertical sync
|
bool is_refusing_sync_ = false; // true once a vertical sync has been detected, until a prolonged period of non-sync has ended suspicion of an ongoing vertical sync
|
||||||
unsigned int sync_capacitor_charge_threshold_; // this charges up during times of sync and depletes otherwise; needs to hit a required threshold to trigger a vertical sync
|
unsigned int sync_capacitor_charge_threshold_ = 0; // this charges up during times of sync and depletes otherwise; needs to hit a required threshold to trigger a vertical sync
|
||||||
unsigned int cycles_of_sync_; // the number of cycles since the potential vertical sync began
|
unsigned int cycles_of_sync_ = 0; // the number of cycles since the potential vertical sync began
|
||||||
unsigned int cycles_since_sync_; // the number of cycles since last in sync, for defeating the possibility of this being a vertical sync
|
unsigned int cycles_since_sync_ = 0; // the number of cycles since last in sync, for defeating the possibility of this being a vertical sync
|
||||||
|
|
||||||
unsigned int cycles_per_line_;
|
unsigned int cycles_per_line_ = 1;
|
||||||
|
|
||||||
float input_gamma_, output_gamma_;
|
float input_gamma_ = 1.0f, output_gamma_ = 1.0f;
|
||||||
void update_gamma();
|
void update_gamma();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -221,9 +221,9 @@ class CRT {
|
|||||||
@param required_length The number of samples to allocate.
|
@param required_length The number of samples to allocate.
|
||||||
@returns A pointer to the allocated area if room is available; @c nullptr otherwise.
|
@returns A pointer to the allocated area if room is available; @c nullptr otherwise.
|
||||||
*/
|
*/
|
||||||
inline uint8_t *allocate_write_area(size_t required_length) {
|
inline uint8_t *allocate_write_area(size_t required_length, size_t required_alignment = 1) {
|
||||||
std::unique_lock<std::mutex> output_lock = openGL_output_builder_.get_output_lock();
|
std::unique_lock<std::mutex> output_lock = openGL_output_builder_.get_output_lock();
|
||||||
return openGL_output_builder_.texture_builder.allocate_write_area(required_length);
|
return openGL_output_builder_.texture_builder.allocate_write_area(required_length, required_alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*! Causes appropriate OpenGL or OpenGL ES calls to be issued in order to draw the current CRT state.
|
/*! Causes appropriate OpenGL or OpenGL ES calls to be issued in order to draw the current CRT state.
|
||||||
|
@ -67,9 +67,7 @@ ArrayBuilder::Submission ArrayBuilder::submit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ArrayBuilder::Buffer::Buffer(size_t size, std::function<void(bool is_input, uint8_t *, size_t)> submission_function) :
|
ArrayBuilder::Buffer::Buffer(size_t size, std::function<void(bool is_input, uint8_t *, size_t)> submission_function) :
|
||||||
is_full(false),
|
submission_function_(submission_function) {
|
||||||
submission_function_(submission_function),
|
|
||||||
allocated_data(0), flushed_data(0), submitted_data(0) {
|
|
||||||
if(!submission_function_) {
|
if(!submission_function_) {
|
||||||
glGenBuffers(1, &buffer);
|
glGenBuffers(1, &buffer);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
glBindBuffer(GL_ARRAY_BUFFER, buffer);
|
||||||
|
@ -82,17 +82,17 @@ class ArrayBuilder {
|
|||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool is_full;
|
bool is_full = false;
|
||||||
GLuint buffer;
|
GLuint buffer = 0;
|
||||||
std::function<void(bool is_input, uint8_t *, size_t)> submission_function_;
|
std::function<void(bool is_input, uint8_t *, size_t)> submission_function_;
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data;
|
||||||
size_t allocated_data;
|
size_t allocated_data = 0;
|
||||||
size_t flushed_data;
|
size_t flushed_data = 0;
|
||||||
size_t submitted_data;
|
size_t submitted_data = 0;
|
||||||
} output_, input_;
|
} output_, input_;
|
||||||
uint8_t *get_storage(size_t size, Buffer &buffer);
|
uint8_t *get_storage(size_t size, Buffer &buffer);
|
||||||
|
|
||||||
bool is_full_;
|
bool is_full_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ inline uint8_t *TextureBuilder::pointer_to_location(uint16_t x, uint16_t y) {
|
|||||||
return &image_[((y * InputBufferBuilderWidth) + x) * bytes_per_pixel_];
|
return &image_[((y * InputBufferBuilderWidth) + x) * bytes_per_pixel_];
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t *TextureBuilder::allocate_write_area(size_t required_length) {
|
uint8_t *TextureBuilder::allocate_write_area(size_t required_length, size_t required_alignment) {
|
||||||
// Keep a flag to indicate whether the buffer was full at allocate_write_area; if it was then
|
// Keep a flag to indicate whether the buffer was full at allocate_write_area; if it was then
|
||||||
// don't return anything now, and decline to act upon follow-up methods. is_full_ may be reset
|
// don't return anything now, and decline to act upon follow-up methods. is_full_ may be reset
|
||||||
// by asynchronous calls to submit. was_full_ will not be touched by it.
|
// by asynchronous calls to submit. was_full_ will not be touched by it.
|
||||||
@ -69,8 +69,10 @@ uint8_t *TextureBuilder::allocate_write_area(size_t required_length) {
|
|||||||
|
|
||||||
// If there's not enough space on this line, move to the next. If the next is where the current
|
// If there's not enough space on this line, move to the next. If the next is where the current
|
||||||
// submission group started, trigger is/was_full_ and return nothing.
|
// submission group started, trigger is/was_full_ and return nothing.
|
||||||
if(write_areas_start_x_ + required_length + 2 > InputBufferBuilderWidth) {
|
size_t alignment_offset = (required_alignment - ((write_areas_start_x_ + 1) % required_alignment)) % required_alignment;
|
||||||
|
if(write_areas_start_x_ + required_length + 2 + alignment_offset > InputBufferBuilderWidth) {
|
||||||
write_areas_start_x_ = 0;
|
write_areas_start_x_ = 0;
|
||||||
|
alignment_offset = (required_alignment - 1) % required_alignment;
|
||||||
write_areas_start_y_ = (write_areas_start_y_ + 1) % InputBufferBuilderHeight;
|
write_areas_start_y_ = (write_areas_start_y_ + 1) % InputBufferBuilderHeight;
|
||||||
|
|
||||||
if(write_areas_start_y_ == first_unsubmitted_y_) {
|
if(write_areas_start_y_ == first_unsubmitted_y_) {
|
||||||
@ -80,7 +82,7 @@ uint8_t *TextureBuilder::allocate_write_area(size_t required_length) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Queue up the latest write area.
|
// Queue up the latest write area.
|
||||||
write_area_.x = write_areas_start_x_ + 1;
|
write_area_.x = write_areas_start_x_ + 1 + static_cast<uint16_t>(alignment_offset);
|
||||||
write_area_.y = write_areas_start_y_;
|
write_area_.y = write_areas_start_y_;
|
||||||
write_area_.length = (uint16_t)required_length;
|
write_area_.length = (uint16_t)required_length;
|
||||||
|
|
||||||
@ -99,13 +101,13 @@ void TextureBuilder::reduce_previous_allocation_to(size_t actual_length) {
|
|||||||
// against rounding errors when this run is drawn.
|
// against rounding errors when this run is drawn.
|
||||||
// TODO: allow somebody else to specify the rule for generating a left-padding value and
|
// TODO: allow somebody else to specify the rule for generating a left-padding value and
|
||||||
// a right-padding value.
|
// a right-padding value.
|
||||||
uint8_t *start_pointer = pointer_to_location(write_area_.x, write_area_.y);
|
uint8_t *start_pointer = pointer_to_location(write_area_.x, write_area_.y) - bytes_per_pixel_;
|
||||||
memcpy( &start_pointer[-bytes_per_pixel_],
|
memcpy( start_pointer,
|
||||||
start_pointer,
|
&start_pointer[bytes_per_pixel_],
|
||||||
bytes_per_pixel_);
|
bytes_per_pixel_);
|
||||||
|
|
||||||
memcpy( &start_pointer[actual_length * bytes_per_pixel_],
|
memcpy( &start_pointer[(actual_length + 1) * bytes_per_pixel_],
|
||||||
&start_pointer[(actual_length - 1) * bytes_per_pixel_],
|
&start_pointer[actual_length * bytes_per_pixel_],
|
||||||
bytes_per_pixel_);
|
bytes_per_pixel_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -66,10 +66,11 @@ class TextureBuilder {
|
|||||||
TextureBuilder(size_t bytes_per_pixel, GLenum texture_unit);
|
TextureBuilder(size_t bytes_per_pixel, GLenum texture_unit);
|
||||||
virtual ~TextureBuilder();
|
virtual ~TextureBuilder();
|
||||||
|
|
||||||
/// Finds the first available space of at least @c required_length pixels in size. Calls must be paired off
|
/// Finds the first available space of at least @c required_length pixels in size which is suitably aligned
|
||||||
/// with calls to @c reduce_previous_allocation_to.
|
/// for writing of @c required_alignment number of pixels at a time.
|
||||||
|
/// Calls must be paired off with calls to @c reduce_previous_allocation_to.
|
||||||
/// @returns a pointer to the allocated space if any was available; @c nullptr otherwise.
|
/// @returns a pointer to the allocated space if any was available; @c nullptr otherwise.
|
||||||
uint8_t *allocate_write_area(size_t required_length);
|
uint8_t *allocate_write_area(size_t required_length, size_t required_alignment = 1);
|
||||||
|
|
||||||
/// Announces that the owner is finished with the region created by the most recent @c allocate_write_area
|
/// Announces that the owner is finished with the region created by the most recent @c allocate_write_area
|
||||||
/// and indicates that its actual final size was @c actual_length.
|
/// and indicates that its actual final size was @c actual_length.
|
||||||
|
@ -13,13 +13,9 @@
|
|||||||
using namespace Storage;
|
using namespace Storage;
|
||||||
|
|
||||||
DigitalPhaseLockedLoop::DigitalPhaseLockedLoop(int clocks_per_bit, size_t length_of_history) :
|
DigitalPhaseLockedLoop::DigitalPhaseLockedLoop(int clocks_per_bit, size_t length_of_history) :
|
||||||
clocks_per_bit_(clocks_per_bit),
|
|
||||||
phase_(0),
|
|
||||||
window_length_(clocks_per_bit),
|
|
||||||
offset_history_pointer_(0),
|
|
||||||
offset_history_(length_of_history, 0),
|
offset_history_(length_of_history, 0),
|
||||||
offset_(0),
|
window_length_(clocks_per_bit),
|
||||||
delegate_(nullptr) {}
|
clocks_per_bit_(clocks_per_bit) {}
|
||||||
|
|
||||||
void DigitalPhaseLockedLoop::run_for(const Cycles cycles) {
|
void DigitalPhaseLockedLoop::run_for(const Cycles cycles) {
|
||||||
offset_ += cycles.as_int();
|
offset_ += cycles.as_int();
|
||||||
|
@ -50,20 +50,20 @@ class DigitalPhaseLockedLoop {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Delegate *delegate_;
|
Delegate *delegate_ = nullptr;
|
||||||
|
|
||||||
void post_phase_offset(int phase, int offset);
|
void post_phase_offset(int phase, int offset);
|
||||||
|
|
||||||
std::vector<int> offset_history_;
|
std::vector<int> offset_history_;
|
||||||
size_t offset_history_pointer_;
|
size_t offset_history_pointer_ = 0;
|
||||||
int offset_;
|
int offset_ = 0;
|
||||||
|
|
||||||
int phase_;
|
int phase_ = 0;
|
||||||
int window_length_;
|
int window_length_ = 0;
|
||||||
bool window_was_filled_;
|
bool window_was_filled_ = false;
|
||||||
|
|
||||||
int clocks_per_bit_;
|
int clocks_per_bit_ = 0;
|
||||||
int tolerance_;
|
int tolerance_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ void Shifter::set_should_obey_syncs(bool should_obey_syncs) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Shifter::add_input_bit(int value) {
|
void Shifter::add_input_bit(int value) {
|
||||||
shift_register_ = (shift_register_ << 1) | value;
|
shift_register_ = (shift_register_ << 1) | static_cast<unsigned int>(value);
|
||||||
bits_since_token_++;
|
bits_since_token_++;
|
||||||
|
|
||||||
token_ = Token::None;
|
token_ = Token::None;
|
||||||
|
@ -40,10 +40,10 @@ class Shifter {
|
|||||||
private:
|
private:
|
||||||
// Bit stream input state
|
// Bit stream input state
|
||||||
int bits_since_token_ = 0;
|
int bits_since_token_ = 0;
|
||||||
int shift_register_ = 0;
|
unsigned int shift_register_ = 0;
|
||||||
bool is_awaiting_marker_value_ = false;
|
bool is_awaiting_marker_value_ = false;
|
||||||
bool should_obey_syncs_;
|
bool should_obey_syncs_ = true;
|
||||||
Token token_;
|
Token token_ = None;
|
||||||
|
|
||||||
// input configuration
|
// input configuration
|
||||||
bool is_double_density_ = false;
|
bool is_double_density_ = false;
|
||||||
|
@ -41,14 +41,14 @@ int Parser::get_next_byte(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
|||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Parser::get_next_short(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
unsigned int Parser::get_next_short(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
||||||
int result = get_next_byte(tape);
|
unsigned int result = static_cast<unsigned int>(get_next_byte(tape));
|
||||||
result |= get_next_byte(tape) << 8;
|
result |= static_cast<unsigned int>(get_next_byte(tape)) << 8;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Parser::get_next_word(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
unsigned int Parser::get_next_word(const std::shared_ptr<Storage::Tape::Tape> &tape) {
|
||||||
int result = get_next_short(tape);
|
unsigned int result = get_next_short(tape);
|
||||||
result |= get_next_short(tape) << 8;
|
result |= get_next_short(tape) << 8;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -53,8 +53,8 @@ class Parser: public Storage::Tape::Parser<SymbolType>, public Shifter::Delegate
|
|||||||
|
|
||||||
int get_next_bit(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
int get_next_bit(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
||||||
int get_next_byte(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
int get_next_byte(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
||||||
int get_next_short(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
unsigned int get_next_short(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
||||||
int get_next_word(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
unsigned int get_next_word(const std::shared_ptr<Storage::Tape::Tape> &tape);
|
||||||
void reset_crc();
|
void reset_crc();
|
||||||
uint16_t get_crc();
|
uint16_t get_crc();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user