mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Merge branch 'MSX2' of github.com:TomHarte/CLK into MSX2
This commit is contained in:
commit
0d4dc214fb
@ -345,14 +345,16 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
next_line_buffer.is_refresh =
|
next_line_buffer.vertical_state =
|
||||||
this->screen_mode_ == ScreenMode::Blank ||
|
this->screen_mode_ == ScreenMode::Blank ?
|
||||||
this->is_vertical_blank();
|
VerticalState::Blank :
|
||||||
|
this->vertical_state();
|
||||||
|
const bool is_refresh = next_line_buffer.vertical_state == VerticalState::Blank;
|
||||||
|
|
||||||
// TODO: an actual sprites-enabled flag.
|
// TODO: an actual sprites-enabled flag.
|
||||||
Storage<personality>::begin_line(this->screen_mode_, next_line_buffer.is_refresh, false);
|
Storage<personality>::begin_line(this->screen_mode_, is_refresh, false);
|
||||||
|
|
||||||
if(next_line_buffer.is_refresh) {
|
if(is_refresh) {
|
||||||
// The Yamaha handles refresh lines via its own microprogram; other VDPs
|
// The Yamaha handles refresh lines via its own microprogram; other VDPs
|
||||||
// can fall back on the regular refresh mechanic.
|
// can fall back on the regular refresh mechanic.
|
||||||
if constexpr (is_yamaha_vdp(personality)) {
|
if constexpr (is_yamaha_vdp(personality)) {
|
||||||
@ -425,7 +427,7 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
|||||||
|
|
||||||
#define border(left, right) intersect(left, right, this->output_border(end - start, cram_value))
|
#define border(left, right) intersect(left, right, this->output_border(end - start, cram_value))
|
||||||
|
|
||||||
if(line_buffer.is_refresh) {
|
if(line_buffer.vertical_state != VerticalState::Pixels) {
|
||||||
if(
|
if(
|
||||||
this->output_pointer_.row >= this->mode_timing_.first_vsync_line &&
|
this->output_pointer_.row >= this->mode_timing_.first_vsync_line &&
|
||||||
this->output_pointer_.row < this->mode_timing_.first_vsync_line + 4
|
this->output_pointer_.row < this->mode_timing_.first_vsync_line + 4
|
||||||
@ -1036,7 +1038,7 @@ uint8_t Base<personality>::read_register() {
|
|||||||
|
|
||||||
return
|
return
|
||||||
transfer_ready |
|
transfer_ready |
|
||||||
(is_vertical_blank() ? 0x40 : 0x00) |
|
(vertical_state() != VerticalState::Pixels ? 0x40 : 0x00) |
|
||||||
(is_horizontal_blank() ? 0x20 : 0x00) |
|
(is_horizontal_blank() ? 0x20 : 0x00) |
|
||||||
(Storage<personality>::command_ ? 0x01 : 0x00);
|
(Storage<personality>::command_ ? 0x01 : 0x00);
|
||||||
|
|
||||||
@ -1099,8 +1101,11 @@ int Base<personality>::fetch_line() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <Personality personality>
|
template <Personality personality>
|
||||||
bool Base<personality>::is_vertical_blank() const {
|
VerticalState Base<personality>::vertical_state() const {
|
||||||
return fetch_pointer_.row >= mode_timing_.pixel_lines && fetch_pointer_.row != mode_timing_.total_lines - 1;
|
// TODO: the Yamaha uses an internal flag for visible region which toggles at contextually-appropriate moments.
|
||||||
|
// This test won't work properly there.
|
||||||
|
if(fetch_pointer_.row == mode_timing_.total_lines - 1) return VerticalState::Prefetch;
|
||||||
|
return fetch_pointer_.row >= mode_timing_.pixel_lines ? VerticalState::Blank : VerticalState::Pixels;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <Personality personality>
|
template <Personality personality>
|
||||||
|
@ -29,6 +29,16 @@
|
|||||||
namespace TI {
|
namespace TI {
|
||||||
namespace TMS {
|
namespace TMS {
|
||||||
|
|
||||||
|
enum class VerticalState {
|
||||||
|
/// Describes any line on which pixels do not appear and no fetching occurs, including
|
||||||
|
/// the border, blanking and sync.
|
||||||
|
Blank,
|
||||||
|
/// A line on which pixels do not appear but fetching occurs.
|
||||||
|
Prefetch,
|
||||||
|
/// A line on which pixels appear and fetching occurs.
|
||||||
|
Pixels,
|
||||||
|
};
|
||||||
|
|
||||||
// Temporary buffers collect a representation of each line prior to pixel serialisation.
|
// Temporary buffers collect a representation of each line prior to pixel serialisation.
|
||||||
//
|
//
|
||||||
// TODO: either template on personality, to avoid having to be the union of all potential footprints,
|
// TODO: either template on personality, to avoid having to be the union of all potential footprints,
|
||||||
@ -40,7 +50,7 @@ struct LineBuffer {
|
|||||||
// screen mode captures proper output mode.
|
// screen mode captures proper output mode.
|
||||||
FetchMode fetch_mode = FetchMode::Text;
|
FetchMode fetch_mode = FetchMode::Text;
|
||||||
ScreenMode screen_mode = ScreenMode::Text;
|
ScreenMode screen_mode = ScreenMode::Text;
|
||||||
bool is_refresh = false;
|
VerticalState vertical_state = VerticalState::Blank;
|
||||||
|
|
||||||
// Holds the horizontal scroll position to apply to this line;
|
// Holds the horizontal scroll position to apply to this line;
|
||||||
// of those VDPs currently implemented, affects the Master System only.
|
// of those VDPs currently implemented, affects the Master System only.
|
||||||
@ -545,8 +555,8 @@ template <Personality personality> struct Base: public Storage<personality> {
|
|||||||
LineBufferPointer output_pointer_, fetch_pointer_;
|
LineBufferPointer output_pointer_, fetch_pointer_;
|
||||||
|
|
||||||
int fetch_line() const;
|
int fetch_line() const;
|
||||||
bool is_vertical_blank() const;
|
|
||||||
bool is_horizontal_blank() const;
|
bool is_horizontal_blank() const;
|
||||||
|
VerticalState vertical_state() const;
|
||||||
|
|
||||||
int masked_address(int address) const;
|
int masked_address(int address) const;
|
||||||
void write_vram(uint8_t);
|
void write_vram(uint8_t);
|
||||||
|
@ -42,7 +42,7 @@ enum class ScreenMode {
|
|||||||
constexpr int pixels_per_byte(ScreenMode mode) {
|
constexpr int pixels_per_byte(ScreenMode mode) {
|
||||||
switch(mode) {
|
switch(mode) {
|
||||||
default:
|
default:
|
||||||
case ScreenMode::Blank: return 0;
|
case ScreenMode::Blank: return 1;
|
||||||
case ScreenMode::Text: return 6;
|
case ScreenMode::Text: return 6;
|
||||||
case ScreenMode::MultiColour: return 2;
|
case ScreenMode::MultiColour: return 2;
|
||||||
case ScreenMode::ColouredText: return 8;
|
case ScreenMode::ColouredText: return 8;
|
||||||
|
@ -22,7 +22,7 @@ struct Vector {
|
|||||||
template <int offset, bool high> void set(uint8_t value) {
|
template <int offset, bool high> void set(uint8_t value) {
|
||||||
constexpr uint8_t mask = high ? (offset ? 0x3 : 0x1) : 0xff;
|
constexpr uint8_t mask = high ? (offset ? 0x3 : 0x1) : 0xff;
|
||||||
constexpr int shift = high ? 8 : 0;
|
constexpr int shift = high ? 8 : 0;
|
||||||
v[offset] = (v[offset] & ~(mask << shift)) | (value << shift);
|
v[offset] = (v[offset] & ~(mask << shift)) | ((value & mask) << shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <int offset> void add(int amount) {
|
template <int offset> void add(int amount) {
|
||||||
@ -258,17 +258,16 @@ struct HighSpeedFill: public Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool done() final {
|
bool done() final {
|
||||||
return true;
|
return !context.size.v[1] || !width_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void advance(int pixels_per_byte) final {
|
void advance(int pixels_per_byte) final {
|
||||||
cycles = 48;
|
cycles = 48;
|
||||||
|
|
||||||
// TODO: step at byte speed, not pixel speed.
|
|
||||||
advance_axis<0>(pixels_per_byte);
|
advance_axis<0>(pixels_per_byte);
|
||||||
--context.size.v[0];
|
context.size.v[0] -= pixels_per_byte;
|
||||||
|
|
||||||
if(!context.size.v[0]) {
|
if(!(context.size.v[0] & ~(pixels_per_byte - 1))) {
|
||||||
cycles += 56;
|
cycles += 56;
|
||||||
context.size.v[0] = width_;
|
context.size.v[0] = width_;
|
||||||
context.destination.v[0] = start_x_;
|
context.destination.v[0] = start_x_;
|
||||||
|
Loading…
Reference in New Issue
Block a user