mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-11 08:30:55 +00:00
Starts taking steps towards SMS/GG and V9938/9958 support.
Specifically: routine namespace stuff, plus the intention to move to a table-based operation+cost version of timing. Reordering works fine for the TMS, and probably would also for the SMS/GG, but it'd be problematic with the command engine of the V9938/9958 and maintaining a consistent set of code is easier.
This commit is contained in:
parent
a29a8e292b
commit
e7f4babf41
@ -11,7 +11,7 @@
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
using namespace TI;
|
||||
using namespace TI::TMS;
|
||||
|
||||
namespace {
|
||||
|
||||
@ -83,12 +83,28 @@ enum ScreenMode {
|
||||
|
||||
}
|
||||
|
||||
TMS9918Base::TMS9918Base() :
|
||||
Base::Base(Personality p) :
|
||||
// 342 internal cycles are 228/227.5ths of a line, so 341.25 cycles should be a whole
|
||||
// line. Therefore multiply everything by four, but set line length to 1365 rather than 342*4 = 1368.
|
||||
crt_(new Outputs::CRT::CRT(1365, 4, Outputs::CRT::DisplayType::NTSC60, 4)) {}
|
||||
crt_(new Outputs::CRT::CRT(1365, 4, Outputs::CRT::DisplayType::NTSC60, 4)) {
|
||||
|
||||
TMS9918::TMS9918(Personality p) {
|
||||
switch(p) {
|
||||
case TI::TMS::TMS9918A:
|
||||
case TI::TMS::SMSVDP:
|
||||
case TI::TMS::GGVDP:
|
||||
ram_.resize(16 * 1024);
|
||||
break;
|
||||
case TI::TMS::V9938:
|
||||
ram_.resize(128 * 1024);
|
||||
break;
|
||||
case TI::TMS::V9958:
|
||||
ram_.resize(192 * 1024);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
TMS9918::TMS9918(Personality p):
|
||||
Base(p) {
|
||||
// Unimaginatively, this class just passes RGB through to the shader. Investigation is needed
|
||||
// into whether there's a more natural form.
|
||||
crt_->set_rgb_sampling_function(
|
||||
@ -111,7 +127,7 @@ Outputs::CRT::CRT *TMS9918::get_crt() {
|
||||
return crt_.get();
|
||||
}
|
||||
|
||||
void TMS9918Base::test_sprite(int sprite_number, int screen_row) {
|
||||
void Base::test_sprite(int sprite_number, int screen_row) {
|
||||
if(!(status_ & StatusFifthSprite)) {
|
||||
status_ = static_cast<uint8_t>((status_ & ~31) | sprite_number);
|
||||
}
|
||||
@ -140,7 +156,7 @@ void TMS9918Base::test_sprite(int sprite_number, int screen_row) {
|
||||
sprite_sets_[active_sprite_set_].active_sprite_slot++;
|
||||
}
|
||||
|
||||
void TMS9918Base::get_sprite_contents(int field, int cycles_left, int screen_row) {
|
||||
void Base::get_sprite_contents(int field, int cycles_left, int screen_row) {
|
||||
int sprite_id = field / 6;
|
||||
field %= 6;
|
||||
|
||||
@ -617,7 +633,7 @@ void TMS9918::run_for(const HalfCycles cycles) {
|
||||
}
|
||||
}
|
||||
|
||||
void TMS9918Base::output_border(int cycles) {
|
||||
void Base::output_border(int cycles) {
|
||||
pixel_target_ = reinterpret_cast<uint32_t *>(crt_->allocate_write_area(1));
|
||||
if(pixel_target_) *pixel_target_ = palette[background_colour_];
|
||||
crt_->output_level(static_cast<unsigned int>(cycles) * 4);
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include <cstdint>
|
||||
|
||||
namespace TI {
|
||||
namespace TMS {
|
||||
|
||||
/*!
|
||||
Provides emulation of the TMS9918a, TMS9928 and TMS9929. Likely in the future to be the
|
||||
@ -29,12 +30,8 @@ namespace TI {
|
||||
These chips have only one non-on-demand interaction with the outside world: an interrupt line.
|
||||
See get_time_until_interrupt and get_interrupt_line for asynchronous operation options.
|
||||
*/
|
||||
class TMS9918: public TMS9918Base {
|
||||
class TMS9918: public Base {
|
||||
public:
|
||||
enum Personality {
|
||||
TMS9918A, // includes the 9928 and 9929; set TV standard and output device as desired.
|
||||
};
|
||||
|
||||
/*!
|
||||
Constructs an instance of the drive controller that behaves according to personality @c p.
|
||||
@param p The type of controller to emulate.
|
||||
@ -81,6 +78,7 @@ class TMS9918: public TMS9918Base {
|
||||
bool get_interrupt_line();
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* TMS9918_hpp */
|
||||
|
@ -16,14 +16,23 @@
|
||||
#include <memory>
|
||||
|
||||
namespace TI {
|
||||
namespace TMS {
|
||||
|
||||
class TMS9918Base {
|
||||
enum Personality {
|
||||
TMS9918A, // includes the 9928 and 9929; set TV standard and output device as desired.
|
||||
V9938,
|
||||
V9958,
|
||||
SMSVDP,
|
||||
GGVDP,
|
||||
};
|
||||
|
||||
class Base {
|
||||
protected:
|
||||
TMS9918Base();
|
||||
Base(Personality p);
|
||||
|
||||
std::unique_ptr<Outputs::CRT::CRT> crt_;
|
||||
|
||||
uint8_t ram_[16384];
|
||||
std::vector<uint8_t> ram_;
|
||||
|
||||
uint16_t ram_pointer_ = 0;
|
||||
uint8_t read_ahead_buffer_ = 0;
|
||||
@ -94,8 +103,115 @@ class TMS9918Base {
|
||||
|
||||
inline void test_sprite(int sprite_number, int screen_row);
|
||||
inline void get_sprite_contents(int start, int cycles, int screen_row);
|
||||
|
||||
// Contains tables describing the memory access patterns and, implicitly,
|
||||
// the timing of video generation.
|
||||
enum Operation {
|
||||
HSyncOn,
|
||||
HSyncOff,
|
||||
ColourBurstOn,
|
||||
ColourBurstOff,
|
||||
|
||||
/// A memory access slot that is available for an external read or write.
|
||||
External,
|
||||
|
||||
/// A refresh cycle; neither used for video fetching nor available for external use.
|
||||
Refresh,
|
||||
|
||||
/*!
|
||||
Column N Name Table Read
|
||||
[= 1 slot]
|
||||
*/
|
||||
NameTableRead,
|
||||
|
||||
/*!
|
||||
Column N Pattern Table Read
|
||||
[= 1 slot]
|
||||
*/
|
||||
PatternTableRead,
|
||||
|
||||
/*!
|
||||
Y0, X0, N0, C0, Pattern 0 (1), Pattern 0 (2),
|
||||
Y1, X1, N1, C1, Pattern 1 (1), Pattern 1 (2),
|
||||
Y2, X2
|
||||
[= 14 slots]
|
||||
*/
|
||||
TMSSpriteFetch1,
|
||||
|
||||
/*!
|
||||
N2, C2, Pattern 2 (1), Pattern 2 (2),
|
||||
Y3, X3, N3, C3, Pattern 3 (1), Pattern 3 (2),
|
||||
[= 10 slots]
|
||||
*/
|
||||
TMSSpriteFetch2,
|
||||
|
||||
/*!
|
||||
Sprite N fetch, Sprite N+1 fetch [...]
|
||||
*/
|
||||
TMSSpriteYFetch,
|
||||
|
||||
/*!
|
||||
Colour N, Pattern N,
|
||||
Name N+1,
|
||||
Sprite N,
|
||||
|
||||
Colour N+1, Pattern N+1,
|
||||
Name N+2,
|
||||
Sprite N+1,
|
||||
|
||||
Colour N+2, Pattern N+2,
|
||||
Name N+3,
|
||||
Sprite N+2,
|
||||
|
||||
Colour N+3, Pattern N+3,
|
||||
Name N+4,
|
||||
[= 15 slots]
|
||||
*/
|
||||
TMSBackgroundRenderBlock,
|
||||
|
||||
/*!
|
||||
Pattern N,
|
||||
Name N+1
|
||||
*/
|
||||
TMSPatternNameFetch,
|
||||
|
||||
/*!
|
||||
Sprite N X/Name Read
|
||||
Sprite N+1 X/Name Read
|
||||
Sprite N Tile read (1st word)
|
||||
Sprite N Tile read (2nd word)
|
||||
Sprite N+1 Tile Read (1st word)
|
||||
Sprite N+1 Tile Read (2nd word)
|
||||
[= 6 slots]
|
||||
*/
|
||||
SMSSpriteRenderBlock,
|
||||
|
||||
/*!
|
||||
Column N Tile Read (1st word)
|
||||
Column N Tile Read (2nd word)
|
||||
Column N+1 Name Table Read
|
||||
Sprite (16+N*1.5) Y Read (Reads Y of 2 sprites)
|
||||
Column N+1 Tile Read (1st word)
|
||||
Column N+1 Tile Read (2nd word)
|
||||
Column N+2 Name Table Read
|
||||
Sprite (16+N*1.5+2) Y Read (Reads Y of 2 sprites)
|
||||
Column N+2 Tile Read (1st word)
|
||||
Column N+2 Tile Read (2nd word)
|
||||
Column N+3 Name Table Read
|
||||
Sprite (16+N*1.5+4) Y Read (Reads Y of 2 sprites)
|
||||
Column N+3 Tile Read (1st word)
|
||||
Column N+3 Tile Read (2nd word)
|
||||
[= 14 slots]
|
||||
*/
|
||||
SMSBackgroundRenderBlock,
|
||||
};
|
||||
struct Period {
|
||||
Operation operation;
|
||||
int duration;
|
||||
};
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* TMS9918Base_hpp */
|
||||
|
@ -161,7 +161,7 @@ class ConcreteMachine:
|
||||
}
|
||||
|
||||
void setup_output(float aspect_ratio) override {
|
||||
vdp_.reset(new TI::TMS9918(TI::TMS9918::TMS9918A));
|
||||
vdp_.reset(new TI::TMS::TMS9918(TI::TMS::TMS9918A));
|
||||
get_crt()->set_video_signal(Outputs::CRT::VideoSignal::Composite);
|
||||
}
|
||||
|
||||
@ -358,7 +358,7 @@ class ConcreteMachine:
|
||||
}
|
||||
|
||||
CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
|
||||
std::unique_ptr<TI::TMS9918> vdp_;
|
||||
std::unique_ptr<TI::TMS::TMS9918> vdp_;
|
||||
|
||||
Concurrency::DeferringAsyncTaskQueue audio_queue_;
|
||||
TI::SN76489 sn76489_;
|
||||
|
@ -219,7 +219,7 @@ class ConcreteMachine:
|
||||
}
|
||||
|
||||
void setup_output(float aspect_ratio) override {
|
||||
vdp_.reset(new TI::TMS9918(TI::TMS9918::TMS9918A));
|
||||
vdp_.reset(new TI::TMS::TMS9918(TI::TMS::TMS9918A));
|
||||
}
|
||||
|
||||
void close_output() override {
|
||||
@ -683,7 +683,7 @@ class ConcreteMachine:
|
||||
};
|
||||
|
||||
CPU::Z80::Processor<ConcreteMachine, false, false> z80_;
|
||||
std::unique_ptr<TI::TMS9918> vdp_;
|
||||
std::unique_ptr<TI::TMS::TMS9918> vdp_;
|
||||
Intel::i8255::i8255<i8255PortHandler> i8255_;
|
||||
|
||||
Concurrency::DeferringAsyncTaskQueue audio_queue_;
|
||||
|
Loading…
x
Reference in New Issue
Block a user