From 9bc470027e5cb1ea0750b02212328f214ba195b5 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 15 Apr 2018 19:35:08 -0400 Subject: [PATCH] Put enough in place to get a visual representation of video memory. Not the correct one, and so as to indicate that the machine isn't booting, surprisingly. --- Machines/AppleII/AppleII.cpp | 56 ++++++++----- Machines/AppleII/Video.cpp | 152 ++++++----------------------------- ROMImages/AppleII/readme.txt | 6 ++ 3 files changed, 67 insertions(+), 147 deletions(-) create mode 100644 ROMImages/AppleII/readme.txt diff --git a/Machines/AppleII/AppleII.cpp b/Machines/AppleII/AppleII.cpp index e07d65a57..0e452c3a4 100644 --- a/Machines/AppleII/AppleII.cpp +++ b/Machines/AppleII/AppleII.cpp @@ -23,16 +23,45 @@ class ConcreteMachine: public CRTMachine::Machine, public CPU::MOS6502::BusHandler, public AppleII::Machine { - public: + private: + struct VideoBusHandler : public AppleII::Video::BusHandler { + public: + VideoBusHandler(uint8_t *ram) : ram_(ram) {} + uint8_t perform_read(uint16_t address) { + return ram_[address]; + } + + private: + uint8_t *ram_; + }; + + CPU::MOS6502::Processor m6502_; + VideoBusHandler video_bus_handler_; + 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_; + std::vector character_rom_; + uint16_t rom_start_address_; + + public: ConcreteMachine(): - m6502_(*this) { + m6502_(*this), + video_bus_handler_(ram_) { set_clock_rate(1022727); Memory::Fuzz(ram_, sizeof(ram_)); } void setup_output(float aspect_ratio) override { - video_.reset(new AppleII::Video); + video_.reset(new AppleII::Video::Video(video_bus_handler_)); + video_->set_character_rom(character_rom_); } void close_output() override { @@ -105,33 +134,22 @@ class ConcreteMachine: auto roms = roms_with_names( "AppleII", { - "apple2o.rom" + "apple2o.rom", + "apple2o-character.rom" }); - if(!roms[0]) return false; + if(!roms[0] || !roms[1]) return false; rom_ = std::move(*roms[0]); rom_start_address_ = static_cast(0x10000 - rom_.size()); + character_rom_ = std::move(*roms[1]); + 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_; - uint16_t rom_start_address_; }; } diff --git a/Machines/AppleII/Video.cpp b/Machines/AppleII/Video.cpp index 857edb03b..1753f8ff2 100644 --- a/Machines/AppleII/Video.cpp +++ b/Machines/AppleII/Video.cpp @@ -8,132 +8,28 @@ #include "Video.hpp" -using namespace AppleII; +using namespace AppleII::Video; -Video::Video() : - 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( - "float composite_sample(usampler2D sampler, vec2 coordinate, vec2 icoordinate, float phase, float amplitude)" - "{" - "uint texValue = texture(sampler, coordinate).r;" - "texValue <<= int(icoordinate.x * 8) & 7;" - "return float(texValue & 128u);" -// "uint texValue = texture(sampler, coordinate).r;" -// "texValue <<= uint(icoordinate.x * 7.0) % 7u;" -// "return float(texValue & 128u);" - "}"); - - // Show only the centre 75% of the TV frame. - crt_->set_video_signal(Outputs::CRT::VideoSignal::Composite); - crt_->set_visible_area(Outputs::CRT::Rect(0.115f, 0.115f, 0.77f, 0.77f)); -} - -Outputs::CRT::CRT *Video::get_crt() { - return crt_.get(); -} - -void Video::run_for(const Cycles cycles) { - /* - Addressing scheme used throughout is that column 0 is the first column with pixels in it; - row 0 is the first row with pixels in it. - - A frame is oriented around 65 cycles across, 262 lines down. - */ - const int first_sync_line = 220; // A complete guess. Information needed. - const int first_sync_column = 49; // Also a guess. - - int int_cycles = cycles.as_int(); - while(int_cycles) { - const int cycles_this_line = std::min(65 - column_, int_cycles); - - if(row_ >= first_sync_line && row_ < first_sync_line + 3) { - crt_->output_sync(static_cast(cycles_this_line) * 7); - } else { - const int ending_column = column_ + cycles_this_line; - - // The first 40 columns are submitted to the CRT only upon completion; - // they'll be either graphics or blank, depending on which side we are - // of line 192. - if(column_ < 40) { - if(row_ < 192) { - if(!column_) { - pixel_pointer_ = crt_->allocate_write_area(40); - } - - // TODO: actually store pixels. - - if(ending_column >= 40) { - for(int c = 0; c < 40; ++c) { - pixel_pointer_[c] = static_cast((c * 6) ^ row_); - } - crt_->output_data(280, 7); - } - } else { - if(ending_column >= 40) { - crt_->output_blank(280); - } - } - } - - /* - The left border, sync, right border pattern doesn't depend on whether - there were pixels this row and is output as soon as it is known. - */ - - const int first_blank_start = std::max(40, column_); - const int first_blank_end = std::min(first_sync_column, ending_column); - if(first_blank_end > first_blank_start) { - crt_->output_blank(static_cast(first_blank_end - first_blank_start) * 7); - } - - // TODO: colour burst. - - const int sync_start = std::max(first_sync_column, column_); - const int sync_end = std::min(first_sync_column + 4, ending_column); - if(sync_end > sync_start) { - crt_->output_sync(static_cast(sync_end - sync_start) * 7); - } - - const int second_blank_start = std::max(first_sync_column + 4, column_); - if(ending_column > second_blank_start) { - crt_->output_blank(static_cast(ending_column - second_blank_start) * 7); - } - } - - int_cycles -= cycles_this_line; - column_ = (column_ + cycles_this_line) % 65; - if(!column_) { - row_ = (row_ + 1) % 262; - - // Add an extra half a colour cycle of blank; this isn't counted in the run_for - // count explicitly but is promised. - crt_->output_blank(1); - } - } -} - -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"); -} +//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/ROMImages/AppleII/readme.txt b/ROMImages/AppleII/readme.txt new file mode 100644 index 000000000..f930d3e49 --- /dev/null +++ b/ROMImages/AppleII/readme.txt @@ -0,0 +1,6 @@ +ROM files would ordinarily go here; they are copyright Apple so are not included. + +Expected files: + +apple2o.rom — a 12kb image of the original Apple II's ROMs. +apple2o-character.rom — a 2kb image of the original Apple II's character ROM. \ No newline at end of file