mirror of
https://github.com/TomHarte/CLK.git
synced 2025-04-09 15:39:08 +00:00
Begin commutation of interrupts.
This commit is contained in:
parent
1797bab28f
commit
e2dcb0a8e2
@ -30,34 +30,6 @@ Base<personality>::Base() :
|
||||
// Unimaginatively, this class just passes RGB through to the shader. Investigation is needed
|
||||
// into whether there's a more natural form. It feels unlikely given the diversity of chips modelled.
|
||||
|
||||
// TODO: values in mode_timing_ should be relative to the ModeLatch since the fetch pointer is used pervasively
|
||||
// as the authoritative current position. But also it's not clear to me that my current approach of treating them
|
||||
// as runtime constant is really working. Some more thought required.
|
||||
|
||||
if constexpr (is_sega_vdp(personality)) {
|
||||
// Cf. https://www.smspower.org/forums/8161-SMSDisplayTiming
|
||||
|
||||
// "For a line interrupt, /INT is pulled low 608 mclks into the appropriate scanline relative to pixel 0.
|
||||
// This is 3 mclks before the rising edge of /HSYNC which starts the next scanline."
|
||||
//
|
||||
// i.e. it's 304 internal clocks after the end of the left border.
|
||||
mode_timing_.line_interrupt_position = (LineLayout<personality>::EndOfLeftBorder + 304) % LineLayout<personality>::CyclesPerLine;
|
||||
|
||||
// For a frame interrupt, /INT is pulled low 607 mclks into scanline 192 (of scanlines 0 through 261) relative to pixel 0.
|
||||
// This is 4 mclks before the rising edge of /HSYNC which starts the next scanline.
|
||||
//
|
||||
// i.e. it's 1/2 cycle before the line interrupt position, which I have rounded. Ugh.
|
||||
mode_timing_.end_of_frame_interrupt_position.column = mode_timing_.line_interrupt_position - 1;
|
||||
mode_timing_.end_of_frame_interrupt_position.row = 192 + (LineLayout<personality>::EndOfLeftBorder + 304) / LineLayout<personality>::CyclesPerLine;
|
||||
}
|
||||
|
||||
if constexpr (is_yamaha_vdp(personality)) {
|
||||
// TODO: this is used for interrupt _prediction_ but won't handle text modes correctly, and indeed
|
||||
// can't be just a single value where the programmer has changed into or out of text modes during the
|
||||
// middle of a line, since screen mode is latched (so it'll be one value for that line, another from then onwards).
|
||||
mode_timing_.line_interrupt_position = LineLayout<personality>::EndOfPixels;
|
||||
}
|
||||
|
||||
// Establish that output is delayed after reading by `output_lag` cycles,
|
||||
// i.e. the fetch pointer is currently _ahead_ of the output pointer.
|
||||
output_pointer_.row = output_pointer_.column = 0;
|
||||
@ -303,13 +275,15 @@ void TMS9918<personality>::run_for(const HalfCycles cycles) {
|
||||
// -------------------------------
|
||||
// Check for interrupt conditions.
|
||||
// -------------------------------
|
||||
if constexpr (is_sega_vdp(personality)) {
|
||||
if constexpr (LineLayout<personality>::HasFixedLineInterrupt) {
|
||||
// The Sega VDP offers a decrementing counter for triggering line interrupts;
|
||||
// it is reloaded either when it overflows or upon every non-pixel line after the first.
|
||||
// It is otherwise decremented.
|
||||
|
||||
constexpr int FixedLineInterrupt = to_internal<personality, Origin::ModeLatch>(LineLayout<personality>::FixedLineInterrupt);
|
||||
if(
|
||||
this->fetch_pointer_.column < this->mode_timing_.line_interrupt_position &&
|
||||
end_column >= this->mode_timing_.line_interrupt_position
|
||||
this->fetch_pointer_.column < FixedLineInterrupt &&
|
||||
end_column >= FixedLineInterrupt
|
||||
) {
|
||||
if(this->fetch_pointer_.row >= 0 && this->fetch_pointer_.row <= this->mode_timing_.pixel_lines) {
|
||||
if(!this->line_interrupt_counter_) {
|
||||
|
@ -170,16 +170,6 @@ template <Personality personality> struct Base: public Storage<personality> {
|
||||
// then the appropriate status information will be set.
|
||||
int maximum_visible_sprites = 4;
|
||||
|
||||
// Set the position, in cycles, of the two interrupts,
|
||||
// within a line.
|
||||
//
|
||||
// TODO: redetermine where this number came from.
|
||||
struct {
|
||||
int column = 313;
|
||||
int row = 192;
|
||||
} end_of_frame_interrupt_position;
|
||||
int line_interrupt_position = -1;
|
||||
|
||||
// Enables or disabled the recognition of the sprite
|
||||
// list terminator, and sets the terminator value.
|
||||
bool allow_sprite_terminator = true;
|
||||
|
@ -32,7 +32,7 @@ template <Personality personality, typename Enable = void> struct LineLayout;
|
||||
// ModeLaytchCycle is the cycle at which the video mode, blank disable/enable and
|
||||
// sprite enable/disable are latched for the line.
|
||||
|
||||
template <Personality personality> struct LineLayout<personality, std::enable_if_t<is_classic_vdp(personality)>> {
|
||||
template <Personality personality> struct LineLayout<personality, std::enable_if_t<is_classic_vdp(personality) && !is_sega_vdp(personality)>> {
|
||||
constexpr static int StartOfSync = 0;
|
||||
constexpr static int EndOfSync = 26;
|
||||
constexpr static int StartOfColourBurst = 29;
|
||||
@ -51,11 +51,34 @@ template <Personality personality> struct LineLayout<personality, std::enable_if
|
||||
// and falls into the collection gap between the final sprite
|
||||
// graphics and the initial tiles or pixels.
|
||||
|
||||
constexpr static bool HasDynamicLineInterrupt = false;
|
||||
constexpr static bool HasFixedLineInterrupt = false;
|
||||
constexpr static int EndOfFrameInterrupt = 313;
|
||||
|
||||
/// The number of internal cycles that must elapse between a request to read or write and
|
||||
/// it becoming a candidate for action.
|
||||
constexpr static int VRAMAccessDelay = 6;
|
||||
};
|
||||
|
||||
template <Personality personality> struct LineLayout<personality, std::enable_if_t<is_sega_vdp(personality)>> :
|
||||
public LineLayout<Personality::TMS9918A> {
|
||||
|
||||
// Cf. https://www.smspower.org/forums/8161-SMSDisplayTiming
|
||||
|
||||
// "For a line interrupt, /INT is pulled low 608 mclks into the appropriate scanline relative to pixel 0.
|
||||
// This is 3 mclks before the rising edge of /HSYNC which starts the next scanline."
|
||||
//
|
||||
// i.e. it's 304 internal clocks after the end of the left border.
|
||||
constexpr static bool HasFixedLineInterrupt = false;
|
||||
constexpr static int FixedLineInterrupt = (EndOfLeftBorder + 304) % CyclesPerLine;
|
||||
|
||||
// For a frame interrupt, /INT is pulled low 607 mclks into scanline 192 (of scanlines 0 through 261) relative to pixel 0.
|
||||
// This is 4 mclks before the rising edge of /HSYNC which starts the next scanline.
|
||||
//
|
||||
// i.e. it's 1/2 cycle before the line interrupt position, which I have rounded. Ugh.
|
||||
constexpr static int EndOfFrameInterrupt = 313;
|
||||
};
|
||||
|
||||
template <Personality personality> struct LineLayout<personality, std::enable_if_t<is_yamaha_vdp(personality)>> {
|
||||
constexpr static int StartOfSync = 0;
|
||||
constexpr static int EndOfSync = 100;
|
||||
@ -73,6 +96,10 @@ template <Personality personality> struct LineLayout<personality, std::enable_if
|
||||
|
||||
constexpr static int ModeLatchCycle = 144;
|
||||
|
||||
constexpr static bool HasDynamicLineInterrupt = true;
|
||||
constexpr static bool HasFixedLineInterrupt = false;
|
||||
constexpr static int EndOfFrameInterrupt = 313;
|
||||
|
||||
/// The number of internal cycles that must elapse between a request to read or write and
|
||||
/// it becoming a candidate for action.
|
||||
constexpr static int VRAMAccessDelay = 16;
|
||||
|
Loading…
x
Reference in New Issue
Block a user