diff --git a/Machines/AppleII/AppleII.cpp b/Machines/AppleII/AppleII.cpp index cbe588e5a..e07d65a57 100644 --- a/Machines/AppleII/AppleII.cpp +++ b/Machines/AppleII/AppleII.cpp @@ -47,23 +47,58 @@ class ConcreteMachine: return nullptr; } - void run_for(const Cycles cycles) override { - m6502_.run_for(cycles); + Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { + ++ cycles_since_video_update_; + + switch(address) { + default: + if(isReadOperation(operation)) { + if(address < sizeof(ram_)) { + *value = ram_[address]; + } else if(address >= rom_start_address_) { + *value = rom_[address - rom_start_address_]; + } else { + switch(address) { + default: *value = 0xff; break; + case 0xc000: + // TODO: read keyboard. + *value = 0; + break; + } + } + } else { + if(address < sizeof(ram_)) { + update_video(); // TODO: be more selective. + ram_[address] = *value; + } + } + break; + + case 0xc050: update_video(); video_->set_graphics_mode(); break; + case 0xc051: update_video(); video_->set_text_mode(); break; + case 0xc052: update_video(); video_->set_mixed_mode(false); break; + case 0xc053: update_video(); video_->set_mixed_mode(true); break; + case 0xc054: update_video(); video_->set_video_page(0); break; + case 0xc055: update_video(); video_->set_video_page(1); break; + case 0xc056: update_video(); video_->set_low_resolution(); break; + case 0xc057: update_video(); video_->set_high_resolution(); break; + } + + // The Apple II has a slightly weird timing pattern: every 65th CPU cycle is stretched + // by an extra 1/7th. That's because one cycle lasts 3.5 NTSC colour clocks, so after + // 65 cycles a full line of 227.5 colour clocks have passed. But the high-rate binary + // signal approximation that produces colour needs to be in phase, so a stretch of exactly + // 0.5 further colour cycles is added. + cycles_into_current_line_ = (cycles_into_current_line_ + 1) % 65; + if(!cycles_into_current_line_) { + // Do something. Do something else. + } + + return Cycles(1); } - Cycles perform_bus_operation(CPU::MOS6502::BusOperation operation, uint16_t address, uint8_t *value) { - if(isReadOperation(operation)) { - if(address < sizeof(ram_)) { - *value = ram_[address]; - } else if(address >= rom_start_address_) { - *value = rom_[address - rom_start_address_]; - } - } else { - if(address < sizeof(ram_)) { - ram_[address] = *value; - } - } - return Cycles(1); + void flush() { + update_video(); } bool set_rom_fetcher(const std::function>>(const std::string &machine, const std::vector &names)> &roms_with_names) override { @@ -80,9 +115,19 @@ class ConcreteMachine: return true; } + void run_for(const Cycles cycles) override { + m6502_.run_for(cycles); + } + private: CPU::MOS6502::Processor m6502_; std::unique_ptr video_; + int cycles_into_current_line_ = 0; + Cycles cycles_since_video_update_; + + void update_video() { + video_->run_for(cycles_since_video_update_.flush()); + } uint8_t ram_[48*1024]; std::vector rom_; diff --git a/Machines/AppleII/Video.cpp b/Machines/AppleII/Video.cpp index ffa0cc42d..45418760a 100644 --- a/Machines/AppleII/Video.cpp +++ b/Machines/AppleII/Video.cpp @@ -11,7 +11,7 @@ using namespace AppleII; Video::Video() : - crt_(new Outputs::CRT::CRT(65, 1, Outputs::CRT::DisplayType::NTSC60, 1)) { + crt_(new Outputs::CRT::CRT(455, 1, Outputs::CRT::DisplayType::NTSC60, 1)) { // Set a composite sampling function that assumes 1bpp input, and uses just 7 bits per byte. crt_->set_composite_sampling_function( @@ -30,3 +30,30 @@ Video::Video() : Outputs::CRT::CRT *Video::get_crt() { return crt_.get(); } + +void Video::run_for(const Cycles) { +} + +void Video::set_graphics_mode() { + printf("Graphics mode\n"); +} + +void Video::set_text_mode() { + printf("Text mode\n"); +} + +void Video::set_mixed_mode(bool mixed_mode) { + printf("Mixed mode: %s\n", mixed_mode ? "true" : "false"); +} + +void Video::set_video_page(int page) { + printf("Video page: %d\n", page); +} + +void Video::set_low_resolution() { + printf("Low resolution\n"); +} + +void Video::set_high_resolution() { + printf("High resolution\n"); +} diff --git a/Machines/AppleII/Video.hpp b/Machines/AppleII/Video.hpp index 2fd74e8b0..2a24b8769 100644 --- a/Machines/AppleII/Video.hpp +++ b/Machines/AppleII/Video.hpp @@ -21,6 +21,21 @@ class Video { /// @returns The CRT this video feed is feeding. Outputs::CRT::CRT *get_crt(); + /*! + Advances time by @c cycles; expects to be fed by the CPU clock. + Implicitly adds an extra half a colour clock at the end of every + line. + */ + void run_for(const Cycles); + + // Inputs for the various soft switches. + void set_graphics_mode(); + void set_text_mode(); + void set_mixed_mode(bool); + void set_video_page(int); + void set_low_resolution(); + void set_high_resolution(); + private: std::unique_ptr crt_; };