diff --git a/Components/1770/1770.cpp b/Components/1770/1770.cpp index 276e13de8..6603caaec 100644 --- a/Components/1770/1770.cpp +++ b/Components/1770/1770.cpp @@ -276,7 +276,7 @@ void WD1770::process_input_bit(int value, unsigned int cycles_since_index_hole) bits_since_token_++; Token::Type token_type = Token::Byte; - if(is_double_density_) + if(!is_double_density_) { switch(shift_register_ & 0xffff) { @@ -356,16 +356,19 @@ void WD1770::process_index_hole() #define END_SECTION() 0; } -void WD1770::posit_event(Event type) +void WD1770::posit_event(Event new_event_type) { - if(!(interesting_event_mask_ & (int)type)) return; - interesting_event_mask_ &= ~type; + if(!(interesting_event_mask_ & (int)new_event_type)) return; + interesting_event_mask_ &= ~new_event_type; BEGIN_SECTION() // Wait for a new command, branch to the appropriate handler. wait_for_command: + printf("Idle...\n"); + status_ &= ~Flag::Busy; WAIT_FOR_EVENT(Event::Command); + printf("Starting %02x\n", command_); status_ |= Flag::Busy; if(!(command_ & 0x80)) goto begin_type_1; if(!(command_ & 0x40)) goto begin_type_2; @@ -377,9 +380,9 @@ void WD1770::posit_event(Event type) */ begin_type_1: // Set initial flags, skip spin-up if possible. - status_ &= ~(Flag::DataRequest | Flag::DataRequest); + status_ &= ~(Flag::DataRequest | Flag::DataRequest | Flag::SeekError); set_interrupt_request(false); - if(!(command_&0x08)) goto test_type1_type; + if((command_&0x08) || (status_ & Flag::MotorOn)) goto test_type1_type; // Perform spin up. status_ |= Flag::MotorOn; @@ -389,6 +392,7 @@ void WD1770::posit_event(Event type) WAIT_FOR_EVENT(Event::IndexHole); WAIT_FOR_EVENT(Event::IndexHole); WAIT_FOR_EVENT(Event::IndexHole); + status_ |= Flag::SpinUp; test_type1_type: // Set step direction if this is a step in or out. @@ -402,10 +406,10 @@ void WD1770::posit_event(Event type) perform_seek_or_restore_command: if(track_ == data_) goto verify; - step_direction_ = (data_ < track_); + step_direction_ = (data_ > track_); adjust_track: - if(step_direction_) track_--; else track_++; + if(step_direction_) track_++; else track_--; perform_step: if(!step_direction_ && get_is_track_zero()) @@ -435,15 +439,77 @@ void WD1770::posit_event(Event type) if(!(command_ & 0x04)) { set_interrupt_request(true); - status_ &= ~(Flag::Busy); goto wait_for_command; } printf("!!!TODO: verify a type 1!!!\n"); - begin_type_2: - printf("!!!TODO: type 2 commands!!!\n"); + /* + Type 2 entry point. + */ + begin_type_2: + status_ &= ~(Flag::DataRequest | Flag::LostData | Flag::RecordNotFound | Flag::WriteProtect | Flag::RecordType); + set_interrupt_request(false); + distance_into_header_ = 0; + if((command_&0x08) || (status_ & Flag::MotorOn)) goto test_type2_delay; + + // Perform spin up. + status_ |= Flag::MotorOn; + WAIT_FOR_EVENT(Event::IndexHole); + WAIT_FOR_EVENT(Event::IndexHole); + WAIT_FOR_EVENT(Event::IndexHole); + WAIT_FOR_EVENT(Event::IndexHole); + WAIT_FOR_EVENT(Event::IndexHole); + WAIT_FOR_EVENT(Event::IndexHole); + + test_type2_delay: + index_hole_count_ = 0; + if(!(command_ & 0x04)) goto test_type2_write_protection; + WAIT_FOR_TIME(30); + + test_type2_write_protection: + if(command_&0x20) // TODO:: && is_write_protected + { + set_interrupt_request(true); + status_ |= Flag::WriteProtect; + goto wait_for_command; + } + + type2_get_header: + WAIT_FOR_EVENT(Event::IndexHole | Event::Token); + if(new_event_type == Event::Token) + { + if(!distance_into_header_ && latest_token_.type == Token::ID) distance_into_header_++; + else if(distance_into_header_ && latest_token_.type == Token::Byte) + { + header[distance_into_header_ - 1] = latest_token_.byte_value; + distance_into_header_++; + if(distance_into_header_ == 5) + { + if(header[0] == track_ && header[1] == sector_) + { + // TODO: test CRC + goto type2_read_or_write_data; + } + else + { + distance_into_header_ = 0; + } + } + } + } + else if(index_hole_count_ == 5) + { + set_interrupt_request(true); + status_ |= Flag::RecordNotFound; + goto wait_for_command; + } + goto type2_get_header; + + + type2_read_or_write_data: + printf("!!!TODO: data portion of sector!!!\n"); begin_type_3: printf("!!!TODO: type 3 commands!!!\n"); diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp index c000f7f5a..b51bcfbe9 100644 --- a/Components/1770/1770.hpp +++ b/Components/1770/1770.hpp @@ -30,6 +30,7 @@ class WD1770: public Storage::Disk::Drive { RecordType = 0x20, SpinUp = 0x20, RecordNotFound = 0x10, + SeekError = 0x10, CRCError = 0x08, LostData = 0x04, TrackZero = 0x04, @@ -116,6 +117,10 @@ class WD1770: public Storage::Disk::Drive { int resume_point_; int delay_time_; + // ID buffer + int distance_into_header_; + uint8_t header[5]; + // virtual void process_input_bit(int value, unsigned int cycles_since_index_hole); virtual void process_index_hole(); diff --git a/Machines/Electron/Electron.cpp b/Machines/Electron/Electron.cpp index eda25f817..a29054b37 100644 --- a/Machines/Electron/Electron.cpp +++ b/Machines/Electron/Electron.cpp @@ -411,6 +411,9 @@ unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uin { *value &= _roms[ROMSlotBASIC][address & 16383]; } + } else if(_rom_write_masks[_active_rom]) + { + _roms[_active_rom][address & 16383] = *value; } } break; @@ -496,7 +499,7 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target) if(target.acorn.has_dfs) { - set_rom(ROMSlot0, _dfs); + set_rom(ROMSlot0, _dfs, true); } _wd1770->set_disk(target.disks.front()); @@ -505,7 +508,7 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target) ROMSlot slot = ROMSlot12; for(std::shared_ptr cartridge : target.cartridges) { - set_rom(slot, cartridge->get_segments().front().data); + set_rom(slot, cartridge->get_segments().front().data, false); slot = (ROMSlot)(((int)slot + 1)&15); } @@ -515,7 +518,7 @@ void Machine::configure_as_target(const StaticAnalyser::Target &target) } } -void Machine::set_rom(ROMSlot slot, std::vector data) +void Machine::set_rom(ROMSlot slot, std::vector data, bool is_writeable) { uint8_t *target = nullptr; switch(slot) @@ -524,7 +527,10 @@ void Machine::set_rom(ROMSlot slot, std::vector data) case ROMSlotADFS: _adfs = data; return; case ROMSlotOS: target = _os; break; - default: target = _roms[slot]; break; + default: + target = _roms[slot]; + _rom_write_masks[slot] = is_writeable; + break; } memcpy(target, &data[0], std::min((size_t)16384, data.size())); diff --git a/Machines/Electron/Electron.hpp b/Machines/Electron/Electron.hpp index 2b3b85f14..0628d92b5 100644 --- a/Machines/Electron/Electron.hpp +++ b/Machines/Electron/Electron.hpp @@ -148,7 +148,7 @@ class Machine: public: Machine(); - void set_rom(ROMSlot slot, std::vector data); + void set_rom(ROMSlot slot, std::vector data, bool is_writeable); void configure_as_target(const StaticAnalyser::Target &target); void set_key_state(Key key, bool isPressed); @@ -189,6 +189,7 @@ class Machine: // Things that directly constitute the memory map. uint8_t _roms[16][16384]; + bool _rom_write_masks[16]; uint8_t _os[16384], _ram[32768]; std::vector _dfs, _adfs; diff --git a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSElectron.mm b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSElectron.mm index ad3481dd3..97f3ed865 100644 --- a/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSElectron.mm +++ b/OSBindings/Mac/Clock Signal/Machine/Wrappers/CSElectron.mm @@ -33,7 +33,7 @@ - (void)setROM:(nonnull NSData *)rom slot:(int)slot { @synchronized(self) { - _electron.set_rom((Electron::ROMSlot)slot, rom.stdVector8); + _electron.set_rom((Electron::ROMSlot)slot, rom.stdVector8, false); } }