diff --git a/Machines/Commodore/Plus4/Plus4.cpp b/Machines/Commodore/Plus4/Plus4.cpp index a3c7cdc93..7aab42d1d 100644 --- a/Machines/Commodore/Plus4/Plus4.cpp +++ b/Machines/Commodore/Plus4/Plus4.cpp @@ -250,18 +250,15 @@ public: // Update other subsystems. advance_timers_and_tape(length); - if(!superspeed_) { - video_.run_for(length); + video_.run_for(length); - if(c1541_) { - c1541_cycles_ += length * Cycles(1'000'000); - c1541_->run_for(c1541_cycles_.divide(media_divider_)); - } - - - time_since_audio_update_ += length; + if(c1541_) { + c1541_cycles_ += length * Cycles(1'000'000); + c1541_->run_for(c1541_cycles_.divide(media_divider_)); } + time_since_audio_update_ += length; + if(operation == CPU::MOS6502Mk2::BusOperation::Ready) { return length; } @@ -299,100 +296,74 @@ public: serial_port_.set_output(Serial::Line::Attention, Serial::LineLevel(~output & 0x04)); } } else if(address < 0xfd00 || address >= 0xff40) { -// if( -// use_fast_tape_hack_ && -// operation == CPU::MOS6502Esque::BusOperation::ReadOpcode -// ) { -// superspeed_ |= address == 0xe5fd; -// superspeed_ &= (address != 0xe68b) && (address != 0xe68d); -// } - - static constexpr bool use_hle = true; - -// if( -// use_fast_tape_hack_ && -// operation == CPU::MOS6502Esque::BusOperation::ReadOpcode && -// address == 0xe5fd -// ) { -// printf("Pulse %d from %lld ", -// pulse_num_, -// tape_player_->serialiser()->offset() -// ); -// } - if constexpr (is_read(operation)) { + value = map_.read(address); + if( use_fast_tape_hack_ && operation == CPU::MOS6502Mk2::BusOperation::ReadOpcode && - ( - (use_hle && address == 0xe5fd) || - address == 0xe68b || - address == 0xe68d - ) + + address == 0xf0f0 // ldcass ) { - // ++pulse_num_; - if(use_hle) { - read_dipole(); + // Input: + // A: 0 = Load, 1-255 = Verify; + // X/Y = Load address (if secondary address = 0). + // Output: + // Carry: 0 = No errors, 1 = Error; + // A = KERNAL error code (if Carry = 1); + // X/Y = Address of last byte loaded/verified (if Carry = 0). + // Used registers: A, X, Y. Real address: $F49E. + + + auto registers = m6502_.registers(); +// static constexpr uint16_t tape_buffer = 0x0333; + + // TODO: check byte at 0xab for a potential filename length; if set then get + // filename... from somewhere? + + const uint8_t name_length = ram_[0xab]; + if(name_length) { + printf("Name: ??? [%d bytes]\n", name_length); } - // using Flag = CPU::MOS6502::Flag; - // using Register = CPU::MOS6502::Register; - // const auto flags = m6502_.value_of(Register::Flags); - // printf("to %lld: %c%c%c\n", - // tape_player_->serialiser()->offset(), - // flags & Flag::Sign ? 'n' : '-', - // flags & Flag::Overflow ? 'v' : '-', - // flags & Flag::Carry ? 'c' : '-' - // ); - value = 0x60; - } else { - value = map_.read(address); - } - } else { - map_.write(address) = value; - } - - - // TODO: rdbyte and ldsync is probably sufficient? - -// if(use_fast_tape_hack_ && operation == CPU::MOS6502Esque::BusOperation::ReadOpcode) { -// static constexpr uint16_t ldsync = 0; -// switch(address) { -// default: break; -// -// case ldsync: -// break; -// } -// -// if(address == 0xe9cc) { -// // Skip the `jsr rdblok` that opens `fah` (i.e. find any header), performing -// // its function as a high-level emulation. -// Storage::Tape::Commodore::Parser parser(TargetPlatform::Plus4); -// auto header = parser.get_next_header(*tape_player_->serialiser()); -// -// const auto tape_position = tape_player_->serialiser()->offset(); -// if(header) { -// // Copy to in-memory buffer and set type. + Storage::Tape::Commodore::Parser parser(TargetPlatform::Plus4); + const auto header = parser.get_next_header(*tape_player_->serialiser()); + if(header) { + // TODO: Copy header into place. // std::memcpy(&ram_[0x0333], header->data.data(), 191); // map_.write(0xb6) = 0x33; // map_.write(0xb7) = 0x03; // map_.write(0xf8) = header->type_descriptor(); -//// hold_tape_ = true; -// Logger::info().append("Found header"); -// } else { -// // no header found, so pretend this hack never interceded -// tape_player_->serialiser()->set_offset(tape_position); -//// hold_tape_ = false; -// Logger::info().append("Didn't find header"); -// } -// -// // Clear status and the verify flags. + + const auto body = parser.get_next_data(*tape_player_->serialiser()); + + if(body) { +// auto load_address = +// ram_[0xad] ? uint16_t((registers.y << 8) | registers.x) : header->starting_address; + auto load_address = + ram_[0xad] ? uint16_t((registers.y << 8) | registers.x) : header->starting_address; + + for(const auto byte: body->data) { + ram_[load_address] = byte; + ++load_address; + } + + --load_address; + registers.x = load_address & 0xff; + registers.y = load_address >> 8; + registers.flags.set_per(0); // C = 0 => success. + } + } + // ram_[0x90] = 0; // ram_[0x93] = 0; -// -// value = 0x0c; // NOP abs. -// } -// } + + m6502_.set_registers(registers); + value = 0x60; // i.e. RTS. + } + } else { + map_.write(address) = value; + } } else if(address < 0xff00) { // Miscellaneous hardware. All TODO. if constexpr (is_read(operation)) { @@ -621,7 +592,7 @@ public: } } - return superspeed_ ? Cycles(0) : length; + return length; } private: @@ -769,12 +740,11 @@ private: std::unique_ptr tape_player_; bool play_button_ = false; - bool allow_fast_tape_hack_ = false; // TODO: implement fast-tape hack. + bool allow_fast_tape_hack_ = false; bool use_fast_tape_hack_ = false; - bool superspeed_ = false; void set_use_fast_tape() { use_fast_tape_hack_ = - allow_fast_tape_hack_ && tape_player_->motor_control() && rom_is_paged_ && !tape_player_->is_at_end(); + allow_fast_tape_hack_ && rom_is_paged_ && !tape_player_->is_at_end(); } void update_tape_motor() { const auto output = io_output_ | ~io_direction_; @@ -788,352 +758,6 @@ private: tape_player_->run_for(length); } - // TODO: substantially simplify the below; at the minute it's a - // literal transcription of the original as a simple first step. - void read_dipole() { - using Flag = CPU::MOS6502Mk2::Flag; - - // - // Get registers now and ensure they'll be written back at function exit. - // - auto registers = m6502_.registers(); - struct ScopeGuard { - ScopeGuard(std::function at_exit) : at_exit_(at_exit) {} - ~ScopeGuard() { at_exit_(); } - private: - std::function at_exit_; - } store_registers([&] { - m6502_.set_registers(registers); - }); - - // - // Time advancement. - // - const auto advance_cycles = [&](int cycles) -> bool { - advance_timers_and_tape(video_.cycle_length(false) * cycles); - return !use_fast_tape_hack_; - }; - - // - // 6502 pseudo-ops. - // - const auto ldabs = [&] (uint8_t &target, const uint16_t address) { - registers.flags.set_per(target = map_.read(address)); - }; - const auto ldimm = [&] (uint8_t &target, const uint8_t value) { - registers.flags.set_per(target = value); - }; - const auto pha = [&] () { - map_.write(0x100 + registers.s) = registers.a; - --registers.s; - }; - const auto pla = [&] () { - ++registers.s; - registers.a = map_.read(0x100 + registers.s); - }; - const auto bit = [&] (const uint8_t value) { - registers.flags.set_per(registers.a & value); - registers.flags.set_per(value); - registers.flags.set_per(value); - }; - const auto cmp = [&] (const uint8_t value) { - const uint16_t temp16 = registers.a - value; - registers.flags.set_per(uint8_t(temp16)); - registers.flags.set_per(((~temp16) >> 8)&1); - }; - const auto andimm = [&] (const uint8_t value) { - registers.a &= value; - registers.flags.set_per(registers.a); - }; - const auto ne = [&]() -> bool { - return !registers.flags.get(); - }; - const auto eq = [&]() -> bool { - return registers.flags.get(); - }; - - // - // Common branch points. - // - const auto dipok = [&] { - // clc ; everything's fine - // rts - registers.flags.set_per(0); - }; - const auto rshort = [&] { - // bit tshrtd ; got a short - // bvs dipok ; !bra - bit(0x40); - dipok(); - }; - const auto rlong = [&] { - // bit tlongd ; got a long - bit(0x00); - dipok(); - }; - const auto rderr1 = [&] { - // sec ; i'm confused - // rts - registers.flags.set_per(Flag::Carry); - }; - - // - // Labels. - // - static constexpr uint16_t dsamp1 = 0x7b8; - static constexpr uint16_t dsamp2 = 0x7ba; - static constexpr uint16_t zcell = 0x07bc; - - //rddipl - // ldx dsamp1 ; setup x,y with 1st sample point - // ldy dsamp1+1 - ldabs(registers.x, dsamp1); - ldabs(registers.y, dsamp1 + 1); - advance_cycles(8); - - //badeg1 - do { - // lda dsamp2+1 ; put 2nd samp value on stack in reverse order - // pha - // lda dsamp2 - // pha - ldabs(registers.a, dsamp2 + 1); - pha(); - ldabs(registers.a, dsamp2); - pha(); - advance_cycles(14); - - // lda #$10 - //rwtl ; wait till rd line is high - // bit port [= $0001] - // beq rwtl ; !ls! - ldimm(registers.a, 0x10); - advance_cycles(2); - do { - bit(io_input()); - if(advance_cycles(6)) { - return; - } - } while(eq()); - - //rwth ;it's high...now wait till it's low - // bit port - // bne rwth ; caught the edge - do { - bit(io_input()); - if(advance_cycles(6)) { - return; - } - } while(ne()); - - - // stx timr2l - // sty timr2h - timers_.write<2>(registers.x); - timers_.write<3>(registers.y); - advance_cycles(8); - - - //; go! ...ta - // - // pla ;go! ...ta - // sta timr3l - // pla - // sta timr3h ;go! ...tb - pla(); - timers_.write<4>(registers.a); - pla(); - timers_.write<5>(registers.a); - advance_cycles(14); - - - //; clear timer flags - // - // lda #$50 ; clr ta,tb - // sta tedirq - ldimm(registers.a, 0x50); - interrupts_.set_status(registers.a); - advance_cycles(6); - - - //; um...check that edge again - // - //casdb1 - // lda port - // cmp port - // bne casdb1 ; something is going on here... - // and #$10 ; a look at that edge again - // bne badeg1 ; woa! got a bad edge trigger !ls! - do { - ldimm(registers.a, io_input()); - cmp(io_input()); - if(advance_cycles(9)) { - return; - } - } while(ne()); - andimm(0x10); - advance_cycles(5); - } while(ne()); - - - // - //; must have been a valid edge - //; - //; do stop key check here - // - // jsr balout - - /* balout not checked */ - - - // lda #$10 - //wata ; wait for ta to timeout - ldimm(registers.a, 0x10); - advance_cycles(3); - do { - // bit port ; kuldge, kludge, kludge !!! <<><>> - // bne rshort ; kuldge, kludge, kludge !!! <<><>> - bit(io_input()); - if(ne()) { - rshort(); - return; - } - - // bit tedirq - // beq wata - bit(interrupts_.status()); - - if(advance_cycles(12)) { - return; - } - } while(eq()); - - - // - //; now do the dipole sample #1 - // - //casdb2 - do { - // lda port - // cmp port - ldimm(registers.a, io_input()); - cmp(io_input()); - - if(advance_cycles(9)) { - return; - } - // bne casdb2 - } while(ne()); - - // and #$10 - // bne rshort ; shorts anyone? - andimm(0x10); - advance_cycles(3); - if(ne()) { - rshort(); - return; - } - - // - //; perhaps a long or a word? - // - // lda #$40 - //watb - // bit tedirq - // beq watb - // - //; wait for tb to timeout - //; now do the dipole sample #2 - ldimm(registers.a, 0x40); - advance_cycles(3); - do { - bit(interrupts_.status()); - if(advance_cycles(6)) { - return; - } - } while(eq()); - - - //casdb3 - // lda port - // cmp port - // bne casdb3 - do { - ldimm(registers.a, io_input()); - cmp(io_input()); - if(advance_cycles(9)) { - return; - } - } while(ne()); - - // and #$10 - // bne rlong ; looks like a long from here !ls! - andimm(0x10); - advance_cycles(2); - if(ne()) { - rlong(); - return; - } - - // ; or could it be a word? - // lda zcell - // sta timr2l - // lda zcell+1 - // sta timr2h - ldabs(registers.a, zcell); - timers_.write<2>(registers.a); - ldabs(registers.a, zcell + 1); - timers_.write<3>(registers.y); - advance_cycles(16); - - - // ; go! z-cell check - // ; clear ta flag - // lda #$10 - // sta tedirq ; verify +180 half of word dipole - // lda #$10 - ldimm(registers.a, 0x10); - interrupts_.set_status(registers.a); - ldimm(registers.a, 0x10); - advance_cycles(8); - - //wata2 - // bit tedirq - // beq wata2 ; check z-cell is low - do { - bit(interrupts_.status()); - if(advance_cycles(7)) { - return; - } - } while(eq()); - - //casdb4 - // lda port - // cmp port - // bne casdb4 - do { - ldimm(registers.a, io_input()); - cmp(io_input()); - if(advance_cycles(9)) { - return; - } - } while(ne()); - - // and #$10 - // beq rderr1 ; !ls! - // bit twordd ; got a word dipole - // bmi dipok ; !bra - andimm(0x10); - advance_cycles(2); - if(eq()) { - rderr1(); - return; - } - bit(0x80); - advance_cycles(2); - dipok(); - } - uint8_t io_direction_ = 0x00, io_output_ = 0x00; uint8_t io_input() const { const uint8_t all_inputs = diff --git a/Machines/Commodore/Vic-20/Vic20.cpp b/Machines/Commodore/Vic-20/Vic20.cpp index e30696c3c..900a24dbc 100644 --- a/Machines/Commodore/Vic-20/Vic20.cpp +++ b/Machines/Commodore/Vic-20/Vic20.cpp @@ -550,6 +550,7 @@ public: value = 0x0c; // i.e. NOP abs, to swallow the entire JSR } else if(address == 0xf90b) { + // second JSR in TAPE / LAB_F8F4. auto registers = m6502_.registers(); if(registers.x == 0xe) { Storage::Tape::Commodore::Parser parser(TargetPlatform::Vic20);