mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-07 23:25:00 +00:00
Merge pull request #1312 from TomHarte/BetterLogging
Switch to a better logging interface.
This commit is contained in:
@@ -11,6 +11,12 @@
|
|||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::MultiMachine> logger;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
using namespace Analyser::Dynamic;
|
using namespace Analyser::Dynamic;
|
||||||
|
|
||||||
MultiMachine::MultiMachine(std::vector<std::unique_ptr<DynamicMachine>> &&machines) :
|
MultiMachine::MultiMachine(std::vector<std::unique_ptr<DynamicMachine>> &&machines) :
|
||||||
@@ -61,13 +67,14 @@ bool MultiMachine::would_collapse(const std::vector<std::unique_ptr<DynamicMachi
|
|||||||
|
|
||||||
void MultiMachine::did_run_machines(MultiTimedMachine *) {
|
void MultiMachine::did_run_machines(MultiTimedMachine *) {
|
||||||
std::lock_guard machines_lock(machines_mutex_);
|
std::lock_guard machines_lock(machines_mutex_);
|
||||||
#ifndef NDEBUG
|
|
||||||
for(const auto &machine: machines_) {
|
if constexpr (logger.enabled) {
|
||||||
auto timed_machine = machine->timed_machine();
|
auto line = logger.info();
|
||||||
LOGNBR(PADHEX(2) << timed_machine->get_confidence() << " " << timed_machine->debug_type() << "; ");
|
for(const auto &machine: machines_) {
|
||||||
|
auto timed_machine = machine->timed_machine();
|
||||||
|
line.append("%0.4f %s; ", timed_machine->get_confidence(), timed_machine->debug_type().c_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
LOGNBR(std::endl);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
DynamicMachine *front = machines_.front().get();
|
DynamicMachine *front = machines_.front().get();
|
||||||
std::stable_sort(machines_.begin(), machines_.end(),
|
std::stable_sort(machines_.begin(), machines_.end(),
|
||||||
|
@@ -93,7 +93,7 @@ Analyser::Static::TargetList Analyser::Static::Commodore::GetTargets(const Media
|
|||||||
// make a first guess based on loading address
|
// make a first guess based on loading address
|
||||||
switch(files.front().starting_address) {
|
switch(files.front().starting_address) {
|
||||||
default:
|
default:
|
||||||
LOG("Unrecognised loading address for Commodore program: " << PADHEX(4) << files.front().starting_address);
|
Log::Logger<Log::Source::CommodoreStaticAnalyser>().error().append("Unrecognised loading address for Commodore program: %04x", files.front().starting_address);
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case 0x1001:
|
case 0x1001:
|
||||||
memory_model = Target::MemoryModel::Unexpanded;
|
memory_model = Target::MemoryModel::Unexpanded;
|
||||||
|
@@ -9,10 +9,12 @@
|
|||||||
#include "1770.hpp"
|
#include "1770.hpp"
|
||||||
|
|
||||||
#include "../../Storage/Disk/Encodings/MFM/Constants.hpp"
|
#include "../../Storage/Disk/Encodings/MFM/Constants.hpp"
|
||||||
|
|
||||||
#define LOG_PREFIX "[WD FDC] "
|
|
||||||
#include "../../Outputs/Log.hpp"
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Log::Logger<Log::Source::WDFDC> logger;
|
||||||
|
}
|
||||||
|
|
||||||
using namespace WD;
|
using namespace WD;
|
||||||
|
|
||||||
WD1770::WD1770(Personality p) :
|
WD1770::WD1770(Personality p) :
|
||||||
@@ -29,10 +31,10 @@ void WD1770::write(int address, uint8_t value) {
|
|||||||
if((value&0xf0) == 0xd0) {
|
if((value&0xf0) == 0xd0) {
|
||||||
if(value == 0xd0) {
|
if(value == 0xd0) {
|
||||||
// Force interrupt **immediately**.
|
// Force interrupt **immediately**.
|
||||||
LOG("Force interrupt immediately");
|
logger.info().append("Force interrupt immediately");
|
||||||
posit_event(int(Event1770::ForceInterrupt));
|
posit_event(int(Event1770::ForceInterrupt));
|
||||||
} else {
|
} else {
|
||||||
ERROR("!!!TODO: force interrupt!!!");
|
logger.error().append("TODO: force interrupt");
|
||||||
update_status([] (Status &status) {
|
update_status([] (Status &status) {
|
||||||
status.type = Status::One;
|
status.type = Status::One;
|
||||||
});
|
});
|
||||||
@@ -99,14 +101,14 @@ uint8_t WD1770::read(int address) {
|
|||||||
if(status_.type == Status::One)
|
if(status_.type == Status::One)
|
||||||
status |= (status_.spin_up ? Flag::SpinUp : 0);
|
status |= (status_.spin_up ? Flag::SpinUp : 0);
|
||||||
}
|
}
|
||||||
// LOG("Returned status " << PADHEX(2) << int(status) << " of type " << 1+int(status_.type));
|
// logger.info().append("Returned status %02x of type %d", status, 1+int(status_.type));
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
LOG("Returned track " << int(track_));
|
logger.info().append("Returned track %d", track_);
|
||||||
return track_;
|
return track_;
|
||||||
case 2:
|
case 2:
|
||||||
LOG("Returned sector " << int(sector_));
|
logger.info().append("Returned sector %d", sector_);
|
||||||
return sector_;
|
return sector_;
|
||||||
case 3:
|
case 3:
|
||||||
update_status([] (Status &status) {
|
update_status([] (Status &status) {
|
||||||
@@ -212,7 +214,7 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
// Wait for a new command, branch to the appropriate handler.
|
// Wait for a new command, branch to the appropriate handler.
|
||||||
case 0:
|
case 0:
|
||||||
wait_for_command:
|
wait_for_command:
|
||||||
LOG("Idle...");
|
logger.info().append("Idle...");
|
||||||
set_data_mode(DataMode::Scanning);
|
set_data_mode(DataMode::Scanning);
|
||||||
index_hole_count_ = 0;
|
index_hole_count_ = 0;
|
||||||
|
|
||||||
@@ -229,7 +231,7 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
status.track_zero = false; // Always reset by a non-type 1; so reset regardless and set properly later.
|
status.track_zero = false; // Always reset by a non-type 1; so reset regardless and set properly later.
|
||||||
});
|
});
|
||||||
|
|
||||||
LOG("Starting " << PADHEX(2) << int(command_));
|
logger.info().append("Starting %02x", command_);
|
||||||
|
|
||||||
if(!(command_ & 0x80)) goto begin_type_1;
|
if(!(command_ & 0x80)) goto begin_type_1;
|
||||||
if(!(command_ & 0x40)) goto begin_type_2;
|
if(!(command_ & 0x40)) goto begin_type_2;
|
||||||
@@ -259,7 +261,7 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
status.data_request = false;
|
status.data_request = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
LOG("Step/Seek/Restore with track " << int(track_) << " data " << int(data_));
|
logger.info().append("Step/Seek/Restore with track %d data %d", track_, data_);
|
||||||
if(!has_motor_on_line() && !has_head_load_line()) goto test_type1_type;
|
if(!has_motor_on_line() && !has_head_load_line()) goto test_type1_type;
|
||||||
|
|
||||||
if(has_motor_on_line()) goto begin_type1_spin_up;
|
if(has_motor_on_line()) goto begin_type1_spin_up;
|
||||||
@@ -339,7 +341,7 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
READ_ID();
|
READ_ID();
|
||||||
|
|
||||||
if(index_hole_count_ == 6) {
|
if(index_hole_count_ == 6) {
|
||||||
LOG("Nothing found to verify");
|
logger.info().append("Nothing found to verify");
|
||||||
update_status([] (Status &status) {
|
update_status([] (Status &status) {
|
||||||
status.seek_error = true;
|
status.seek_error = true;
|
||||||
});
|
});
|
||||||
@@ -357,7 +359,7 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(header_[0] == track_) {
|
if(header_[0] == track_) {
|
||||||
LOG("Reached track " << std::dec << int(track_));
|
logger.info().append("Reached track %d", track_);
|
||||||
update_status([] (Status &status) {
|
update_status([] (Status &status) {
|
||||||
status.crc_error = false;
|
status.crc_error = false;
|
||||||
});
|
});
|
||||||
@@ -430,7 +432,7 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
READ_ID();
|
READ_ID();
|
||||||
|
|
||||||
if(index_hole_count_ == 5) {
|
if(index_hole_count_ == 5) {
|
||||||
LOG("Failed to find sector " << std::dec << int(sector_));
|
logger.info().append("Failed to find sector %d", sector_);
|
||||||
update_status([] (Status &status) {
|
update_status([] (Status &status) {
|
||||||
status.record_not_found = true;
|
status.record_not_found = true;
|
||||||
});
|
});
|
||||||
@@ -440,12 +442,12 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
distance_into_section_ = 0;
|
distance_into_section_ = 0;
|
||||||
set_data_mode(DataMode::Scanning);
|
set_data_mode(DataMode::Scanning);
|
||||||
|
|
||||||
LOG("Considering " << std::dec << int(header_[0]) << "/" << int(header_[2]));
|
logger.info().append("Considering %d/%d", header_[0], header_[2]);
|
||||||
if( header_[0] == track_ && header_[2] == sector_ &&
|
if( header_[0] == track_ && header_[2] == sector_ &&
|
||||||
(has_motor_on_line() || !(command_&0x02) || ((command_&0x08) >> 3) == header_[1])) {
|
(has_motor_on_line() || !(command_&0x02) || ((command_&0x08) >> 3) == header_[1])) {
|
||||||
LOG("Found " << std::dec << int(header_[0]) << "/" << int(header_[2]));
|
logger.info().append("Found %d/%d", header_[0], header_[2]);
|
||||||
if(get_crc_generator().get_value()) {
|
if(get_crc_generator().get_value()) {
|
||||||
LOG("CRC error; back to searching");
|
logger.info().append("CRC error; back to searching");
|
||||||
update_status([] (Status &status) {
|
update_status([] (Status &status) {
|
||||||
status.crc_error = true;
|
status.crc_error = true;
|
||||||
});
|
});
|
||||||
@@ -503,18 +505,18 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
set_data_mode(DataMode::Scanning);
|
set_data_mode(DataMode::Scanning);
|
||||||
|
|
||||||
if(get_crc_generator().get_value()) {
|
if(get_crc_generator().get_value()) {
|
||||||
LOG("CRC error; terminating");
|
logger.info().append("CRC error; terminating");
|
||||||
update_status([] (Status &status) {
|
update_status([] (Status &status) {
|
||||||
status.crc_error = true;
|
status.crc_error = true;
|
||||||
});
|
});
|
||||||
goto wait_for_command;
|
goto wait_for_command;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("Finished reading sector " << std::dec << int(sector_));
|
logger.info().append("Finished reading sector %d", sector_);
|
||||||
|
|
||||||
if(command_ & 0x10) {
|
if(command_ & 0x10) {
|
||||||
sector_++;
|
sector_++;
|
||||||
LOG("Advancing to search for sector " << std::dec << int(sector_));
|
logger.info().append("Advancing to search for sector %d", sector_);
|
||||||
goto test_type2_write_protection;
|
goto test_type2_write_protection;
|
||||||
}
|
}
|
||||||
goto wait_for_command;
|
goto wait_for_command;
|
||||||
@@ -598,7 +600,7 @@ void WD1770::posit_event(int new_event_type) {
|
|||||||
sector_++;
|
sector_++;
|
||||||
goto test_type2_write_protection;
|
goto test_type2_write_protection;
|
||||||
}
|
}
|
||||||
LOG("Wrote sector " << std::dec << int(sector_));
|
logger.info().append("Wrote sector %d", sector_);
|
||||||
goto wait_for_command;
|
goto wait_for_command;
|
||||||
|
|
||||||
|
|
||||||
|
@@ -8,13 +8,11 @@
|
|||||||
|
|
||||||
#include "ncr5380.hpp"
|
#include "ncr5380.hpp"
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define NDEBUG
|
|
||||||
#endif
|
|
||||||
#define LOG_PREFIX "[5380] "
|
|
||||||
|
|
||||||
#include "../../Outputs/Log.hpp"
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Log::Logger<Log::Source::NCR5380> logger;
|
||||||
|
}
|
||||||
// TODO:
|
// TODO:
|
||||||
//
|
//
|
||||||
// end_of_dma_ should be set if: /EOP && /DACK && (/RD || /WR); for at least 100ns.
|
// end_of_dma_ should be set if: /EOP && /DACK && (/RD || /WR); for at least 100ns.
|
||||||
@@ -38,7 +36,7 @@ NCR5380::NCR5380(SCSI::Bus &bus, int clock_rate) :
|
|||||||
void NCR5380::write(int address, uint8_t value, bool) {
|
void NCR5380::write(int address, uint8_t value, bool) {
|
||||||
switch(address & 7) {
|
switch(address & 7) {
|
||||||
case 0:
|
case 0:
|
||||||
LOG("[0] Set current SCSI bus state to " << PADHEX(2) << int(value));
|
logger.info().append("[0] Set current SCSI bus state to %02x", value);
|
||||||
|
|
||||||
data_bus_ = value;
|
data_bus_ = value;
|
||||||
if(dma_request_ && dma_operation_ == DMAOperation::Send) {
|
if(dma_request_ && dma_operation_ == DMAOperation::Send) {
|
||||||
@@ -47,7 +45,7 @@ void NCR5380::write(int address, uint8_t value, bool) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: {
|
case 1: {
|
||||||
LOG("[1] Initiator command register set: " << PADHEX(2) << int(value));
|
logger.info().append("[1] Initiator command register set: %02x", value);
|
||||||
initiator_command_ = value;
|
initiator_command_ = value;
|
||||||
|
|
||||||
bus_output_ &= ~(Line::Reset | Line::Acknowledge | Line::Busy | Line::SelectTarget | Line::Attention);
|
bus_output_ &= ~(Line::Reset | Line::Acknowledge | Line::Busy | Line::SelectTarget | Line::Attention);
|
||||||
@@ -63,7 +61,7 @@ void NCR5380::write(int address, uint8_t value, bool) {
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
LOG("[2] Set mode: " << PADHEX(2) << int(value));
|
logger.info().append("[2] Set mode: %02x", value);
|
||||||
mode_ = value;
|
mode_ = value;
|
||||||
|
|
||||||
// bit 7: 1 = use block mode DMA mode (if DMA mode is also enabled)
|
// bit 7: 1 = use block mode DMA mode (if DMA mode is also enabled)
|
||||||
@@ -104,27 +102,27 @@ void NCR5380::write(int address, uint8_t value, bool) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: {
|
case 3: {
|
||||||
LOG("[3] Set target command: " << PADHEX(2) << int(value));
|
logger.info().append("[3] Set target command: %02x", value);
|
||||||
target_command_ = value;
|
target_command_ = value;
|
||||||
update_control_output();
|
update_control_output();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case 4:
|
case 4:
|
||||||
LOG("[4] Set select enabled: " << PADHEX(2) << int(value));
|
logger.info().append("[4] Set select enabled: %02x", value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 5:
|
case 5:
|
||||||
LOG("[5] Start DMA send: " << PADHEX(2) << int(value));
|
logger.info().append("[5] Start DMA send: %02x", value);
|
||||||
dma_operation_ = DMAOperation::Send;
|
dma_operation_ = DMAOperation::Send;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
LOG("[6] Start DMA target receive: " << PADHEX(2) << int(value));
|
logger.info().append("[6] Start DMA target receive: %02x", value);
|
||||||
dma_operation_ = DMAOperation::TargetReceive;
|
dma_operation_ = DMAOperation::TargetReceive;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 7:
|
case 7:
|
||||||
LOG("[7] Start DMA initiator receive: " << PADHEX(2) << int(value));
|
logger.info().append("[7] Start DMA initiator receive: %02x", value);
|
||||||
dma_operation_ = DMAOperation::InitiatorReceive;
|
dma_operation_ = DMAOperation::InitiatorReceive;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -148,7 +146,7 @@ void NCR5380::write(int address, uint8_t value, bool) {
|
|||||||
uint8_t NCR5380::read(int address, bool) {
|
uint8_t NCR5380::read(int address, bool) {
|
||||||
switch(address & 7) {
|
switch(address & 7) {
|
||||||
case 0:
|
case 0:
|
||||||
LOG("[0] Get current SCSI bus state: " << PADHEX(2) << (bus_.get_state() & 0xff));
|
logger.info().append("[0] Get current SCSI bus state: %02x", (bus_.get_state() & 0xff));
|
||||||
|
|
||||||
if(dma_request_ && dma_operation_ == DMAOperation::InitiatorReceive) {
|
if(dma_request_ && dma_operation_ == DMAOperation::InitiatorReceive) {
|
||||||
return dma_acknowledge();
|
return dma_acknowledge();
|
||||||
@@ -156,7 +154,7 @@ uint8_t NCR5380::read(int address, bool) {
|
|||||||
return uint8_t(bus_.get_state());
|
return uint8_t(bus_.get_state());
|
||||||
|
|
||||||
case 1:
|
case 1:
|
||||||
LOG("[1] Initiator command register get: " << (arbitration_in_progress_ ? 'p' : '-') << (lost_arbitration_ ? 'l' : '-'));
|
logger.info().append("[1] Initiator command register get: %c%c", arbitration_in_progress_ ? 'p' : '-', lost_arbitration_ ? 'l' : '-');
|
||||||
return
|
return
|
||||||
// Bits repeated as they were set.
|
// Bits repeated as they were set.
|
||||||
(initiator_command_ & ~0x60) |
|
(initiator_command_ & ~0x60) |
|
||||||
@@ -168,11 +166,11 @@ uint8_t NCR5380::read(int address, bool) {
|
|||||||
(lost_arbitration_ ? 0x20 : 0x00);
|
(lost_arbitration_ ? 0x20 : 0x00);
|
||||||
|
|
||||||
case 2:
|
case 2:
|
||||||
LOG("[2] Get mode");
|
logger.info().append("[2] Get mode");
|
||||||
return mode_;
|
return mode_;
|
||||||
|
|
||||||
case 3:
|
case 3:
|
||||||
LOG("[3] Get target command");
|
logger.info().append("[3] Get target command");
|
||||||
return target_command_;
|
return target_command_;
|
||||||
|
|
||||||
case 4: {
|
case 4: {
|
||||||
@@ -186,7 +184,7 @@ uint8_t NCR5380::read(int address, bool) {
|
|||||||
((bus_state & Line::Input) ? 0x04 : 0x00) |
|
((bus_state & Line::Input) ? 0x04 : 0x00) |
|
||||||
((bus_state & Line::SelectTarget) ? 0x02 : 0x00) |
|
((bus_state & Line::SelectTarget) ? 0x02 : 0x00) |
|
||||||
((bus_state & Line::Parity) ? 0x01 : 0x00);
|
((bus_state & Line::Parity) ? 0x01 : 0x00);
|
||||||
LOG("[4] Get current bus state: " << PADHEX(2) << int(result));
|
logger.info().append("[4] Get current bus state: %02x", result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -201,16 +199,16 @@ uint8_t NCR5380::read(int address, bool) {
|
|||||||
/* b2 = busy error */
|
/* b2 = busy error */
|
||||||
((bus_state & Line::Attention) ? 0x02 : 0x00) |
|
((bus_state & Line::Attention) ? 0x02 : 0x00) |
|
||||||
((bus_state & Line::Acknowledge) ? 0x01 : 0x00);
|
((bus_state & Line::Acknowledge) ? 0x01 : 0x00);
|
||||||
LOG("[5] Get bus and status: " << PADHEX(2) << int(result));
|
logger.info().append("[5] Get bus and status: %02x", result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 6:
|
case 6:
|
||||||
LOG("[6] Get input data");
|
logger.info().append("[6] Get input data");
|
||||||
return 0xff;
|
return 0xff;
|
||||||
|
|
||||||
case 7:
|
case 7:
|
||||||
LOG("[7] Reset parity/interrupt");
|
logger.info().append("[7] Reset parity/interrupt");
|
||||||
irq_ = false;
|
irq_ = false;
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
|
@@ -11,13 +11,14 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define NDEBUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LOG_PREFIX "[MFP] "
|
|
||||||
#include "../../Outputs/Log.hpp"
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::MFP68901> logger;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
using namespace Motorola::MFP68901;
|
using namespace Motorola::MFP68901;
|
||||||
|
|
||||||
ClockingHint::Preference MFP68901::preferred_clocking() const {
|
ClockingHint::Preference MFP68901::preferred_clocking() const {
|
||||||
@@ -64,11 +65,11 @@ uint8_t MFP68901::read(int address) {
|
|||||||
case 0x11: case 0x12: return get_timer_data(address - 0xf);
|
case 0x11: case 0x12: return get_timer_data(address - 0xf);
|
||||||
|
|
||||||
// USART block: TODO.
|
// USART block: TODO.
|
||||||
case 0x13: LOG("Read: sync character generator"); break;
|
case 0x13: logger.error().append("Read: sync character generator"); break;
|
||||||
case 0x14: LOG("Read: USART control"); break;
|
case 0x14: logger.error().append("Read: USART control"); break;
|
||||||
case 0x15: LOG("Read: receiver status"); break;
|
case 0x15: logger.error().append("Read: receiver status"); break;
|
||||||
case 0x16: LOG("Read: transmitter status"); break;
|
case 0x16: logger.error().append("Read: transmitter status"); break;
|
||||||
case 0x17: LOG("Read: USART data"); break;
|
case 0x17: logger.error().append("Read: USART data"); break;
|
||||||
}
|
}
|
||||||
return 0x00;
|
return 0x00;
|
||||||
}
|
}
|
||||||
@@ -169,11 +170,11 @@ void MFP68901::write(int address, uint8_t value) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
// USART block: TODO.
|
// USART block: TODO.
|
||||||
case 0x13: LOG("Write: sync character generator"); break;
|
case 0x13: logger.error().append("Write: sync character generator"); break;
|
||||||
case 0x14: LOG("Write: USART control"); break;
|
case 0x14: logger.error().append("Write: USART control"); break;
|
||||||
case 0x15: LOG("Write: receiver status"); break;
|
case 0x15: logger.error().append("Write: receiver status"); break;
|
||||||
case 0x16: LOG("Write: transmitter status"); break;
|
case 0x16: logger.error().append("Write: transmitter status"); break;
|
||||||
case 0x17: LOG("Write: USART data"); break;
|
case 0x17: logger.error().append("Write: USART data"); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
update_clocking_observer();
|
update_clocking_observer();
|
||||||
@@ -220,7 +221,7 @@ HalfCycles MFP68901::next_sequence_point() {
|
|||||||
// MARK: - Timers
|
// MARK: - Timers
|
||||||
|
|
||||||
void MFP68901::set_timer_mode(int timer, TimerMode mode, int prescale, bool reset_timer) {
|
void MFP68901::set_timer_mode(int timer, TimerMode mode, int prescale, bool reset_timer) {
|
||||||
LOG("Timer " << timer << " mode set: " << int(mode) << "; prescale: " << prescale);
|
logger.error().append("Timer %d mode set: %d; prescale: %d", timer, mode, prescale);
|
||||||
timers_[timer].mode = mode;
|
timers_[timer].mode = mode;
|
||||||
if(reset_timer) {
|
if(reset_timer) {
|
||||||
timers_[timer].prescale_count = 0;
|
timers_[timer].prescale_count = 0;
|
||||||
@@ -398,7 +399,7 @@ int MFP68901::acknowledge_interrupt() {
|
|||||||
|
|
||||||
int selected = 0;
|
int selected = 0;
|
||||||
while((1 << selected) != mask) ++selected;
|
while((1 << selected) != mask) ++selected;
|
||||||
// LOG("Interrupt acknowledged: " << selected);
|
// logger.error().append("Interrupt acknowledged: %d", selected);
|
||||||
return (interrupt_vector_ & 0xf0) | uint8_t(selected);
|
return (interrupt_vector_ & 0xf0) | uint8_t(selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -10,6 +10,12 @@
|
|||||||
|
|
||||||
#include "../../Outputs/Log.hpp"
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::i8272> logger;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
using namespace Intel::i8272;
|
using namespace Intel::i8272;
|
||||||
|
|
||||||
i8272::i8272(BusHandler &bus_handler, Cycles clock_rate) :
|
i8272::i8272(BusHandler &bus_handler, Cycles clock_rate) :
|
||||||
@@ -54,7 +60,7 @@ void i8272::run_for(Cycles cycles) {
|
|||||||
while(steps--) {
|
while(steps--) {
|
||||||
// Perform a step.
|
// Perform a step.
|
||||||
int direction = (drives_[c].target_head_position < drives_[c].head_position) ? -1 : 1;
|
int direction = (drives_[c].target_head_position < drives_[c].head_position) ? -1 : 1;
|
||||||
LOG("Target " << PADDEC(0) << drives_[c].target_head_position << " versus believed " << int(drives_[c].head_position));
|
logger.info().append("Target %d versus believed %d", drives_[c].target_head_position, drives_[c].head_position);
|
||||||
select_drive(c);
|
select_drive(c);
|
||||||
get_drive().step(Storage::Disk::HeadPosition(direction));
|
get_drive().step(Storage::Disk::HeadPosition(direction));
|
||||||
if(drives_[c].target_head_position >= 0) drives_[c].head_position += direction;
|
if(drives_[c].target_head_position >= 0) drives_[c].head_position += direction;
|
||||||
@@ -303,17 +309,17 @@ void i8272::posit_event(int event_type) {
|
|||||||
// the index hole limit is breached or a sector is found with a cylinder, head, sector and size equal to the
|
// the index hole limit is breached or a sector is found with a cylinder, head, sector and size equal to the
|
||||||
// values in the internal registers.
|
// values in the internal registers.
|
||||||
index_hole_limit_ = 2;
|
index_hole_limit_ = 2;
|
||||||
// LOG("Seeking " << PADDEC(0) << cylinder_ << " " << head_ " " << sector_ << " " << size_);
|
// logger.info().append("Seeking " << PADDEC(0) << cylinder_ << " " << head_ " " << sector_ << " " << size_);
|
||||||
find_next_sector:
|
find_next_sector:
|
||||||
FIND_HEADER();
|
FIND_HEADER();
|
||||||
if(!index_hole_limit_) {
|
if(!index_hole_limit_) {
|
||||||
// Two index holes have passed wihout finding the header sought.
|
// Two index holes have passed wihout finding the header sought.
|
||||||
// LOG("Not found");
|
// logger.info().append("Not found");
|
||||||
status_.set(Status1::NoData);
|
status_.set(Status1::NoData);
|
||||||
goto abort;
|
goto abort;
|
||||||
}
|
}
|
||||||
index_hole_count_ = 0;
|
index_hole_count_ = 0;
|
||||||
// LOG("Header");
|
// logger.info().append("Header");
|
||||||
READ_HEADER();
|
READ_HEADER();
|
||||||
if(index_hole_count_) {
|
if(index_hole_count_) {
|
||||||
// This implies an index hole was sighted within the header. Error out.
|
// This implies an index hole was sighted within the header. Error out.
|
||||||
@@ -324,11 +330,11 @@ void i8272::posit_event(int event_type) {
|
|||||||
// This implies a CRC error in the header; mark as such but continue.
|
// This implies a CRC error in the header; mark as such but continue.
|
||||||
status_.set(Status1::DataError);
|
status_.set(Status1::DataError);
|
||||||
}
|
}
|
||||||
// LOG("Considering << PADHEX(2) << header_[0] << " " << header_[1] << " " << header_[2] << " " << header_[3] << " [" << get_crc_generator().get_value() << "]");
|
// logger.info().append("Considering %02x %02x %02x %02x [%04x]", header_[0], header_[1], header_[2], header_[3], get_crc_generator().get_value());
|
||||||
if(header_[0] != cylinder_ || header_[1] != head_ || header_[2] != sector_ || header_[3] != size_) goto find_next_sector;
|
if(header_[0] != cylinder_ || header_[1] != head_ || header_[2] != sector_ || header_[3] != size_) goto find_next_sector;
|
||||||
|
|
||||||
// Branch to whatever is supposed to happen next
|
// Branch to whatever is supposed to happen next
|
||||||
// LOG("Proceeding");
|
// logger.info().append("Proceeding");
|
||||||
switch(command_.command()) {
|
switch(command_.command()) {
|
||||||
default:
|
default:
|
||||||
case Command::ReadData:
|
case Command::ReadData:
|
||||||
@@ -343,13 +349,13 @@ void i8272::posit_event(int event_type) {
|
|||||||
|
|
||||||
// Performs the read data or read deleted data command.
|
// Performs the read data or read deleted data command.
|
||||||
read_data:
|
read_data:
|
||||||
// LOG(PADHEX(2) << "Read [deleted] data ["
|
// logger.info().append("Read [deleted] data [%02x %02x %02x %02x ... %02x %02x]",
|
||||||
// << int(command_[2]) << " "
|
// command_[2],
|
||||||
// << int(command_[3]) << " "
|
// command_[3],
|
||||||
// << int(command_[4]) << " "
|
// command_[4],
|
||||||
// << int(command_[5]) << " ... "
|
// command_[5],
|
||||||
// << int(command_[6]) << " "
|
// command_[6],
|
||||||
// << int(command_[8]) << "]");
|
// command_[8]);
|
||||||
read_next_data:
|
read_next_data:
|
||||||
goto read_write_find_header;
|
goto read_write_find_header;
|
||||||
|
|
||||||
@@ -433,13 +439,13 @@ void i8272::posit_event(int event_type) {
|
|||||||
goto post_st012chrn;
|
goto post_st012chrn;
|
||||||
|
|
||||||
write_data:
|
write_data:
|
||||||
// LOG(PADHEX(2) << "Write [deleted] data ["
|
// logger.info().append("Write [deleted] data [%02x %02x %02x %02x ... %02x %02x]",
|
||||||
// << int(command_[2]) << " "
|
// command_[2],
|
||||||
// << int(command_[3]) << " "
|
// command_[3],
|
||||||
// << int(command_[4]) << " "
|
// command_[4],
|
||||||
// << int(command_[5]) << " ... "
|
// command_[5],
|
||||||
// << int(command_[6]) << " "
|
// command_[6],
|
||||||
// << int(command_[8]) << "]");
|
// command_[8]);
|
||||||
|
|
||||||
if(get_drive().get_is_read_only()) {
|
if(get_drive().get_is_read_only()) {
|
||||||
status_.set(Status1::NotWriteable);
|
status_.set(Status1::NotWriteable);
|
||||||
@@ -474,7 +480,7 @@ void i8272::posit_event(int event_type) {
|
|||||||
goto write_loop;
|
goto write_loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG("Wrote " << PADDEC(0) << distance_into_section_ << " bytes");
|
logger.info().append("Wrote %d bytes", distance_into_section_);
|
||||||
write_crc();
|
write_crc();
|
||||||
expects_input_ = false;
|
expects_input_ = false;
|
||||||
WAIT_FOR_EVENT(Event::DataWritten);
|
WAIT_FOR_EVENT(Event::DataWritten);
|
||||||
@@ -490,7 +496,7 @@ void i8272::posit_event(int event_type) {
|
|||||||
// Performs the read ID command.
|
// Performs the read ID command.
|
||||||
read_id:
|
read_id:
|
||||||
// Establishes the drive and head being addressed, and whether in double density mode.
|
// Establishes the drive and head being addressed, and whether in double density mode.
|
||||||
// LOG(PADHEX(2) << "Read ID [" << int(command_[0]) << " " << int(command_[1]) << "]");
|
// logger.info().append("Read ID [%02x %02x]", command_[0], command_[1]);
|
||||||
|
|
||||||
// Sets a maximum index hole limit of 2 then waits either until it finds a header mark or sees too many index holes.
|
// Sets a maximum index hole limit of 2 then waits either until it finds a header mark or sees too many index holes.
|
||||||
// If a header mark is found, reads in the following bytes that produce a header. Otherwise branches to data not found.
|
// If a header mark is found, reads in the following bytes that produce a header. Otherwise branches to data not found.
|
||||||
@@ -512,11 +518,11 @@ void i8272::posit_event(int event_type) {
|
|||||||
|
|
||||||
// Performs read track.
|
// Performs read track.
|
||||||
read_track:
|
read_track:
|
||||||
// LOG(PADHEX(2) << "Read track ["
|
// logger.info().append("Read track [%02x %02x %02x %02x]"
|
||||||
// << int(command_[2]) << " "
|
// command_[2],
|
||||||
// << int(command_[3]) << " "
|
// command_[3],
|
||||||
// << int(command_[4]) << " "
|
// command_[4],
|
||||||
// << int(command_[5]) << "]");
|
// command_[5]);
|
||||||
|
|
||||||
// Wait for the index hole.
|
// Wait for the index hole.
|
||||||
WAIT_FOR_EVENT(Event::IndexHole);
|
WAIT_FOR_EVENT(Event::IndexHole);
|
||||||
@@ -557,7 +563,7 @@ void i8272::posit_event(int event_type) {
|
|||||||
|
|
||||||
// Performs format [/write] track.
|
// Performs format [/write] track.
|
||||||
format_track:
|
format_track:
|
||||||
LOG("Format track");
|
logger.info().append("Format track");
|
||||||
if(get_drive().get_is_read_only()) {
|
if(get_drive().get_is_read_only()) {
|
||||||
status_.set(Status1::NotWriteable);
|
status_.set(Status1::NotWriteable);
|
||||||
goto abort;
|
goto abort;
|
||||||
@@ -601,12 +607,8 @@ void i8272::posit_event(int event_type) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG(PADHEX(2) << "W:"
|
logger.info().append("W: %02x %02x %02x %02x, %04x",
|
||||||
<< int(header_[0]) << " "
|
header_[0], header_[1], header_[2], header_[3], get_crc_generator().get_value());
|
||||||
<< int(header_[1]) << " "
|
|
||||||
<< int(header_[2]) << " "
|
|
||||||
<< int(header_[3]) << ", "
|
|
||||||
<< get_crc_generator().get_value());
|
|
||||||
write_crc();
|
write_crc();
|
||||||
|
|
||||||
// Write the sector body.
|
// Write the sector body.
|
||||||
@@ -638,15 +640,15 @@ void i8272::posit_event(int event_type) {
|
|||||||
goto post_st012chrn;
|
goto post_st012chrn;
|
||||||
|
|
||||||
scan_low:
|
scan_low:
|
||||||
ERROR("Scan low unimplemented!!");
|
logger.error().append("Scan low unimplemented!!");
|
||||||
goto wait_for_command;
|
goto wait_for_command;
|
||||||
|
|
||||||
scan_low_or_equal:
|
scan_low_or_equal:
|
||||||
ERROR("Scan low or equal unimplemented!!");
|
logger.error().append("Scan low or equal unimplemented!!");
|
||||||
goto wait_for_command;
|
goto wait_for_command;
|
||||||
|
|
||||||
scan_high_or_equal:
|
scan_high_or_equal:
|
||||||
ERROR("Scan high or equal unimplemented!!");
|
logger.error().append("Scan high or equal unimplemented!!");
|
||||||
goto wait_for_command;
|
goto wait_for_command;
|
||||||
|
|
||||||
// Performs both recalibrate and seek commands. These commands occur asynchronously, so the actual work
|
// Performs both recalibrate and seek commands. These commands occur asynchronously, so the actual work
|
||||||
@@ -677,11 +679,11 @@ void i8272::posit_event(int event_type) {
|
|||||||
// up in run_for understands to mean 'keep going until track 0 is active').
|
// up in run_for understands to mean 'keep going until track 0 is active').
|
||||||
if(command_.command() != Command::Recalibrate) {
|
if(command_.command() != Command::Recalibrate) {
|
||||||
drives_[drive].target_head_position = command_.seek_target();
|
drives_[drive].target_head_position = command_.seek_target();
|
||||||
LOG(PADHEX(2) << "Seek to " << int(command_.seek_target()));
|
logger.info().append("Seek to %d", command_.seek_target());
|
||||||
} else {
|
} else {
|
||||||
drives_[drive].target_head_position = -1;
|
drives_[drive].target_head_position = -1;
|
||||||
drives_[drive].head_position = 0;
|
drives_[drive].head_position = 0;
|
||||||
LOG("Recalibrate");
|
logger.info().append("Recalibrate");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check whether any steps are even needed; if not then mark as completed already.
|
// Check whether any steps are even needed; if not then mark as completed already.
|
||||||
@@ -694,7 +696,7 @@ void i8272::posit_event(int event_type) {
|
|||||||
|
|
||||||
// Performs sense interrupt status.
|
// Performs sense interrupt status.
|
||||||
sense_interrupt_status:
|
sense_interrupt_status:
|
||||||
LOG("Sense interrupt status");
|
logger.info().append("Sense interrupt status");
|
||||||
{
|
{
|
||||||
// Find the first drive that is in the CompletedSeeking state.
|
// Find the first drive that is in the CompletedSeeking state.
|
||||||
int found_drive = -1;
|
int found_drive = -1;
|
||||||
@@ -722,7 +724,7 @@ void i8272::posit_event(int event_type) {
|
|||||||
// Performs specify.
|
// Performs specify.
|
||||||
specify:
|
specify:
|
||||||
// Just store the values, and terminate the command.
|
// Just store the values, and terminate the command.
|
||||||
LOG("Specify");
|
logger.info().append("Specify");
|
||||||
step_rate_time_ = command_.specify_specs().step_rate_time;
|
step_rate_time_ = command_.specify_specs().step_rate_time;
|
||||||
head_unload_time_ = command_.specify_specs().head_unload_time;
|
head_unload_time_ = command_.specify_specs().head_unload_time;
|
||||||
head_load_time_ = command_.specify_specs().head_load_time;
|
head_load_time_ = command_.specify_specs().head_load_time;
|
||||||
@@ -733,7 +735,7 @@ void i8272::posit_event(int event_type) {
|
|||||||
goto wait_for_command;
|
goto wait_for_command;
|
||||||
|
|
||||||
sense_drive_status:
|
sense_drive_status:
|
||||||
LOG("Sense drive status");
|
logger.info().append("Sense drive status");
|
||||||
{
|
{
|
||||||
int drive = command_.target().drive;
|
int drive = command_.target().drive;
|
||||||
select_drive(drive);
|
select_drive(drive);
|
||||||
@@ -772,11 +774,13 @@ void i8272::posit_event(int event_type) {
|
|||||||
// Posts whatever is in result_stack_ as a result phase. Be aware that it is a stack, so the
|
// Posts whatever is in result_stack_ as a result phase. Be aware that it is a stack, so the
|
||||||
// last thing in it will be returned first.
|
// last thing in it will be returned first.
|
||||||
post_result:
|
post_result:
|
||||||
// LOGNBR(PADHEX(2) << "Result to " << int(command_[0] & 0x1f) << ", main " << int(main_status_) << "; ");
|
// {
|
||||||
// for(std::size_t c = 0; c < result_stack_.size(); c++) {
|
// auto line = logger.info();
|
||||||
// LOGNBR(" " << int(result_stack_[result_stack_.size() - 1 - c]));
|
// line.append("Result to %02x, main %02x", command_[0] & 0x1f, main_status_);
|
||||||
|
// for(std::size_t c = 0; c < result_stack_.size(); c++) {
|
||||||
|
// line.append(" %02x", result_stack_[result_stack_.size() - 1 - c]);
|
||||||
|
// }
|
||||||
// }
|
// }
|
||||||
// LOGNBR(std::endl);
|
|
||||||
|
|
||||||
// Set ready to send data to the processor, no longer in non-DMA execution phase.
|
// Set ready to send data to the processor, no longer in non-DMA execution phase.
|
||||||
is_executing_ = false;
|
is_executing_ = false;
|
||||||
|
@@ -8,15 +8,16 @@
|
|||||||
|
|
||||||
#include "z8530.hpp"
|
#include "z8530.hpp"
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define NDEBUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LOG_PREFIX "[SCC] "
|
|
||||||
#include "../../Outputs/Log.hpp"
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
using namespace Zilog::SCC;
|
using namespace Zilog::SCC;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::SCC> log;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void z8530::reset() {
|
void z8530::reset() {
|
||||||
// TODO.
|
// TODO.
|
||||||
}
|
}
|
||||||
@@ -53,7 +54,7 @@ std::uint8_t z8530::read(int address) {
|
|||||||
|
|
||||||
case 2: // Handled non-symmetrically between channels.
|
case 2: // Handled non-symmetrically between channels.
|
||||||
if(address & 1) {
|
if(address & 1) {
|
||||||
LOG("Unimplemented: register 2 status bits");
|
log.error().append("Unimplemented: register 2 status bits");
|
||||||
} else {
|
} else {
|
||||||
result = interrupt_vector_;
|
result = interrupt_vector_;
|
||||||
|
|
||||||
@@ -110,11 +111,11 @@ void z8530::write(int address, std::uint8_t value) {
|
|||||||
case 2: // Interrupt vector register; used only by Channel B.
|
case 2: // Interrupt vector register; used only by Channel B.
|
||||||
// So there's only one of these.
|
// So there's only one of these.
|
||||||
interrupt_vector_ = value;
|
interrupt_vector_ = value;
|
||||||
LOG("Interrupt vector set to " << PADHEX(2) << int(value));
|
log.info().append("Interrupt vector set to %d", value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 9: // Master interrupt and reset register; there is also only one of these.
|
case 9: // Master interrupt and reset register; there is also only one of these.
|
||||||
LOG("Master interrupt and reset register: " << PADHEX(2) << int(value));
|
log.info().append("Master interrupt and reset register: %02x", value);
|
||||||
master_interrupt_control_ = value;
|
master_interrupt_control_ = value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -151,7 +152,7 @@ uint8_t z8530::Channel::read(bool data, uint8_t pointer) {
|
|||||||
if(data) {
|
if(data) {
|
||||||
return data_;
|
return data_;
|
||||||
} else {
|
} else {
|
||||||
LOG("Control read from register " << int(pointer));
|
log.info().append("Control read from register %d", pointer);
|
||||||
// Otherwise, this is a control read...
|
// Otherwise, this is a control read...
|
||||||
switch(pointer) {
|
switch(pointer) {
|
||||||
default:
|
default:
|
||||||
@@ -236,10 +237,10 @@ void z8530::Channel::write(bool data, uint8_t pointer, uint8_t value) {
|
|||||||
data_ = value;
|
data_ = value;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
LOG("Control write: " << PADHEX(2) << int(value) << " to register " << int(pointer));
|
log.info().append("Control write: %02x to register %d", value, pointer);
|
||||||
switch(pointer) {
|
switch(pointer) {
|
||||||
default:
|
default:
|
||||||
LOG("Unrecognised control write: " << PADHEX(2) << int(value) << " to register " << int(pointer));
|
log.info().append("Unrecognised control write: %02x to register %d", value, pointer);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x0: // Write register 0 — CRC reset and other functions.
|
case 0x0: // Write register 0 — CRC reset and other functions.
|
||||||
@@ -247,13 +248,13 @@ void z8530::Channel::write(bool data, uint8_t pointer, uint8_t value) {
|
|||||||
switch(value >> 6) {
|
switch(value >> 6) {
|
||||||
default: /* Do nothing. */ break;
|
default: /* Do nothing. */ break;
|
||||||
case 1:
|
case 1:
|
||||||
LOG("TODO: reset Rx CRC checker.");
|
log.error().append("TODO: reset Rx CRC checker.");
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
LOG("TODO: reset Tx CRC checker.");
|
log.error().append("TODO: reset Tx CRC checker.");
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
LOG("TODO: reset Tx underrun/EOM latch.");
|
log.error().append("TODO: reset Tx underrun/EOM latch.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -261,24 +262,24 @@ void z8530::Channel::write(bool data, uint8_t pointer, uint8_t value) {
|
|||||||
switch((value >> 3)&7) {
|
switch((value >> 3)&7) {
|
||||||
default: /* Do nothing. */ break;
|
default: /* Do nothing. */ break;
|
||||||
case 2:
|
case 2:
|
||||||
// LOG("reset ext/status interrupts.");
|
// log.info().append("reset ext/status interrupts.");
|
||||||
external_status_interrupt_ = false;
|
external_status_interrupt_ = false;
|
||||||
external_interrupt_status_ = 0;
|
external_interrupt_status_ = 0;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
LOG("TODO: send abort (SDLC).");
|
log.error().append("TODO: send abort (SDLC).");
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
LOG("TODO: enable interrupt on next Rx character.");
|
log.error().append("TODO: enable interrupt on next Rx character.");
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
LOG("TODO: reset Tx interrupt pending.");
|
log.error().append("TODO: reset Tx interrupt pending.");
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
LOG("TODO: reset error.");
|
log.error().append("TODO: reset error.");
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
LOG("TODO: reset highest IUS.");
|
log.error().append("TODO: reset highest IUS.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -303,7 +304,7 @@ void z8530::Channel::write(bool data, uint8_t pointer, uint8_t value) {
|
|||||||
b1 = 1 => transmit buffer empty interrupt is enabled; 0 => it isn't.
|
b1 = 1 => transmit buffer empty interrupt is enabled; 0 => it isn't.
|
||||||
b0 = 1 => external interrupt is enabled; 0 => it isn't.
|
b0 = 1 => external interrupt is enabled; 0 => it isn't.
|
||||||
*/
|
*/
|
||||||
LOG("Interrupt mask: " << PADHEX(2) << int(value));
|
log.info().append("Interrupt mask: %02x", value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x2: // Write register 2 - interrupt vector.
|
case 0x2: // Write register 2 - interrupt vector.
|
||||||
@@ -318,9 +319,7 @@ void z8530::Channel::write(bool data, uint8_t pointer, uint8_t value) {
|
|||||||
case 2: receive_bit_count = 6; break;
|
case 2: receive_bit_count = 6; break;
|
||||||
case 3: receive_bit_count = 8; break;
|
case 3: receive_bit_count = 8; break;
|
||||||
}
|
}
|
||||||
LOG("Receive bit count: " << receive_bit_count);
|
log.info().append("Receive bit count: %d", receive_bit_count);
|
||||||
|
|
||||||
(void)receive_bit_count;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
b7,b6:
|
b7,b6:
|
||||||
|
@@ -22,6 +22,8 @@ namespace {
|
|||||||
constexpr unsigned int CRTCyclesPerLine = 1365;
|
constexpr unsigned int CRTCyclesPerLine = 1365;
|
||||||
constexpr unsigned int CRTCyclesDivider = 4;
|
constexpr unsigned int CRTCyclesDivider = 4;
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::TMS9918> logger;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <Personality personality>
|
template <Personality personality>
|
||||||
@@ -837,7 +839,7 @@ void Base<personality>::commit_register(int reg, uint8_t value) {
|
|||||||
Storage<personality>::solid_background_ = value & 0x20;
|
Storage<personality>::solid_background_ = value & 0x20;
|
||||||
Storage<personality>::sprites_enabled_ = !(value & 0x02);
|
Storage<personality>::sprites_enabled_ = !(value & 0x02);
|
||||||
if(value & 0x01) {
|
if(value & 0x01) {
|
||||||
LOG("TODO: Yamaha greyscale");
|
logger.error().append("TODO: Yamaha greyscale");
|
||||||
}
|
}
|
||||||
// b7: "1 = input on colour bus, enable mouse; 1 = output on colour bus, disable mouse" [documentation clearly in error]
|
// b7: "1 = input on colour bus, enable mouse; 1 = output on colour bus, disable mouse" [documentation clearly in error]
|
||||||
// b6: 1 = enable light pen
|
// b6: 1 = enable light pen
|
||||||
@@ -854,7 +856,7 @@ void Base<personality>::commit_register(int reg, uint8_t value) {
|
|||||||
// TODO: on the Yamaha, at least, tie this interrupt overtly to vertical state.
|
// TODO: on the Yamaha, at least, tie this interrupt overtly to vertical state.
|
||||||
|
|
||||||
if(value & 0x08) {
|
if(value & 0x08) {
|
||||||
LOG("TODO: Yamaha interlace mode");
|
logger.error().append("TODO: Yamaha interlace mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
// b7: 1 = 212 lines of pixels; 0 = 192
|
// b7: 1 = 212 lines of pixels; 0 = 192
|
||||||
@@ -918,7 +920,7 @@ void Base<personality>::commit_register(int reg, uint8_t value) {
|
|||||||
case 20:
|
case 20:
|
||||||
case 21:
|
case 21:
|
||||||
case 22:
|
case 22:
|
||||||
// LOG("TODO: Yamaha colour burst selection; " << PADHEX(2) << +value);
|
// logger.error().append("TODO: Yamaha colour burst selection; %02x", value);
|
||||||
// Documentation is "fill with 0s for no colour burst; magic pattern for colour burst"
|
// Documentation is "fill with 0s for no colour burst; magic pattern for colour burst"
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -1004,7 +1006,7 @@ void Base<personality>::commit_register(int reg, uint8_t value) {
|
|||||||
// Kill the command immediately if it's done in zero operations
|
// Kill the command immediately if it's done in zero operations
|
||||||
// (e.g. a line of length 0).
|
// (e.g. a line of length 0).
|
||||||
if(!Storage<personality>::command_ && (value >> 4)) {
|
if(!Storage<personality>::command_ && (value >> 4)) {
|
||||||
LOG("TODO: Yamaha command " << PADHEX(2) << +value);
|
logger.error().append("TODO: Yamaha command %02x", value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seed timing information if a command was found.
|
// Seed timing information if a command was found.
|
||||||
|
@@ -8,11 +8,6 @@
|
|||||||
|
|
||||||
#include "IWM.hpp"
|
#include "IWM.hpp"
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define NDEBUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LOG_PREFIX "[IWM] "
|
|
||||||
#include "../../Outputs/Log.hpp"
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
using namespace Apple;
|
using namespace Apple;
|
||||||
@@ -27,6 +22,8 @@ namespace {
|
|||||||
constexpr int Q6 = 1 << 6;
|
constexpr int Q6 = 1 << 6;
|
||||||
constexpr int Q7 = 1 << 7;
|
constexpr int Q7 = 1 << 7;
|
||||||
constexpr int SEL = 1 << 8; /* This is an additional input, not available on a Disk II, with a confusingly-similar name to SELECT but a distinct purpose. */
|
constexpr int SEL = 1 << 8; /* This is an additional input, not available on a Disk II, with a confusingly-similar name to SELECT but a distinct purpose. */
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::IWM> logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
IWM::IWM(int clock_rate) :
|
IWM::IWM(int clock_rate) :
|
||||||
@@ -55,7 +52,7 @@ uint8_t IWM::read(int address) {
|
|||||||
|
|
||||||
switch(state_ & (Q6 | Q7 | ENABLE)) {
|
switch(state_ & (Q6 | Q7 | ENABLE)) {
|
||||||
default:
|
default:
|
||||||
LOG("Invalid read\n");
|
logger.info().append("Invalid read\n");
|
||||||
return 0xff;
|
return 0xff;
|
||||||
|
|
||||||
// "Read all 1s".
|
// "Read all 1s".
|
||||||
@@ -68,9 +65,9 @@ uint8_t IWM::read(int address) {
|
|||||||
|
|
||||||
if(data_register_ & 0x80) {
|
if(data_register_ & 0x80) {
|
||||||
data_register_ = 0;
|
data_register_ = 0;
|
||||||
// LOG("Reading data: " << PADHEX(2) << int(result));
|
// logger.info().append("Reading data: %02x", result);
|
||||||
}
|
}
|
||||||
// LOG("Reading data register: " << PADHEX(2) << int(result));
|
// logger.info().append("Reading data register: %02x", result);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -103,7 +100,7 @@ uint8_t IWM::read(int address) {
|
|||||||
bit 6: 1 = write state (0 = underrun has occurred; 1 = no underrun so far).
|
bit 6: 1 = write state (0 = underrun has occurred; 1 = no underrun so far).
|
||||||
bit 7: 1 = write data buffer ready for data (1 = ready; 0 = busy).
|
bit 7: 1 = write data buffer ready for data (1 = ready; 0 = busy).
|
||||||
*/
|
*/
|
||||||
// LOG("Reading write handshake: " << PADHEX(2) << int(0x3f | write_handshake_));
|
// logger.info().append("Reading write handshake: %02x", 0x3f | write_handshake_);
|
||||||
return 0x3f | write_handshake_;
|
return 0x3f | write_handshake_;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,9 +131,9 @@ void IWM::write(int address, uint8_t input) {
|
|||||||
|
|
||||||
// TEMPORARY. To test for the unimplemented mode.
|
// TEMPORARY. To test for the unimplemented mode.
|
||||||
if(input&0x2) {
|
if(input&0x2) {
|
||||||
LOG("Switched to asynchronous mode");
|
logger.info().append("Switched to asynchronous mode");
|
||||||
} else {
|
} else {
|
||||||
LOG("Switched to synchronous mode");
|
logger.info().append("Switched to synchronous mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(mode_ & 0x18) {
|
switch(mode_ & 0x18) {
|
||||||
@@ -145,8 +142,8 @@ void IWM::write(int address, uint8_t input) {
|
|||||||
case 0x10: bit_length_ = Cycles(32); break; // slow mode, 8Mhz
|
case 0x10: bit_length_ = Cycles(32); break; // slow mode, 8Mhz
|
||||||
case 0x18: bit_length_ = Cycles(16); break; // fast mode, 8Mhz
|
case 0x18: bit_length_ = Cycles(16); break; // fast mode, 8Mhz
|
||||||
}
|
}
|
||||||
LOG("Mode is now " << PADHEX(2) << int(mode_));
|
logger.info().append("Mode is now %02x", mode_);
|
||||||
LOG("New bit length is " << std::dec << bit_length_.as_integral());
|
logger.info().append("New bit length is %d", bit_length_.as<int>());
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Q7|Q6|ENABLE: // Write data register.
|
case Q7|Q6|ENABLE: // Write data register.
|
||||||
@@ -260,7 +257,7 @@ void IWM::run_for(const Cycles cycles) {
|
|||||||
drives_[active_drive_]->run_for(Cycles(1));
|
drives_[active_drive_]->run_for(Cycles(1));
|
||||||
++cycles_since_shift_;
|
++cycles_since_shift_;
|
||||||
if(cycles_since_shift_ == bit_length_ + error_margin) {
|
if(cycles_since_shift_ == bit_length_ + error_margin) {
|
||||||
// LOG("Shifting 0 at " << std::dec << cycles_since_shift_.as_integral());
|
// logger.info().append("Shifting 0 at %d ", cycles_since_shift_.as<int>());
|
||||||
propose_shift(0);
|
propose_shift(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,11 +291,11 @@ void IWM::run_for(const Cycles cycles) {
|
|||||||
if(!(write_handshake_ & 0x80)) {
|
if(!(write_handshake_ & 0x80)) {
|
||||||
shift_register_ = next_output_;
|
shift_register_ = next_output_;
|
||||||
output_bits_remaining_ = 8;
|
output_bits_remaining_ = 8;
|
||||||
// LOG("Next byte: " << PADHEX(2) << int(shift_register_));
|
// logger.info().append("Next byte: %02x", shift_register_);
|
||||||
} else {
|
} else {
|
||||||
write_handshake_ &= ~0x40;
|
write_handshake_ &= ~0x40;
|
||||||
if(drives_[active_drive_]) drives_[active_drive_]->end_writing();
|
if(drives_[active_drive_]) drives_[active_drive_]->end_writing();
|
||||||
LOG("Overrun; done.");
|
logger.info().append("Overrun; done.");
|
||||||
output_bits_remaining_ = 1;
|
output_bits_remaining_ = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,7 +351,7 @@ void IWM::select_shift_mode() {
|
|||||||
shift_register_ = next_output_;
|
shift_register_ = next_output_;
|
||||||
write_handshake_ |= 0x80 | 0x40;
|
write_handshake_ |= 0x80 | 0x40;
|
||||||
output_bits_remaining_ = 8;
|
output_bits_remaining_ = 8;
|
||||||
LOG("Seeding output with " << PADHEX(2) << int(shift_register_));
|
logger.info().append("Seeding output with %02x", shift_register_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -368,7 +365,7 @@ void IWM::process_event(const Storage::Disk::Drive::Event &event) {
|
|||||||
switch(event.type) {
|
switch(event.type) {
|
||||||
case Storage::Disk::Track::Event::IndexHole: return;
|
case Storage::Disk::Track::Event::IndexHole: return;
|
||||||
case Storage::Disk::Track::Event::FluxTransition:
|
case Storage::Disk::Track::Event::FluxTransition:
|
||||||
// LOG("Shifting 1 at " << std::dec << cycles_since_shift_.as_integral());
|
// logger.info().append("Shifting 1 at %d", cycles_since_shift_.as<int>());
|
||||||
propose_shift(1);
|
propose_shift(1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -377,8 +374,8 @@ void IWM::process_event(const Storage::Disk::Drive::Event &event) {
|
|||||||
void IWM::propose_shift(uint8_t bit) {
|
void IWM::propose_shift(uint8_t bit) {
|
||||||
// TODO: synchronous mode.
|
// TODO: synchronous mode.
|
||||||
|
|
||||||
// LOG("Shifting at " << std::dec << cycles_since_shift_.as_integral());
|
// logger.info().append("Shifting at %d", cycles_since_shift_.as<int>());
|
||||||
// LOG("Shifting input");
|
// logger.info().append("Shifting input");
|
||||||
|
|
||||||
// See above for text from the IWM patent, column 7, around line 35 onwards.
|
// See above for text from the IWM patent, column 7, around line 35 onwards.
|
||||||
// The error_margin here implements the 'before' part of that contract.
|
// The error_margin here implements the 'before' part of that contract.
|
||||||
@@ -393,7 +390,7 @@ void IWM::propose_shift(uint8_t bit) {
|
|||||||
|
|
||||||
shift_register_ = uint8_t((shift_register_ << 1) | bit);
|
shift_register_ = uint8_t((shift_register_ << 1) | bit);
|
||||||
if(shift_register_ & 0x80) {
|
if(shift_register_ & 0x80) {
|
||||||
// if(data_register_ & 0x80) LOG("Byte missed");
|
// if(data_register_ & 0x80) logger.info().append("Byte missed");
|
||||||
data_register_ = shift_register_;
|
data_register_ = shift_register_;
|
||||||
shift_register_ = 0;
|
shift_register_ = 0;
|
||||||
}
|
}
|
||||||
|
@@ -8,19 +8,18 @@
|
|||||||
|
|
||||||
#include "Executor.hpp"
|
#include "Executor.hpp"
|
||||||
|
|
||||||
|
#include "../../Machines/Utility/MemoryFuzzer.hpp"
|
||||||
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "../../Machines/Utility/MemoryFuzzer.hpp"
|
|
||||||
|
|
||||||
#define LOG_PREFIX "[M50740] "
|
|
||||||
#include "../../Outputs/Log.hpp"
|
|
||||||
|
|
||||||
using namespace InstructionSet::M50740;
|
using namespace InstructionSet::M50740;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr int port_remap[] = {0, 1, 2, 0, 3};
|
constexpr int port_remap[] = {0, 1, 2, 0, 3};
|
||||||
|
Log::Logger<Log::Source::M50740> logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
Executor::Executor(PortHandler &port_handler) : port_handler_(port_handler) {
|
Executor::Executor(PortHandler &port_handler) : port_handler_(port_handler) {
|
||||||
@@ -83,13 +82,13 @@ uint8_t Executor::read(uint16_t address) {
|
|||||||
port_handler_.run_ports_for(cycles_since_port_handler_.flush<Cycles>());
|
port_handler_.run_ports_for(cycles_since_port_handler_.flush<Cycles>());
|
||||||
switch(address) {
|
switch(address) {
|
||||||
default:
|
default:
|
||||||
LOG("Unrecognised read from " << PADHEX(4) << address);
|
logger.error().append("Unrecognised read from %02x", address);
|
||||||
return 0xff;
|
return 0xff;
|
||||||
|
|
||||||
// "Port R"; sixteen four-bit ports
|
// "Port R"; sixteen four-bit ports
|
||||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
||||||
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||||
LOG("Unimplemented Port R read from " << PADHEX(4) << address);
|
logger.error().append("Unimplemented Port R read from %04x", address);
|
||||||
return 0x00;
|
return 0x00;
|
||||||
|
|
||||||
// Ports P0–P3.
|
// Ports P0–P3.
|
||||||
@@ -134,7 +133,7 @@ void Executor::write(uint16_t address, uint8_t value) {
|
|||||||
|
|
||||||
// ROM 'writes' are almost as easy (albeit unexpected).
|
// ROM 'writes' are almost as easy (albeit unexpected).
|
||||||
if(address >= 0x100) {
|
if(address >= 0x100) {
|
||||||
LOG("Attempted ROM write of " << PADHEX(2) << value << " to " << PADHEX(4) << address);
|
logger.info().append("Attempted ROM write of %02x to %04x", value, address);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,13 +142,13 @@ void Executor::write(uint16_t address, uint8_t value) {
|
|||||||
|
|
||||||
switch(address) {
|
switch(address) {
|
||||||
default:
|
default:
|
||||||
LOG("Unrecognised write of " << PADHEX(2) << value << " to " << PADHEX(4) << address);
|
logger.error().append("Unrecognised write of %02x to %04x", value, address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// "Port R"; sixteen four-bit ports
|
// "Port R"; sixteen four-bit ports
|
||||||
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
case 0xd0: case 0xd1: case 0xd2: case 0xd3: case 0xd4: case 0xd5: case 0xd6: case 0xd7:
|
||||||
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
case 0xd8: case 0xd9: case 0xda: case 0xdb: case 0xdc: case 0xdd: case 0xde: case 0xdf:
|
||||||
LOG("Unimplemented Port R write of " << PADHEX(2) << value << " from " << PADHEX(4) << address);
|
logger.error().append("Unimplemented Port R write of %02x to %04x", value, address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Ports P0–P3.
|
// Ports P0–P3.
|
||||||
@@ -779,7 +778,7 @@ template <Operation operation> void Executor::perform(uint8_t *operand [[maybe_u
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG("Unimplemented operation: " << operation);
|
logger.error().append("Unimplemented operation: %d", operation);
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
#undef set_nz
|
#undef set_nz
|
||||||
@@ -823,13 +822,13 @@ inline void Executor::subtract_duration(int duration) {
|
|||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case 0x04:
|
case 0x04:
|
||||||
LOG("TODO: Timer X; Pulse output mode");
|
logger.error().append("TODO: Timer X; Pulse output mode");
|
||||||
break;
|
break;
|
||||||
case 0x08:
|
case 0x08:
|
||||||
LOG("TODO: Timer X; Event counter mode");
|
logger.error().append("TODO: Timer X; Event counter mode");
|
||||||
break;
|
break;
|
||||||
case 0x0c:
|
case 0x0c:
|
||||||
LOG("TODO: Timer X; Pulse width measurement mode");
|
logger.error().append("TODO: Timer X; Pulse width measurement mode");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,8 +18,6 @@
|
|||||||
#include "../Utility/MemoryPacker.hpp"
|
#include "../Utility/MemoryPacker.hpp"
|
||||||
#include "../Utility/MemoryFuzzer.hpp"
|
#include "../Utility/MemoryFuzzer.hpp"
|
||||||
|
|
||||||
//#define NDEBUG
|
|
||||||
#define LOG_PREFIX "[Amiga] "
|
|
||||||
#include "../../Outputs/Log.hpp"
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
#include "Chipset.hpp"
|
#include "Chipset.hpp"
|
||||||
@@ -35,6 +33,8 @@ namespace {
|
|||||||
constexpr int PALClockRate = 7'093'790;
|
constexpr int PALClockRate = 7'093'790;
|
||||||
//constexpr int NTSCClockRate = 7'159'090;
|
//constexpr int NTSCClockRate = 7'159'090;
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::Amiga> logger;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Amiga {
|
namespace Amiga {
|
||||||
@@ -95,7 +95,7 @@ class ConcreteMachine:
|
|||||||
// Check for assertion of reset.
|
// Check for assertion of reset.
|
||||||
if(cycle.operation & CPU::MC68000::Operation::Reset) {
|
if(cycle.operation & CPU::MC68000::Operation::Reset) {
|
||||||
memory_.reset();
|
memory_.reset();
|
||||||
LOG("Reset; PC is around " << PADHEX(8) << mc68000_.get_state().registers.program_counter);
|
logger.info().append("Reset; PC is around %08x", mc68000_.get_state().registers.program_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Autovector interrupts.
|
// Autovector interrupts.
|
||||||
@@ -142,7 +142,7 @@ class ConcreteMachine:
|
|||||||
if(select_b) chipset_.cia_b.write(reg, cycle.value8_high());
|
if(select_b) chipset_.cia_b.write(reg, cycle.value8_high());
|
||||||
}
|
}
|
||||||
|
|
||||||
// LOG("CIA " << (((address >> 12) & 3)^3) << " " << (operation & Microcycle::Read ? "read " : "write ") << std::dec << (reg & 0xf) << " of " << PADHEX(4) << +cycle.value16());
|
// logger.info().append("CIA %d %s %d of %04x", ((address >> 12) & 3)^3, operation & Microcycle::Read ? "read" : "write", reg & 0xf, cycle.value16());
|
||||||
} else if(address >= 0xdf'f000 && address <= 0xdf'f1be) {
|
} else if(address >= 0xdf'f000 && address <= 0xdf'f1be) {
|
||||||
chipset_.perform(cycle);
|
chipset_.perform(cycle);
|
||||||
} else if(address >= 0xe8'0000 && address < 0xe9'0000) {
|
} else if(address >= 0xe8'0000 && address < 0xe9'0000) {
|
||||||
@@ -158,9 +158,9 @@ class ConcreteMachine:
|
|||||||
cycle.set_value16(0xffff);
|
cycle.set_value16(0xffff);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't log for the region that is definitely just ROM this machine doesn't have.
|
// Log only for the region that is definitely not just ROM this machine doesn't have.
|
||||||
if(address < 0xf0'0000) {
|
if(address < 0xf0'0000) {
|
||||||
LOG("Unmapped " << (cycle.operation & CPU::MC68000::Operation::Read ? "read from " : "write to ") << PADHEX(6) << ((*cycle.address)&0xffffff) << " of " << cycle.value16());
|
logger.error().append("Unmapped %s %06x of %04x", cycle.operation & CPU::MC68000::Operation::Read ? "read from " : "write to ", (*cycle.address)&0xffffff, cycle.value16());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -10,9 +10,6 @@
|
|||||||
|
|
||||||
#include "Flags.hpp"
|
#include "Flags.hpp"
|
||||||
|
|
||||||
#define LOG_PREFIX "[Audio] "
|
|
||||||
#include "../../Outputs/Log.hpp"
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
@@ -9,20 +9,16 @@
|
|||||||
#include "Blitter.hpp"
|
#include "Blitter.hpp"
|
||||||
|
|
||||||
#include "Minterms.hpp"
|
#include "Minterms.hpp"
|
||||||
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define NDEBUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LOG_PREFIX "[Blitter] "
|
|
||||||
#include "../../Outputs/Log.hpp"
|
|
||||||
|
|
||||||
using namespace Amiga;
|
using namespace Amiga;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::AmigaBlitter> logger;
|
||||||
|
|
||||||
/// @returns Either the final carry flag or the output nibble when using fill mode given that it either @c is_exclusive fill mode, or isn't;
|
/// @returns Either the final carry flag or the output nibble when using fill mode given that it either @c is_exclusive fill mode, or isn't;
|
||||||
/// and the specified initial @c carry and input @c nibble.
|
/// and the specified initial @c carry and input @c nibble.
|
||||||
template <bool wants_carry> constexpr uint32_t fill_nibble(bool is_exclusive, uint8_t carry, uint8_t nibble) {
|
template <bool wants_carry> constexpr uint32_t fill_nibble(bool is_exclusive, uint8_t carry, uint8_t nibble) {
|
||||||
@@ -130,18 +126,18 @@ void Blitter<record_bus>::set_control(int index, uint16_t value) {
|
|||||||
sequencer_.set_control(value >> 8);
|
sequencer_.set_control(value >> 8);
|
||||||
}
|
}
|
||||||
shifts_[index] = value >> 12;
|
shifts_[index] = value >> 12;
|
||||||
LOG("Set control " << index << " to " << PADHEX(4) << value);
|
logger.info().append("Set control %d to %04x", index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool record_bus>
|
template <bool record_bus>
|
||||||
void Blitter<record_bus>::set_first_word_mask(uint16_t value) {
|
void Blitter<record_bus>::set_first_word_mask(uint16_t value) {
|
||||||
LOG("Set first word mask: " << PADHEX(4) << value);
|
logger.info().append("Set first word mask: %04x", value);
|
||||||
a_mask_[0] = value;
|
a_mask_[0] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <bool record_bus>
|
template <bool record_bus>
|
||||||
void Blitter<record_bus>::set_last_word_mask(uint16_t value) {
|
void Blitter<record_bus>::set_last_word_mask(uint16_t value) {
|
||||||
LOG("Set last word mask: " << PADHEX(4) << value);
|
logger.info().append("Set last word mask: %04x", value);
|
||||||
a_mask_[1] = value;
|
a_mask_[1] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +149,7 @@ void Blitter<record_bus>::set_size(uint16_t value) {
|
|||||||
if(!width_) width_ = 0x40;
|
if(!width_) width_ = 0x40;
|
||||||
height_ = value >> 6;
|
height_ = value >> 6;
|
||||||
if(!height_) height_ = 1024;
|
if(!height_) height_ = 1024;
|
||||||
LOG("Set size to " << std::dec << width_ << ", " << height_);
|
logger.info().append("Set size to %d, %d", width_, height_);
|
||||||
|
|
||||||
// Current assumption: writing this register informs the
|
// Current assumption: writing this register informs the
|
||||||
// blitter that it should treat itself as about to start a new line.
|
// blitter that it should treat itself as about to start a new line.
|
||||||
@@ -161,24 +157,24 @@ void Blitter<record_bus>::set_size(uint16_t value) {
|
|||||||
|
|
||||||
template <bool record_bus>
|
template <bool record_bus>
|
||||||
void Blitter<record_bus>::set_minterms(uint16_t value) {
|
void Blitter<record_bus>::set_minterms(uint16_t value) {
|
||||||
LOG("Set minterms " << PADHEX(4) << value);
|
logger.info().append("Set minterms: %02x", value & 0xff);
|
||||||
minterms_ = value & 0xff;
|
minterms_ = value & 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
//template <bool record_bus>
|
//template <bool record_bus>
|
||||||
//void Blitter<record_bus>::set_vertical_size([[maybe_unused]] uint16_t value) {
|
//void Blitter<record_bus>::set_vertical_size([[maybe_unused]] uint16_t value) {
|
||||||
// LOG("Set vertical size " << PADHEX(4) << value);
|
// logger.info().append("Set vertical size %04x", value);
|
||||||
// // TODO. This is ECS only, I think. Ditto set_horizontal_size.
|
// // TODO. This is ECS only, I think. Ditto set_horizontal_size.
|
||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//template <bool record_bus>
|
//template <bool record_bus>
|
||||||
//void Blitter<record_bus>::set_horizontal_size([[maybe_unused]] uint16_t value) {
|
//void Blitter<record_bus>::set_horizontal_size([[maybe_unused]] uint16_t value) {
|
||||||
// LOG("Set horizontal size " << PADHEX(4) << value);
|
// logger.info().append("Set horizontal size %04x", value);
|
||||||
//}
|
//}
|
||||||
|
|
||||||
template <bool record_bus>
|
template <bool record_bus>
|
||||||
void Blitter<record_bus>::set_data(int channel, uint16_t value) {
|
void Blitter<record_bus>::set_data(int channel, uint16_t value) {
|
||||||
LOG("Set data " << channel << " to " << PADHEX(4) << value);
|
logger.info().append("Set data %d to %04x", channel, value);
|
||||||
|
|
||||||
// Ugh, backed myself into a corner. TODO: clean.
|
// Ugh, backed myself into a corner. TODO: clean.
|
||||||
switch(channel) {
|
switch(channel) {
|
||||||
@@ -193,7 +189,7 @@ template <bool record_bus>
|
|||||||
uint16_t Blitter<record_bus>::get_status() {
|
uint16_t Blitter<record_bus>::get_status() {
|
||||||
const uint16_t result =
|
const uint16_t result =
|
||||||
(not_zero_flag_ ? 0x0000 : 0x2000) | (height_ ? 0x4000 : 0x0000);
|
(not_zero_flag_ ? 0x0000 : 0x2000) | (height_ ? 0x4000 : 0x0000);
|
||||||
LOG("Returned status of " << result);
|
logger.info().append("Returned status of %04x", result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,17 +8,16 @@
|
|||||||
|
|
||||||
#include "Chipset.hpp"
|
#include "Chipset.hpp"
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define NDEBUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LOG_PREFIX "[Amiga chipset] "
|
|
||||||
#include "../../Outputs/Log.hpp"
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Log::Logger<Log::Source::AmigaChipset> logger;
|
||||||
|
}
|
||||||
|
|
||||||
using namespace Amiga;
|
using namespace Amiga;
|
||||||
|
|
||||||
#define DMA_CONSTRUCT *this, reinterpret_cast<uint16_t *>(map.chip_ram.data()), map.chip_ram.size() >> 1
|
#define DMA_CONSTRUCT *this, reinterpret_cast<uint16_t *>(map.chip_ram.data()), map.chip_ram.size() >> 1
|
||||||
@@ -869,16 +868,16 @@ void Chipset::write(uint32_t address, uint16_t value, bool allow_conversion) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x02a: // VPOSW
|
case 0x02a: // VPOSW
|
||||||
LOG("TODO: write vertical position high " << PADHEX(4) << value);
|
logger.error().append("TODO: write vertical position high %04x", value);
|
||||||
break;
|
break;
|
||||||
case 0x02c: // VHPOSW
|
case 0x02c: // VHPOSW
|
||||||
LOG("TODO: write vertical position low " << PADHEX(4) << value);
|
logger.error().append("TODO: write vertical position low %04x", value);
|
||||||
is_long_field_ = value & 0x8000;
|
is_long_field_ = value & 0x8000;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Joystick/mouse input.
|
// Joystick/mouse input.
|
||||||
case 0x034: // POTGO
|
case 0x034: // POTGO
|
||||||
// LOG("TODO: pot port start");
|
// logger.error().append("TODO: pot port start");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Disk DMA and control.
|
// Disk DMA and control.
|
||||||
@@ -887,11 +886,11 @@ void Chipset::write(uint32_t address, uint16_t value, bool allow_conversion) {
|
|||||||
case 0x024: disk_.set_length(value); break; // DSKLEN
|
case 0x024: disk_.set_length(value); break; // DSKLEN
|
||||||
|
|
||||||
case 0x026: // DSKDAT
|
case 0x026: // DSKDAT
|
||||||
LOG("TODO: disk DMA; " << PADHEX(4) << value << " to " << address);
|
logger.error().append("TODO: disk DMA; %04x to %04x", value, address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x09e: // ADKCON
|
case 0x09e: // ADKCON
|
||||||
LOG("Write disk control");
|
logger.info().append("Write disk control");
|
||||||
ApplySetClear(paula_disk_control_, 0x7fff);
|
ApplySetClear(paula_disk_control_, 0x7fff);
|
||||||
|
|
||||||
disk_controller_.set_control(paula_disk_control_);
|
disk_controller_.set_control(paula_disk_control_);
|
||||||
@@ -905,7 +904,7 @@ void Chipset::write(uint32_t address, uint16_t value, bool allow_conversion) {
|
|||||||
|
|
||||||
// Refresh.
|
// Refresh.
|
||||||
case 0x028: // REFPTR
|
case 0x028: // REFPTR
|
||||||
LOG("TODO (maybe): refresh; " << PADHEX(4) << value << " to " << PADHEX(8) << address);
|
logger.info().append("TODO (maybe): refresh; %04x to %08x", value, address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Serial port.
|
// Serial port.
|
||||||
@@ -944,7 +943,7 @@ void Chipset::write(uint32_t address, uint16_t value, bool allow_conversion) {
|
|||||||
break;
|
break;
|
||||||
case 0x092: // DDFSTRT
|
case 0x092: // DDFSTRT
|
||||||
if(fetch_window_[0] != value) {
|
if(fetch_window_[0] != value) {
|
||||||
LOG("Fetch window start set to " << std::dec << value);
|
logger.info().append("Fetch window start set to %d", value);
|
||||||
}
|
}
|
||||||
fetch_window_[0] = value & 0xfe;
|
fetch_window_[0] = value & 0xfe;
|
||||||
break;
|
break;
|
||||||
@@ -952,7 +951,7 @@ void Chipset::write(uint32_t address, uint16_t value, bool allow_conversion) {
|
|||||||
// TODO: something in my interpretation of ddfstart and ddfstop
|
// TODO: something in my interpretation of ddfstart and ddfstop
|
||||||
// means a + 8 is needed below for high-res displays. Investigate.
|
// means a + 8 is needed below for high-res displays. Investigate.
|
||||||
if(fetch_window_[1] != value) {
|
if(fetch_window_[1] != value) {
|
||||||
LOG("Fetch window stop set to " << std::dec << fetch_window_[1]);
|
logger.info().append("Fetch window stop set to %d", fetch_window_[1]);
|
||||||
}
|
}
|
||||||
fetch_window_[1] = value & 0xfe;
|
fetch_window_[1] = value & 0xfe;
|
||||||
break;
|
break;
|
||||||
@@ -989,7 +988,7 @@ void Chipset::write(uint32_t address, uint16_t value, bool allow_conversion) {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x106: // BPLCON3 (ECS)
|
case 0x106: // BPLCON3 (ECS)
|
||||||
LOG("TODO: Bitplane control; " << PADHEX(4) << value << " to " << PADHEX(8) << address);
|
logger.error().append("TODO: Bitplane control; %04x to %08x", value, address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x108: bitplanes_.set_modulo<0>(value); break; // BPL1MOD
|
case 0x108: bitplanes_.set_modulo<0>(value); break; // BPL1MOD
|
||||||
@@ -1001,7 +1000,7 @@ void Chipset::write(uint32_t address, uint16_t value, bool allow_conversion) {
|
|||||||
case 0x116:
|
case 0x116:
|
||||||
case 0x118:
|
case 0x118:
|
||||||
case 0x11a:
|
case 0x11a:
|
||||||
LOG("TODO: Bitplane data; " << PADHEX(4) << value << " to " << PADHEX(8) << address);
|
logger.error().append("TODO: Bitplane data; %04x to %08x", value, address);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Blitter.
|
// Blitter.
|
||||||
@@ -1056,7 +1055,7 @@ void Chipset::write(uint32_t address, uint16_t value, bool allow_conversion) {
|
|||||||
case 0x088: copper_.reload<0>(); break;
|
case 0x088: copper_.reload<0>(); break;
|
||||||
case 0x08a: copper_.reload<1>(); break;
|
case 0x08a: copper_.reload<1>(); break;
|
||||||
case 0x08c:
|
case 0x08c:
|
||||||
LOG("TODO: coprocessor instruction fetch identity " << PADHEX(4) << value);
|
logger.error().append("TODO: coprocessor instruction fetch identity %04x", value);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Sprites.
|
// Sprites.
|
||||||
@@ -1144,15 +1143,15 @@ uint16_t Chipset::read(uint32_t address, bool allow_conversion) {
|
|||||||
case 0x00c: return joystick(0).get_position(); // JOY1DAT
|
case 0x00c: return joystick(0).get_position(); // JOY1DAT
|
||||||
|
|
||||||
case 0x016: // POTGOR / POTINP
|
case 0x016: // POTGOR / POTINP
|
||||||
// LOG("TODO: pot port read");
|
// logger.error().append("TODO: pot port read");
|
||||||
return 0xff00;
|
return 0xff00;
|
||||||
|
|
||||||
// Disk DMA and control.
|
// Disk DMA and control.
|
||||||
case 0x010: // ADKCONR
|
case 0x010: // ADKCONR
|
||||||
LOG("Read disk control");
|
logger.info().append("Read disk control");
|
||||||
return paula_disk_control_;
|
return paula_disk_control_;
|
||||||
case 0x01a: // DSKBYTR
|
case 0x01a: // DSKBYTR
|
||||||
LOG("TODO: disk status");
|
logger.error().append("TODO: disk status");
|
||||||
assert(false); // Not yet implemented.
|
assert(false); // Not yet implemented.
|
||||||
return 0xffff;
|
return 0xffff;
|
||||||
|
|
||||||
@@ -1194,7 +1193,7 @@ Chipset::CIAAHandler::CIAAHandler(MemoryMap &map, DiskController &controller, Mo
|
|||||||
void Chipset::CIAAHandler::set_port_output(MOS::MOS6526::Port port, uint8_t value) {
|
void Chipset::CIAAHandler::set_port_output(MOS::MOS6526::Port port, uint8_t value) {
|
||||||
if(port) {
|
if(port) {
|
||||||
// CIA A, Port B: Parallel port output.
|
// CIA A, Port B: Parallel port output.
|
||||||
LOG("TODO: parallel output " << PADHEX(2) << +value);
|
logger.info().append("TODO: parallel output %02x", value);
|
||||||
} else {
|
} else {
|
||||||
// CIA A, Port A:
|
// CIA A, Port A:
|
||||||
//
|
//
|
||||||
@@ -1216,7 +1215,7 @@ void Chipset::CIAAHandler::set_port_output(MOS::MOS6526::Port port, uint8_t valu
|
|||||||
|
|
||||||
uint8_t Chipset::CIAAHandler::get_port_input(MOS::MOS6526::Port port) {
|
uint8_t Chipset::CIAAHandler::get_port_input(MOS::MOS6526::Port port) {
|
||||||
if(port) {
|
if(port) {
|
||||||
LOG("TODO: parallel input?");
|
logger.info().append("TODO: parallel input?");
|
||||||
} else {
|
} else {
|
||||||
// Use the mouse as FIR0, the joystick as FIR1.
|
// Use the mouse as FIR0, the joystick as FIR1.
|
||||||
return
|
return
|
||||||
@@ -1256,12 +1255,12 @@ void Chipset::CIABHandler::set_port_output(MOS::MOS6526::Port port, uint8_t valu
|
|||||||
// b2: SEL
|
// b2: SEL
|
||||||
// b1: POUT
|
// b1: POUT
|
||||||
// b0: BUSY
|
// b0: BUSY
|
||||||
LOG("TODO: DTR/RTS/etc: " << PADHEX(2) << +value);
|
logger.error().append("TODO: DTR/RTS/etc: %02x", value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t Chipset::CIABHandler::get_port_input(MOS::MOS6526::Port) {
|
uint8_t Chipset::CIABHandler::get_port_input(MOS::MOS6526::Port) {
|
||||||
LOG("Unexpected: input for CIA B");
|
logger.error().append("Unexpected: input for CIA B");
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,15 +6,10 @@
|
|||||||
// Copyright © 2021 Thomas Harte. All rights reserved.
|
// Copyright © 2021 Thomas Harte. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define NDEBUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LOG_PREFIX "[Copper] "
|
|
||||||
#include "../../Outputs/Log.hpp"
|
|
||||||
|
|
||||||
#include "Chipset.hpp"
|
|
||||||
#include "Copper.hpp"
|
#include "Copper.hpp"
|
||||||
|
#include "Chipset.hpp"
|
||||||
|
|
||||||
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
using namespace Amiga;
|
using namespace Amiga;
|
||||||
|
|
||||||
@@ -31,6 +26,8 @@ bool satisfies_raster(uint16_t position, uint16_t blitter_status, uint16_t *inst
|
|||||||
return (position & mask) >= (instruction[0] & mask);
|
return (position & mask) >= (instruction[0] & mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::AmigaCopper> logger;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -85,7 +82,7 @@ bool Copper::advance_dma(uint16_t position, uint16_t blitter_status) {
|
|||||||
|
|
||||||
case State::Waiting:
|
case State::Waiting:
|
||||||
if(satisfies_raster(position, blitter_status, instruction_)) {
|
if(satisfies_raster(position, blitter_status, instruction_)) {
|
||||||
LOG("Unblocked waiting for " << PADHEX(4) << instruction_[0] << " at " << PADHEX(4) << position << " with mask " << PADHEX(4) << (instruction_[1] & 0x7ffe));
|
logger.info().append("Unblocked waiting for %04x at %04x with mask %04x", instruction_[0], position, instruction_[1] & 0x7ffe);
|
||||||
state_ = State::FetchFirstWord;
|
state_ = State::FetchFirstWord;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -94,7 +91,7 @@ bool Copper::advance_dma(uint16_t position, uint16_t blitter_status) {
|
|||||||
instruction_[0] = ram_[address_ & ram_mask_];
|
instruction_[0] = ram_[address_ & ram_mask_];
|
||||||
++address_;
|
++address_;
|
||||||
state_ = State::FetchSecondWord;
|
state_ = State::FetchSecondWord;
|
||||||
LOG("First word fetch at " << PADHEX(4) << position);
|
logger.info().append("First word fetch at %04x", position);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case State::FetchSecondWord: {
|
case State::FetchSecondWord: {
|
||||||
@@ -105,7 +102,7 @@ bool Copper::advance_dma(uint16_t position, uint16_t blitter_status) {
|
|||||||
// Read in the second instruction word.
|
// Read in the second instruction word.
|
||||||
instruction_[1] = ram_[address_ & ram_mask_];
|
instruction_[1] = ram_[address_ & ram_mask_];
|
||||||
++address_;
|
++address_;
|
||||||
LOG("Second word fetch at " << PADHEX(4) << position);
|
logger.info().append("Second word fetch at %04x", position);
|
||||||
|
|
||||||
// Check for a MOVE.
|
// Check for a MOVE.
|
||||||
if(!(instruction_[0] & 1)) {
|
if(!(instruction_[0] & 1)) {
|
||||||
@@ -113,7 +110,7 @@ bool Copper::advance_dma(uint16_t position, uint16_t blitter_status) {
|
|||||||
// Stop if this move would be a privilege violation.
|
// Stop if this move would be a privilege violation.
|
||||||
instruction_[0] &= 0x1fe;
|
instruction_[0] &= 0x1fe;
|
||||||
if((instruction_[0] < 0x10) || (instruction_[0] < 0x20 && !(control_&1))) {
|
if((instruction_[0] < 0x10) || (instruction_[0] < 0x20 && !(control_&1))) {
|
||||||
LOG("Invalid MOVE to " << PADHEX(4) << instruction_[0] << "; stopping");
|
logger.info().append("Invalid MOVE to %04x; stopping", instruction_[0]);
|
||||||
state_ = State::Stopped;
|
state_ = State::Stopped;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -8,13 +8,12 @@
|
|||||||
|
|
||||||
#include "Chipset.hpp"
|
#include "Chipset.hpp"
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
#define NDEBUG
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define LOG_PREFIX "[Disk] "
|
|
||||||
#include "../../Outputs/Log.hpp"
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Log::Logger<Log::Source::AmigaDisk> logger;
|
||||||
|
}
|
||||||
|
|
||||||
using namespace Amiga;
|
using namespace Amiga;
|
||||||
|
|
||||||
// MARK: - Disk DMA.
|
// MARK: - Disk DMA.
|
||||||
@@ -46,7 +45,7 @@ void Chipset::DiskDMA::set_length(uint16_t value) {
|
|||||||
buffer_read_ = buffer_write_ = 0;
|
buffer_read_ = buffer_write_ = 0;
|
||||||
|
|
||||||
if(dma_enable_) {
|
if(dma_enable_) {
|
||||||
LOG("Disk DMA " << (write_ ? "write" : "read") << " of " << length_ << " to " << PADHEX(8) << pointer_[0]);
|
logger.info().append("Disk DMA %s of %d to %08x", write_ ? "write" : "read", length_, pointer_[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
state_ = sync_with_word_ ? State::WaitingForSync : State::Reading;
|
state_ = sync_with_word_ ? State::WaitingForSync : State::Reading;
|
||||||
@@ -110,7 +109,7 @@ void Chipset::DiskController::process_input_bit(int value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Chipset::DiskController::set_sync_word(uint16_t value) {
|
void Chipset::DiskController::set_sync_word(uint16_t value) {
|
||||||
LOG("Set disk sync word to " << PADHEX(4) << value);
|
logger.info().append("Set disk sync word to %04x", value);
|
||||||
sync_word_ = value;
|
sync_word_ = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +127,7 @@ void Chipset::DiskController::set_control(uint16_t control) {
|
|||||||
bit_length.clock_rate = (control & 0x100) ? 500000 : 250000;
|
bit_length.clock_rate = (control & 0x100) ? 500000 : 250000;
|
||||||
set_expected_bit_length(bit_length);
|
set_expected_bit_length(bit_length);
|
||||||
|
|
||||||
LOG((sync_with_word_ ? "Will" : "Won't") << " sync with word; bit length is " << ((control & 0x100) ? "short" : "long"));
|
logger.info().append("%s sync with word; bit length is %s", sync_with_word_ ? "Will" : "Won't", (control & 0x100) ? "short" : "long");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Chipset::DiskController::process_index_hole() {
|
void Chipset::DiskController::process_index_hole() {
|
||||||
@@ -182,7 +181,7 @@ void Chipset::DiskController::set_mtr_sel_side_dir_step(uint8_t value) {
|
|||||||
// ID and definitely latch the new motor state.
|
// ID and definitely latch the new motor state.
|
||||||
if(!is_selected) {
|
if(!is_selected) {
|
||||||
drive_ids_[c] <<= 1;
|
drive_ids_[c] <<= 1;
|
||||||
LOG("Shifted drive ID shift register for drive " << +c << " to " << PADHEX(4) << std::bitset<16>{drive_ids_[c]});
|
logger.info().append("Shifted drive ID shift register for drive %d to %08x", c, drive_ids_[c]);
|
||||||
} else {
|
} else {
|
||||||
// Motor transition on -> off => reload register.
|
// Motor transition on -> off => reload register.
|
||||||
if(!motor_on && drive.get_motor_on()) {
|
if(!motor_on && drive.get_motor_on()) {
|
||||||
@@ -191,7 +190,7 @@ void Chipset::DiskController::set_mtr_sel_side_dir_step(uint8_t value) {
|
|||||||
// 0x5555'5555 = 5.25" drive;
|
// 0x5555'5555 = 5.25" drive;
|
||||||
// 0x0000'0000 = no drive.
|
// 0x0000'0000 = no drive.
|
||||||
drive_ids_[c] = 0xffff'ffff;
|
drive_ids_[c] = 0xffff'ffff;
|
||||||
LOG("Reloaded drive ID shift register for drive " << +c);
|
logger.info().append("Reloaded drive ID shift register for drive %d", c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also latch the new motor state.
|
// Also latch the new motor state.
|
||||||
@@ -204,7 +203,7 @@ void Chipset::DiskController::set_mtr_sel_side_dir_step(uint8_t value) {
|
|||||||
|
|
||||||
// Possibly step.
|
// Possibly step.
|
||||||
if(did_step && is_selected) {
|
if(did_step && is_selected) {
|
||||||
LOG("Stepped drive " << +c << " by " << std::dec << +direction.as_int());
|
logger.info().append("Stepped drive %d by %d", c, direction.as_int());
|
||||||
drive.step(direction);
|
drive.step(direction);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,11 +8,14 @@
|
|||||||
|
|
||||||
#include "ReactiveDevice.hpp"
|
#include "ReactiveDevice.hpp"
|
||||||
|
|
||||||
#define LOG_PREFIX "[ADB device] "
|
|
||||||
#include "../../../Outputs/Log.hpp"
|
#include "../../../Outputs/Log.hpp"
|
||||||
|
|
||||||
using namespace Apple::ADB;
|
using namespace Apple::ADB;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Log::Logger<Log::Source::ADBDevice> logger;
|
||||||
|
}
|
||||||
|
|
||||||
ReactiveDevice::ReactiveDevice(Apple::ADB::Bus &bus, uint8_t adb_device_id) :
|
ReactiveDevice::ReactiveDevice(Apple::ADB::Bus &bus, uint8_t adb_device_id) :
|
||||||
bus_(bus),
|
bus_(bus),
|
||||||
device_id_(bus.add_device(this)),
|
device_id_(bus.add_device(this)),
|
||||||
@@ -125,7 +128,7 @@ void ReactiveDevice::adb_bus_did_observe_event(Bus::Event event, uint8_t value)
|
|||||||
phase_ = Phase::AwaitingAttention;
|
phase_ = Phase::AwaitingAttention;
|
||||||
|
|
||||||
command_ = decode_command(value);
|
command_ = decode_command(value);
|
||||||
// LOG(command_);
|
// logger.info().append("%d", command_);
|
||||||
|
|
||||||
// If this command doesn't apply here, but a service request is requested,
|
// If this command doesn't apply here, but a service request is requested,
|
||||||
// post a service request.
|
// post a service request.
|
||||||
|
@@ -16,7 +16,6 @@
|
|||||||
#include "../../../InstructionSets/M50740/Parser.hpp"
|
#include "../../../InstructionSets/M50740/Parser.hpp"
|
||||||
#include "../../../InstructionSets/Disassembler.hpp"
|
#include "../../../InstructionSets/Disassembler.hpp"
|
||||||
|
|
||||||
#define LOG_PREFIX "[ADB GLU] "
|
|
||||||
#include "../../../Outputs/Log.hpp"
|
#include "../../../Outputs/Log.hpp"
|
||||||
|
|
||||||
using namespace Apple::IIgs::ADB;
|
using namespace Apple::IIgs::ADB;
|
||||||
@@ -40,6 +39,8 @@ enum class MicrocontrollerFlags: uint8_t {
|
|||||||
CommandRegisterFull = 0x40,
|
CommandRegisterFull = 0x40,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::ADBGLU> logger;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GLU::GLU() :
|
GLU::GLU() :
|
||||||
@@ -246,7 +247,7 @@ void GLU::set_port_output(int port, uint8_t value) {
|
|||||||
case 3:
|
case 3:
|
||||||
if(modifier_state_ != (value & 0x30)) {
|
if(modifier_state_ != (value & 0x30)) {
|
||||||
modifier_state_ = value & 0x30;
|
modifier_state_ = value & 0x30;
|
||||||
LOG("Modifier state: " << int(value & 0x30));
|
logger.info().append("Modifier state: %02x", modifier_state_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output is inverted respective to input; the microcontroller
|
// Output is inverted respective to input; the microcontroller
|
||||||
|
@@ -50,7 +50,7 @@ namespace {
|
|||||||
|
|
||||||
constexpr int CLOCK_RATE = 7833600;
|
constexpr int CLOCK_RATE = 7833600;
|
||||||
constexpr auto KEYBOARD_CLOCK_RATE = HalfCycles(CLOCK_RATE / 100000);
|
constexpr auto KEYBOARD_CLOCK_RATE = HalfCycles(CLOCK_RATE / 100000);
|
||||||
|
Log::Logger<Log::Source::Macintosh> logger;
|
||||||
|
|
||||||
// Former default PRAM:
|
// Former default PRAM:
|
||||||
//
|
//
|
||||||
@@ -723,7 +723,7 @@ template <Analyser::Static::Macintosh::Target::Model model> class ConcreteMachin
|
|||||||
if(port == Port::B && line == Line::Two) {
|
if(port == Port::B && line == Line::Two) {
|
||||||
keyboard_.set_input(value);
|
keyboard_.set_input(value);
|
||||||
}
|
}
|
||||||
else LOG("Unhandled control line output: " << (port ? 'B' : 'A') << int(line));
|
else logger.error().append("Unhandled 6522 control line output: %c%d", port ? 'B' : 'A', int(line));
|
||||||
}
|
}
|
||||||
|
|
||||||
void run_for(HalfCycles duration) {
|
void run_for(HalfCycles duration) {
|
||||||
|
@@ -29,7 +29,6 @@
|
|||||||
|
|
||||||
#include "../../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
|
#include "../../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
|
||||||
|
|
||||||
#define LOG_PREFIX "[ST] "
|
|
||||||
#include "../../../Outputs/Log.hpp"
|
#include "../../../Outputs/Log.hpp"
|
||||||
|
|
||||||
#include "../../Utility/MemoryPacker.hpp"
|
#include "../../Utility/MemoryPacker.hpp"
|
||||||
@@ -37,6 +36,10 @@
|
|||||||
|
|
||||||
#include "../../../Analyser/Static/AtariST/Target.hpp"
|
#include "../../../Analyser/Static/AtariST/Target.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Log::Logger<Log::Source::AtariST> logger;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Atari {
|
namespace Atari {
|
||||||
namespace ST {
|
namespace ST {
|
||||||
|
|
||||||
@@ -186,7 +189,7 @@ class ConcreteMachine:
|
|||||||
|
|
||||||
// Check for assertion of reset.
|
// Check for assertion of reset.
|
||||||
if(cycle.operation & CPU::MC68000::Operation::Reset) {
|
if(cycle.operation & CPU::MC68000::Operation::Reset) {
|
||||||
LOG("Unhandled Reset");
|
logger.error().append("Unhandled Reset");
|
||||||
}
|
}
|
||||||
|
|
||||||
// A null cycle leaves nothing else to do.
|
// A null cycle leaves nothing else to do.
|
||||||
|
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#include "DMAController.hpp"
|
#include "DMAController.hpp"
|
||||||
|
|
||||||
#define LOG_PREFIX "[DMA] "
|
|
||||||
#include "../../../Outputs/Log.hpp"
|
#include "../../../Outputs/Log.hpp"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
@@ -17,6 +16,8 @@ using namespace Atari::ST;
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::AtariSTDMAController> logger;
|
||||||
|
|
||||||
enum Control: uint16_t {
|
enum Control: uint16_t {
|
||||||
Direction = 0x100,
|
Direction = 0x100,
|
||||||
DRQSource = 0x80,
|
DRQSource = 0x80,
|
||||||
@@ -121,7 +122,7 @@ void DMAController::write(int address, uint16_t value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void DMAController::set_floppy_drive_selection(bool drive1, bool drive2, bool side2) {
|
void DMAController::set_floppy_drive_selection(bool drive1, bool drive2, bool side2) {
|
||||||
// LOG("Selected: " << (drive1 ? "1" : "-") << (drive2 ? "2" : "-") << (side2 ? "s" : "-"));
|
// logger.info().append("Selected: %s%s%s", drive1 ? "1" : "-", drive2 ? "2" : "-", side2 ? "s" : "-");
|
||||||
fdc_.set_floppy_drive_selection(drive1, drive2, side2);
|
fdc_.set_floppy_drive_selection(drive1, drive2, side2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,12 +192,6 @@ int DMAController::bus_grant(uint16_t *ram, size_t size) {
|
|||||||
// Check that the older buffer is full; stop if not.
|
// Check that the older buffer is full; stop if not.
|
||||||
if(!buffer_[active_buffer_ ^ 1].is_full) return 0;
|
if(!buffer_[active_buffer_ ^ 1].is_full) return 0;
|
||||||
|
|
||||||
//#define b(i, n) " " << PADHEX(2) << int(buffer_[i].contents[n])
|
|
||||||
//#define b2(i, n) b(i, n) << b(i, n+1)
|
|
||||||
//#define b4(i, n) b2(i, n) << b2(i, n+2)
|
|
||||||
//#define b16(i) b4(i, 0) << b4(i, 4) << b4(i, 8) << b4(i, 12)
|
|
||||||
// LOG("[1] to " << PADHEX(6) << address_ << b16(active_buffer_ ^ 1));
|
|
||||||
|
|
||||||
for(int c = 0; c < 8; ++c) {
|
for(int c = 0; c < 8; ++c) {
|
||||||
if(size_t(address_) < size) {
|
if(size_t(address_) < size) {
|
||||||
ram[address_ >> 1] = uint16_t(
|
ram[address_ >> 1] = uint16_t(
|
||||||
@@ -211,12 +206,6 @@ int DMAController::bus_grant(uint16_t *ram, size_t size) {
|
|||||||
// Check that the newer buffer is full; stop if not.
|
// Check that the newer buffer is full; stop if not.
|
||||||
if(!buffer_[active_buffer_ ].is_full) return 8;
|
if(!buffer_[active_buffer_ ].is_full) return 8;
|
||||||
|
|
||||||
// LOG("[2] to " << PADHEX(6) << address_ << b16(active_buffer_));
|
|
||||||
//#undef b16
|
|
||||||
//#undef b4
|
|
||||||
//#undef b2
|
|
||||||
//#undef b
|
|
||||||
|
|
||||||
for(int c = 0; c < 8; ++c) {
|
for(int c = 0; c < 8; ++c) {
|
||||||
if(size_t(address_) < size) {
|
if(size_t(address_) < size) {
|
||||||
ram[address_ >> 1] = uint16_t(
|
ram[address_ >> 1] = uint16_t(
|
||||||
|
@@ -8,10 +8,13 @@
|
|||||||
|
|
||||||
#include "IntelligentKeyboard.hpp"
|
#include "IntelligentKeyboard.hpp"
|
||||||
|
|
||||||
|
#include "../../../Outputs/Log.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#define LOG_PREFIX "[IKYB] "
|
namespace {
|
||||||
#include "../../../Outputs/Log.hpp"
|
Log::Logger<Log::Source::IntelligentKeyboard> logger;
|
||||||
|
}
|
||||||
|
|
||||||
using namespace Atari::ST;
|
using namespace Atari::ST;
|
||||||
|
|
||||||
@@ -157,7 +160,7 @@ void IntelligentKeyboard::dispatch_command(uint8_t command) {
|
|||||||
// If not, exit. If so, perform and drop out of the switch.
|
// If not, exit. If so, perform and drop out of the switch.
|
||||||
switch(command_sequence_.front()) {
|
switch(command_sequence_.front()) {
|
||||||
default:
|
default:
|
||||||
LOG("Unrecognised IKBD command " << PADHEX(2) << +command);
|
logger.error().append("Unrecognised IKBD command %02x", command);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x80:
|
case 0x80:
|
||||||
@@ -260,11 +263,11 @@ void IntelligentKeyboard::reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IntelligentKeyboard::resume() {
|
void IntelligentKeyboard::resume() {
|
||||||
LOG("Unimplemented: resume");
|
logger.error().append("Unimplemented: resume");
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntelligentKeyboard::pause() {
|
void IntelligentKeyboard::pause() {
|
||||||
LOG("Unimplemented: pause");
|
logger.error().append("Unimplemented: pause");
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntelligentKeyboard::disable_mouse() {
|
void IntelligentKeyboard::disable_mouse() {
|
||||||
@@ -287,7 +290,7 @@ void IntelligentKeyboard::set_mouse_position(uint16_t x, uint16_t y) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IntelligentKeyboard::set_mouse_keycode_reporting(uint8_t, uint8_t) {
|
void IntelligentKeyboard::set_mouse_keycode_reporting(uint8_t, uint8_t) {
|
||||||
LOG("Unimplemented: set mouse keycode reporting");
|
logger.error().append("Unimplemented: set mouse keycode reporting");
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntelligentKeyboard::set_mouse_threshold(uint8_t x, uint8_t y) {
|
void IntelligentKeyboard::set_mouse_threshold(uint8_t x, uint8_t y) {
|
||||||
@@ -309,7 +312,7 @@ void IntelligentKeyboard::set_mouse_y_upward() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IntelligentKeyboard::set_mouse_button_actions(uint8_t) {
|
void IntelligentKeyboard::set_mouse_button_actions(uint8_t) {
|
||||||
LOG("Unimplemented: set mouse button actions");
|
logger.error().append("Unimplemented: set mouse button actions");
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntelligentKeyboard::interrogate_mouse_position() {
|
void IntelligentKeyboard::interrogate_mouse_position() {
|
||||||
@@ -499,9 +502,9 @@ void IntelligentKeyboard::interrogate_joysticks() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IntelligentKeyboard::set_joystick_monitoring_mode(uint8_t) {
|
void IntelligentKeyboard::set_joystick_monitoring_mode(uint8_t) {
|
||||||
LOG("Unimplemented: joystick monitoring mode");
|
logger.error().append("Unimplemented: joystick monitoring mode");
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntelligentKeyboard::set_joystick_fire_button_monitoring_mode() {
|
void IntelligentKeyboard::set_joystick_fire_button_monitoring_mode() {
|
||||||
LOG("Unimplemented: joystick fire button monitoring mode");
|
logger.error().append("Unimplemented: joystick fire button monitoring mode");
|
||||||
}
|
}
|
||||||
|
@@ -36,6 +36,10 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Log::Logger<Log::Source::Vic20> logger;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Commodore::Vic20 {
|
namespace Commodore::Vic20 {
|
||||||
|
|
||||||
enum ROMSlot {
|
enum ROMSlot {
|
||||||
@@ -530,12 +534,12 @@ class ConcreteMachine:
|
|||||||
const uint16_t tape_buffer_pointer = uint16_t(ram_[0xb2]) | uint16_t(ram_[0xb3] << 8);
|
const uint16_t tape_buffer_pointer = uint16_t(ram_[0xb2]) | uint16_t(ram_[0xb3] << 8);
|
||||||
header->serialise(&ram_[tape_buffer_pointer], 0x8000 - tape_buffer_pointer);
|
header->serialise(&ram_[tape_buffer_pointer], 0x8000 - tape_buffer_pointer);
|
||||||
hold_tape_ = true;
|
hold_tape_ = true;
|
||||||
LOG("Vic-20: Found header");
|
logger.info().append("Found header");
|
||||||
} else {
|
} else {
|
||||||
// no header found, so pretend this hack never interceded
|
// no header found, so pretend this hack never interceded
|
||||||
tape_->get_tape()->set_offset(tape_position);
|
tape_->get_tape()->set_offset(tape_position);
|
||||||
hold_tape_ = false;
|
hold_tape_ = false;
|
||||||
LOG("Vic-20: Didn't find header");
|
logger.info().append("Didn't find header");
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear status and the verify flag
|
// clear status and the verify flag
|
||||||
@@ -576,11 +580,11 @@ class ConcreteMachine:
|
|||||||
m6502_.set_value_of(CPU::MOS6502::Register::ProgramCounter, 0xfccf);
|
m6502_.set_value_of(CPU::MOS6502::Register::ProgramCounter, 0xfccf);
|
||||||
*value = 0xea; // i.e. NOP implied
|
*value = 0xea; // i.e. NOP implied
|
||||||
hold_tape_ = true;
|
hold_tape_ = true;
|
||||||
LOG("Vic-20: Found data");
|
logger.info().append("Found data");
|
||||||
} else {
|
} else {
|
||||||
tape_->get_tape()->set_offset(tape_position);
|
tape_->get_tape()->set_offset(tape_position);
|
||||||
hold_tape_ = false;
|
hold_tape_ = false;
|
||||||
LOG("Vic-20: Didn't find data");
|
logger.info().append("Didn't find data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -18,11 +18,13 @@
|
|||||||
|
|
||||||
#include "../../Analyser/Static/Enterprise/Target.hpp"
|
#include "../../Analyser/Static/Enterprise/Target.hpp"
|
||||||
#include "../../ClockReceiver/JustInTime.hpp"
|
#include "../../ClockReceiver/JustInTime.hpp"
|
||||||
|
#include "../../Outputs/Log.hpp"
|
||||||
#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
|
#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
|
||||||
#include "../../Processors/Z80/Z80.hpp"
|
#include "../../Processors/Z80/Z80.hpp"
|
||||||
|
|
||||||
#define LOG_PREFIX "[Enterprise] "
|
namespace {
|
||||||
#include "../../Outputs/Log.hpp"
|
Log::Logger<Log::Source::Enterprise> logger;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Enterprise {
|
namespace Enterprise {
|
||||||
|
|
||||||
@@ -347,7 +349,7 @@ template <bool has_disk_controller, bool is_6mhz> class ConcreteMachine:
|
|||||||
case PartialMachineCycle::Input:
|
case PartialMachineCycle::Input:
|
||||||
switch(address & 0xff) {
|
switch(address & 0xff) {
|
||||||
default:
|
default:
|
||||||
LOG("Unhandled input from " << PADHEX(2) << (address & 0xff));
|
logger.error().append("Unhandled input from %02x", address & 0xff);
|
||||||
*cycle.value = 0xff;
|
*cycle.value = 0xff;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -412,7 +414,7 @@ template <bool has_disk_controller, bool is_6mhz> class ConcreteMachine:
|
|||||||
case PartialMachineCycle::Output:
|
case PartialMachineCycle::Output:
|
||||||
switch(address & 0xff) {
|
switch(address & 0xff) {
|
||||||
default:
|
default:
|
||||||
LOG("Unhandled output: " << PADHEX(2) << *cycle.value << " to " << PADHEX(2) << (address & 0xff));
|
logger.error().append("Unhandled output: %02x to %02x", *cycle.value, address & 0xff);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x10: case 0x11: case 0x12: case 0x13:
|
case 0x10: case 0x11: case 0x12: case 0x13:
|
||||||
@@ -511,12 +513,12 @@ template <bool has_disk_controller, bool is_6mhz> class ConcreteMachine:
|
|||||||
break;
|
break;
|
||||||
case 0xb6:
|
case 0xb6:
|
||||||
// Just 8 bits of printer data.
|
// Just 8 bits of printer data.
|
||||||
LOG("TODO: printer output " << PADHEX(2) << *cycle.value);
|
logger.info().append("TODO: printer output: %02x", *cycle.value);
|
||||||
break;
|
break;
|
||||||
case 0xb7:
|
case 0xb7:
|
||||||
// b0 = serial data out
|
// b0 = serial data out
|
||||||
// b1 = serial status out
|
// b1 = serial status out
|
||||||
LOG("TODO: serial output " << PADHEX(2) << *cycle.value);
|
logger.info().append("TODO: serial output: %02x", *cycle.value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@@ -49,6 +49,10 @@
|
|||||||
|
|
||||||
#include "../../Analyser/Static/MSX/Target.hpp"
|
#include "../../Analyser/Static/MSX/Target.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
Log::Logger<Log::Source::MSX> logger;
|
||||||
|
}
|
||||||
|
|
||||||
namespace MSX {
|
namespace MSX {
|
||||||
|
|
||||||
class AYPortHandler: public GI::AY38910::PortHandler {
|
class AYPortHandler: public GI::AY38910::PortHandler {
|
||||||
@@ -874,14 +878,14 @@ class ConcreteMachine:
|
|||||||
// b0-b3: keyboard line
|
// b0-b3: keyboard line
|
||||||
machine_.set_keyboard_line(value & 0xf);
|
machine_.set_keyboard_line(value & 0xf);
|
||||||
} break;
|
} break;
|
||||||
default: LOG("Unrecognised: MSX set 8255 output port " << port << " to value " << PADHEX(2) << value); break;
|
default: logger.error().append("Unrecognised: MSX set 8255 output port %d to value %02x", port, value); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t get_value(int port) {
|
uint8_t get_value(int port) {
|
||||||
if(port == 1) {
|
if(port == 1) {
|
||||||
return machine_.read_keyboard();
|
return machine_.read_keyboard();
|
||||||
} else LOG("MSX attempted to read from 8255 port " << port);
|
} else logger.error().append("MSX attempted to read from 8255 port %d");
|
||||||
return 0xff;
|
return 0xff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -23,7 +23,6 @@
|
|||||||
#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
|
#include "../../Outputs/Speaker/Implementation/LowpassSpeaker.hpp"
|
||||||
#include "../../Outputs/Speaker/Implementation/CompoundSource.hpp"
|
#include "../../Outputs/Speaker/Implementation/CompoundSource.hpp"
|
||||||
|
|
||||||
#define LOG_PREFIX "[SMS] "
|
|
||||||
#include "../../Outputs/Log.hpp"
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
#include "../../Analyser/Static/Sega/Target.hpp"
|
#include "../../Analyser/Static/Sega/Target.hpp"
|
||||||
@@ -34,6 +33,7 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr int audio_divider = 1;
|
constexpr int audio_divider = 1;
|
||||||
|
Log::Logger<Log::Source::MasterSystem> logger;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace Sega {
|
namespace Sega {
|
||||||
@@ -255,17 +255,17 @@ template <Analyser::Static::Sega::Target::Model model> class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(write_pointers_[address >> 10]) write_pointers_[address >> 10][address & 1023] = *cycle.value;
|
if(write_pointers_[address >> 10]) write_pointers_[address >> 10][address & 1023] = *cycle.value;
|
||||||
// else LOG("Ignored write to ROM");
|
// else logger.info().append("Ignored write to ROM");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case CPU::Z80::PartialMachineCycle::Input:
|
case CPU::Z80::PartialMachineCycle::Input:
|
||||||
switch(address & 0xc1) {
|
switch(address & 0xc1) {
|
||||||
case 0x00:
|
case 0x00:
|
||||||
LOG("TODO: [input] memory control");
|
logger.error().append("TODO: [input] memory control");
|
||||||
*cycle.value = 0xff;
|
*cycle.value = 0xff;
|
||||||
break;
|
break;
|
||||||
case 0x01:
|
case 0x01:
|
||||||
LOG("TODO: [input] I/O port control");
|
logger.error().append("TODO: [input] I/O port control");
|
||||||
*cycle.value = 0xff;
|
*cycle.value = 0xff;
|
||||||
break;
|
break;
|
||||||
case 0x40:
|
case 0x40:
|
||||||
@@ -305,7 +305,7 @@ template <Analyser::Static::Sega::Target::Model model> class ConcreteMachine:
|
|||||||
} break;
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ERROR("[input] Clearly some sort of typo");
|
logger.error().append("[input] Clearly some sort of typo");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -315,7 +315,7 @@ template <Analyser::Static::Sega::Target::Model model> class ConcreteMachine:
|
|||||||
case 0x00: // i.e. even ports less than 0x40.
|
case 0x00: // i.e. even ports less than 0x40.
|
||||||
if constexpr (is_master_system(model)) {
|
if constexpr (is_master_system(model)) {
|
||||||
// TODO: Obey the RAM enable.
|
// TODO: Obey the RAM enable.
|
||||||
LOG("Memory control: " << PADHEX(2) << +memory_control_);
|
logger.info().append("Memory control: %02x", memory_control_);
|
||||||
memory_control_ = *cycle.value;
|
memory_control_ = *cycle.value;
|
||||||
page_cartridge();
|
page_cartridge();
|
||||||
}
|
}
|
||||||
@@ -357,7 +357,7 @@ template <Analyser::Static::Sega::Target::Model model> class ConcreteMachine:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ERROR("[output] Clearly some sort of typo");
|
logger.error().append("[output] Clearly some sort of typo");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@@ -24,7 +24,6 @@
|
|||||||
// just grab the CPC's version of an FDC.
|
// just grab the CPC's version of an FDC.
|
||||||
#include "../../AmstradCPC/FDC.hpp"
|
#include "../../AmstradCPC/FDC.hpp"
|
||||||
|
|
||||||
#define LOG_PREFIX "[Spectrum] "
|
|
||||||
#include "../../../Outputs/Log.hpp"
|
#include "../../../Outputs/Log.hpp"
|
||||||
|
|
||||||
#include "../../../Outputs/Speaker/Implementation/CompoundSource.hpp"
|
#include "../../../Outputs/Speaker/Implementation/CompoundSource.hpp"
|
||||||
|
@@ -53,7 +53,7 @@
|
|||||||
</BuildableProductRunnable>
|
</BuildableProductRunnable>
|
||||||
<CommandLineArguments>
|
<CommandLineArguments>
|
||||||
<CommandLineArgument
|
<CommandLineArgument
|
||||||
argument = ""/Users/thomasharte/Desktop/Soft/Master System/R-Type (NTSC).sms""
|
argument = ""/Users/thomasharte/Library/Mobile Documents/com~apple~CloudDocs/Soft/Master System/R-Type (NTSC).sms""
|
||||||
isEnabled = "YES">
|
isEnabled = "YES">
|
||||||
</CommandLineArgument>
|
</CommandLineArgument>
|
||||||
<CommandLineArgument
|
<CommandLineArgument
|
||||||
|
169
Outputs/Log.hpp
169
Outputs/Log.hpp
@@ -8,39 +8,142 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdarg>
|
||||||
|
|
||||||
|
namespace Log {
|
||||||
|
// TODO: if adopting C++20, std::format would be a better model to apply below.
|
||||||
|
// But I prefer C files to C++ streams, so here it is for now.
|
||||||
|
|
||||||
|
enum class Source {
|
||||||
|
ADBDevice,
|
||||||
|
ADBGLU,
|
||||||
|
Amiga,
|
||||||
|
AmigaDisk,
|
||||||
|
AmigaCopper,
|
||||||
|
AmigaChipset,
|
||||||
|
AmigaBlitter,
|
||||||
|
AtariST,
|
||||||
|
AtariSTDMAController,
|
||||||
|
CommodoreStaticAnalyser,
|
||||||
|
DirectAccessDevice,
|
||||||
|
Enterprise,
|
||||||
|
i8272,
|
||||||
|
IntelligentKeyboard,
|
||||||
|
IWM,
|
||||||
|
M50740,
|
||||||
|
Macintosh,
|
||||||
|
MasterSystem,
|
||||||
|
MultiMachine,
|
||||||
|
MFP68901,
|
||||||
|
MSX,
|
||||||
|
NCR5380,
|
||||||
|
OpenGL,
|
||||||
|
PCMTrack,
|
||||||
|
SCC,
|
||||||
|
SCSI,
|
||||||
|
SZX,
|
||||||
|
TapeUEF,
|
||||||
|
TMS9918,
|
||||||
|
TZX,
|
||||||
|
Vic20,
|
||||||
|
WDFDC,
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr bool is_enabled(Source source) {
|
||||||
#ifdef NDEBUG
|
#ifdef NDEBUG
|
||||||
|
return false;
|
||||||
#define LOG(x) while(false) {}
|
|
||||||
#define LOGNBR(x) while(false) {}
|
|
||||||
|
|
||||||
#define ERROR(x) while(false) {}
|
|
||||||
#define ERRORNBR(x) while(false) {}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#include <ios>
|
|
||||||
#include <iomanip>
|
|
||||||
|
|
||||||
#define PADHEX(n) std::hex << std::setfill('0') << std::setw(n)
|
|
||||||
#define PADDEC(n) std::dec << std::setfill('0') << std::setw(n)
|
|
||||||
|
|
||||||
#ifdef LOG_PREFIX
|
|
||||||
|
|
||||||
#define LOG(x) std::cout << LOG_PREFIX << x << std::endl
|
|
||||||
#define LOGNBR(x) std::cout << LOG_PREFIX << x
|
|
||||||
|
|
||||||
#define ERROR(x) std::cerr << LOG_PREFIX << x << std::endl
|
|
||||||
#define ERRORNBR(x) std::cerr << LOG_PREFIX << x
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define LOG(x) std::cout << x << std::endl
|
|
||||||
#define LOGNBR(x) std::cout << x
|
|
||||||
|
|
||||||
#define ERROR(x) std::cerr << x << std::endl
|
|
||||||
#define ERRORNBR(x) std::cerr << x
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
// Allow for compile-time source-level enabling and disabling of different sources.
|
||||||
|
switch(source) {
|
||||||
|
default: return true;
|
||||||
|
|
||||||
|
// The following are all things I'm not actively working on.
|
||||||
|
case Source::AmigaBlitter:
|
||||||
|
case Source::AmigaChipset:
|
||||||
|
case Source::AmigaCopper:
|
||||||
|
case Source::AmigaDisk:
|
||||||
|
case Source::IWM:
|
||||||
|
case Source::MFP68901:
|
||||||
|
case Source::NCR5380:
|
||||||
|
case Source::SCC: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const char *prefix(Source source) {
|
||||||
|
switch(source) {
|
||||||
|
default: return nullptr;
|
||||||
|
|
||||||
|
case Source::ADBDevice: return "ADB device";
|
||||||
|
case Source::ADBGLU: return "ADB GLU";
|
||||||
|
case Source::AmigaBlitter: return "Blitter";
|
||||||
|
case Source::AmigaChipset: return "Chipset";
|
||||||
|
case Source::AmigaCopper: return "Copper";
|
||||||
|
case Source::AmigaDisk: return "Disk";
|
||||||
|
case Source::AtariST: return "AtariST";
|
||||||
|
case Source::AtariSTDMAController: return "DMA";
|
||||||
|
case Source::CommodoreStaticAnalyser: return "Commodore Static Analyser";
|
||||||
|
case Source::Enterprise: return "Enterprise";
|
||||||
|
case Source::i8272: return "i8272";
|
||||||
|
case Source::IntelligentKeyboard: return "IKYB";
|
||||||
|
case Source::IWM: return "IWM";
|
||||||
|
case Source::M50740: return "M50740";
|
||||||
|
case Source::Macintosh: return "Macintosh";
|
||||||
|
case Source::MasterSystem: return "SMS";
|
||||||
|
case Source::MFP68901: return "MFP68901";
|
||||||
|
case Source::MultiMachine: return "Multi-machine";
|
||||||
|
case Source::MSX: return "MSX";
|
||||||
|
case Source::NCR5380: return "5380";
|
||||||
|
case Source::OpenGL: return "OpenGL";
|
||||||
|
case Source::PCMTrack: return "PCM Track";
|
||||||
|
case Source::SCSI: return "SCSI";
|
||||||
|
case Source::SCC: return "SCC";
|
||||||
|
case Source::SZX: return "SZX";
|
||||||
|
case Source::TapeUEF: return "UEF";
|
||||||
|
case Source::TZX: return "TZX";
|
||||||
|
case Source::Vic20: return "Vic20";
|
||||||
|
case Source::WDFDC: return "WD FDC";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <Source source>
|
||||||
|
class Logger {
|
||||||
|
public:
|
||||||
|
static constexpr bool enabled = is_enabled(source);
|
||||||
|
|
||||||
|
Logger() {}
|
||||||
|
|
||||||
|
struct LogLine {
|
||||||
|
public:
|
||||||
|
LogLine(FILE *stream) : stream_(stream) {
|
||||||
|
if constexpr (!enabled) return;
|
||||||
|
|
||||||
|
const auto source_prefix = prefix(source);
|
||||||
|
if(source_prefix) {
|
||||||
|
fprintf(stream_, "[%s] ", source_prefix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~LogLine() {
|
||||||
|
if constexpr (!enabled) return;
|
||||||
|
fprintf(stream_, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void append(const char *format, ...) {
|
||||||
|
if constexpr (!enabled) return;
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
vfprintf(stream_, format, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FILE *stream_;
|
||||||
|
};
|
||||||
|
|
||||||
|
LogLine info() { return LogLine(stdout); }
|
||||||
|
LogLine error() { return LogLine(stderr); }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
@@ -14,9 +14,8 @@
|
|||||||
using namespace Outputs::Display::OpenGL;
|
using namespace Outputs::Display::OpenGL;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// The below is disabled because it isn't context/thread-specific. Which makes it
|
thread_local const Shader *bound_shader = nullptr;
|
||||||
// fairly 'unuseful'.
|
Log::Logger<Log::Source::OpenGL> logger;
|
||||||
// Shader *bound_shader = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint Shader::compile_shader(const std::string &source, GLenum type) {
|
GLuint Shader::compile_shader(const std::string &source, GLenum type) {
|
||||||
@@ -25,22 +24,22 @@ GLuint Shader::compile_shader(const std::string &source, GLenum type) {
|
|||||||
test_gl(glShaderSource, shader, 1, &c_str, NULL);
|
test_gl(glShaderSource, shader, 1, &c_str, NULL);
|
||||||
test_gl(glCompileShader, shader);
|
test_gl(glCompileShader, shader);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
if constexpr (logger.enabled) {
|
||||||
GLint isCompiled = 0;
|
GLint isCompiled = 0;
|
||||||
test_gl(glGetShaderiv, shader, GL_COMPILE_STATUS, &isCompiled);
|
test_gl(glGetShaderiv, shader, GL_COMPILE_STATUS, &isCompiled);
|
||||||
if(isCompiled == GL_FALSE) {
|
if(isCompiled == GL_FALSE) {
|
||||||
GLint logLength;
|
GLint logLength;
|
||||||
test_gl(glGetShaderiv, shader, GL_INFO_LOG_LENGTH, &logLength);
|
test_gl(glGetShaderiv, shader, GL_INFO_LOG_LENGTH, &logLength);
|
||||||
if(logLength > 0) {
|
if(logLength > 0) {
|
||||||
const auto length = std::vector<GLchar>::size_type(logLength);
|
const auto length = std::vector<GLchar>::size_type(logLength);
|
||||||
std::vector<GLchar> log(length);
|
std::vector<GLchar> log(length);
|
||||||
test_gl(glGetShaderInfoLog, shader, logLength, &logLength, log.data());
|
test_gl(glGetShaderInfoLog, shader, logLength, &logLength, log.data());
|
||||||
LOG("Compile log:\n" << log.data());
|
logger.error().append("Compile log: %s", log.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
throw (type == GL_VERTEX_SHADER) ? VertexShaderCompilationError : FragmentShaderCompilationError;
|
throw (type == GL_VERTEX_SHADER) ? VertexShaderCompilationError : FragmentShaderCompilationError;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
return shader;
|
return shader;
|
||||||
}
|
}
|
||||||
@@ -69,58 +68,58 @@ void Shader::init(const std::string &vertex_shader, const std::string &fragment_
|
|||||||
|
|
||||||
for(const auto &binding : attribute_bindings) {
|
for(const auto &binding : attribute_bindings) {
|
||||||
test_gl(glBindAttribLocation, shader_program_, binding.index, binding.name.c_str());
|
test_gl(glBindAttribLocation, shader_program_, binding.index, binding.name.c_str());
|
||||||
#ifndef NDEBUG
|
|
||||||
const auto error = glGetError();
|
if constexpr (logger.enabled) {
|
||||||
switch(error) {
|
const auto error = glGetError();
|
||||||
case 0: break;
|
switch(error) {
|
||||||
case GL_INVALID_VALUE:
|
case 0: break;
|
||||||
LOG("GL_INVALID_VALUE when attempting to bind " << binding.name << " to index " << binding.index << " (i.e. index is greater than or equal to GL_MAX_VERTEX_ATTRIBS)");
|
case GL_INVALID_VALUE:
|
||||||
break;
|
logger.error().append("GL_INVALID_VALUE when attempting to bind %s to index %d (i.e. index is greater than or equal to GL_MAX_VERTEX_ATTRIBS)", binding.name.c_str(), binding.index);
|
||||||
case GL_INVALID_OPERATION:
|
break;
|
||||||
LOG("GL_INVALID_OPERATION when attempting to bind " << binding.name << " to index " << binding.index << " (i.e. name begins with gl_)");
|
case GL_INVALID_OPERATION:
|
||||||
break;
|
logger.error().append("GL_INVALID_OPERATION when attempting to bind %s to index %d (i.e. name begins with gl_)", binding.name.c_str(), binding.index);
|
||||||
default:
|
break;
|
||||||
LOG("Error " << error << " when attempting to bind " << binding.name << " to index " << binding.index);
|
default:
|
||||||
break;
|
logger.error().append("Error %d when attempting to bind %s to index %d", error, binding.name.c_str(), binding.index);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
test_gl(glLinkProgram, shader_program_);
|
test_gl(glLinkProgram, shader_program_);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
if constexpr (logger.enabled) {
|
||||||
GLint logLength;
|
GLint logLength;
|
||||||
test_gl(glGetProgramiv, shader_program_, GL_INFO_LOG_LENGTH, &logLength);
|
test_gl(glGetProgramiv, shader_program_, GL_INFO_LOG_LENGTH, &logLength);
|
||||||
if(logLength > 0) {
|
if(logLength > 0) {
|
||||||
GLchar *log = new GLchar[std::size_t(logLength)];
|
std::vector<GLchar> log(logLength);
|
||||||
test_gl(glGetProgramInfoLog, shader_program_, logLength, &logLength, log);
|
test_gl(glGetProgramInfoLog, shader_program_, logLength, &logLength, log.data());
|
||||||
LOG("Link log:\n" << log);
|
logger.error().append("Link log: %s", log.data());
|
||||||
delete[] log;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
GLint didLink = 0;
|
GLint didLink = 0;
|
||||||
test_gl(glGetProgramiv, shader_program_, GL_LINK_STATUS, &didLink);
|
test_gl(glGetProgramiv, shader_program_, GL_LINK_STATUS, &didLink);
|
||||||
if(didLink == GL_FALSE) {
|
if(didLink == GL_FALSE) {
|
||||||
throw ProgramLinkageError;
|
throw ProgramLinkageError;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader::~Shader() {
|
Shader::~Shader() {
|
||||||
// if(bound_shader == this) Shader::unbind();
|
if(bound_shader == this) Shader::unbind();
|
||||||
glDeleteProgram(shader_program_);
|
glDeleteProgram(shader_program_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::bind() const {
|
void Shader::bind() const {
|
||||||
// if(bound_shader != this) {
|
if(bound_shader != this) {
|
||||||
test_gl(glUseProgram, shader_program_);
|
test_gl(glUseProgram, shader_program_);
|
||||||
// bound_shader = this;
|
bound_shader = this;
|
||||||
// }
|
}
|
||||||
flush_functions();
|
flush_functions();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shader::unbind() {
|
void Shader::unbind() {
|
||||||
// bound_shader = nullptr;
|
bound_shader = nullptr;
|
||||||
test_gl(glUseProgram, 0);
|
test_gl(glUseProgram, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -139,7 +138,7 @@ void Shader::enable_vertex_attribute_with_pointer(const std::string &name, GLint
|
|||||||
test_gl(glVertexAttribPointer, GLuint(location), size, type, normalised, stride, pointer);
|
test_gl(glVertexAttribPointer, GLuint(location), size, type, normalised, stride, pointer);
|
||||||
test_gl(glVertexAttribDivisor, GLuint(location), divisor);
|
test_gl(glVertexAttribDivisor, GLuint(location), divisor);
|
||||||
} else {
|
} else {
|
||||||
LOG("Couldn't enable vertex attribute " << name);
|
logger.error().append("Couldn't enable vertex attribute %s", name.c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -147,10 +146,10 @@ void Shader::enable_vertex_attribute_with_pointer(const std::string &name, GLint
|
|||||||
#define with_location(func, ...) {\
|
#define with_location(func, ...) {\
|
||||||
const GLint location = glGetUniformLocation(shader_program_, name.c_str()); \
|
const GLint location = glGetUniformLocation(shader_program_, name.c_str()); \
|
||||||
if(location == -1) { \
|
if(location == -1) { \
|
||||||
LOG("Couldn't get location for uniform " << name); \
|
logger.error().append("Couldn't get location for uniform %s", name.c_str()); \
|
||||||
} else { \
|
} else { \
|
||||||
func(location, __VA_ARGS__); \
|
func(location, __VA_ARGS__); \
|
||||||
if(glGetError()) LOG("Error setting uniform " << name << " via " << #func); \
|
if(glGetError()) logger.error().append("Error setting uniform %s via %s", name.c_str(), #func); \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -60,6 +60,8 @@ constexpr GLenum formatForDepth(std::size_t depth) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::OpenGL> logger;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> void ScanTarget::allocate_buffer(const T &array, GLuint &buffer_name, GLuint &vertex_array_name) {
|
template <typename T> void ScanTarget::allocate_buffer(const T &array, GLuint &buffer_name, GLuint &vertex_array_name) {
|
||||||
@@ -343,7 +345,7 @@ void ScanTarget::update(int, int output_height) {
|
|||||||
// Work with the accumulation_buffer_ potentially starts from here onwards; set its flag.
|
// Work with the accumulation_buffer_ potentially starts from here onwards; set its flag.
|
||||||
while(is_drawing_to_accumulation_buffer_.test_and_set());
|
while(is_drawing_to_accumulation_buffer_.test_and_set());
|
||||||
if(did_create_accumulation_texture) {
|
if(did_create_accumulation_texture) {
|
||||||
LOG("Changed output resolution to " << proportional_width << " by " << framebuffer_height);
|
logger.info().append("Changed output resolution to %d by %d", proportional_width, framebuffer_height);
|
||||||
display_metrics_.announce_did_resize();
|
display_metrics_.announce_did_resize();
|
||||||
std::unique_ptr<OpenGL::TextureTarget> new_framebuffer(
|
std::unique_ptr<OpenGL::TextureTarget> new_framebuffer(
|
||||||
new TextureTarget(
|
new TextureTarget(
|
||||||
|
@@ -55,7 +55,10 @@ class ScanTarget: public Outputs::Display::BufferingScanTarget { // TODO: use pr
|
|||||||
struct OpenGLVersionDumper {
|
struct OpenGLVersionDumper {
|
||||||
OpenGLVersionDumper() {
|
OpenGLVersionDumper() {
|
||||||
// Note the OpenGL version, as the first thing this class does prior to construction.
|
// Note the OpenGL version, as the first thing this class does prior to construction.
|
||||||
LOG("Constructing scan target with OpenGL " << glGetString(GL_VERSION) << "; shading language version " << glGetString(GL_SHADING_LANGUAGE_VERSION));
|
Log::Logger<Log::Source::OpenGL>().info().append(
|
||||||
|
"Constructing scan target with OpenGL %s; shading language version %s",
|
||||||
|
glGetString(GL_VERSION),
|
||||||
|
glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||||
}
|
}
|
||||||
} dumper_;
|
} dumper_;
|
||||||
#endif
|
#endif
|
||||||
|
@@ -9,6 +9,12 @@
|
|||||||
#include "PCMTrack.hpp"
|
#include "PCMTrack.hpp"
|
||||||
#include "../../../Outputs/Log.hpp"
|
#include "../../../Outputs/Log.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::PCMTrack> logger;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
using namespace Storage::Disk;
|
using namespace Storage::Disk;
|
||||||
|
|
||||||
PCMTrack::PCMTrack() : segment_pointer_(0) {}
|
PCMTrack::PCMTrack() : segment_pointer_(0) {}
|
||||||
@@ -60,7 +66,7 @@ PCMTrack *PCMTrack::resampled_clone(Track *original, size_t bits_per_track) {
|
|||||||
return pcm_original->resampled_clone(bits_per_track);
|
return pcm_original->resampled_clone(bits_per_track);
|
||||||
}
|
}
|
||||||
|
|
||||||
ERROR("NOT IMPLEMENTED: resampling non-PCMTracks");
|
logger.error().append("NOT IMPLEMENTED: resampling non-PCMTracks");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -11,6 +11,12 @@
|
|||||||
|
|
||||||
using namespace SCSI;
|
using namespace SCSI;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::DirectAccessDevice> logger;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void DirectAccessDevice::set_storage(const std::shared_ptr<Storage::MassStorage::MassStorageDevice> &device) {
|
void DirectAccessDevice::set_storage(const std::shared_ptr<Storage::MassStorage::MassStorageDevice> &device) {
|
||||||
device_ = device;
|
device_ = device;
|
||||||
}
|
}
|
||||||
@@ -19,7 +25,7 @@ bool DirectAccessDevice::read(const Target::CommandState &state, Target::Respond
|
|||||||
if(!device_) return false;
|
if(!device_) return false;
|
||||||
|
|
||||||
const auto specs = state.read_write_specs();
|
const auto specs = state.read_write_specs();
|
||||||
LOG("Read: " << std::dec << specs.number_of_blocks << " from " << specs.address);
|
logger.info().append("Read: %d from %d", specs.number_of_blocks, specs.address);
|
||||||
|
|
||||||
std::vector<uint8_t> output = device_->get_block(specs.address);
|
std::vector<uint8_t> output = device_->get_block(specs.address);
|
||||||
for(uint32_t offset = 1; offset < specs.number_of_blocks; ++offset) {
|
for(uint32_t offset = 1; offset < specs.number_of_blocks; ++offset) {
|
||||||
@@ -38,7 +44,7 @@ bool DirectAccessDevice::write(const Target::CommandState &state, Target::Respon
|
|||||||
if(!device_) return false;
|
if(!device_) return false;
|
||||||
|
|
||||||
const auto specs = state.read_write_specs();
|
const auto specs = state.read_write_specs();
|
||||||
LOG("Write: " << specs.number_of_blocks << " to " << specs.address);
|
logger.info().append("Write: %d to %d", specs.number_of_blocks, specs.address);
|
||||||
|
|
||||||
responder.receive_data(device_->get_block_size() * specs.number_of_blocks, [this, specs] (const Target::CommandState &state, Target::Responder &responder) {
|
responder.receive_data(device_->get_block_size() * specs.number_of_blocks, [this, specs] (const Target::CommandState &state, Target::Responder &responder) {
|
||||||
const auto received_data = state.received_data();
|
const auto received_data = state.received_data();
|
||||||
|
@@ -347,6 +347,7 @@ template <typename Executor> class Target: public Bus::Observer, public Responde
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Executor executor_;
|
Executor executor_;
|
||||||
|
Log::Logger<Log::Source::SCSI> log_;
|
||||||
|
|
||||||
// Bus::Observer.
|
// Bus::Observer.
|
||||||
void scsi_bus_did_change(Bus *, BusState new_state, double time_since_change) final;
|
void scsi_bus_did_change(Bus *, BusState new_state, double time_since_change) final;
|
||||||
|
@@ -178,7 +178,7 @@ template <typename Executor> bool Target<Executor>::dispatch_command() {
|
|||||||
#define G1(x) (0x20|x)
|
#define G1(x) (0x20|x)
|
||||||
#define G5(x) (0xa0|x)
|
#define G5(x) (0xa0|x)
|
||||||
|
|
||||||
LOG("---Command " << PADHEX(2) << int(command_[0]) << "---");
|
log_.info().append("---Command %02x---", command_[0]);
|
||||||
|
|
||||||
switch(command_[0]) {
|
switch(command_[0]) {
|
||||||
default: return false;
|
default: return false;
|
||||||
@@ -278,5 +278,5 @@ template <typename Executor> void Target<Executor>::end_command() {
|
|||||||
bus_state_ = DefaultBusState;
|
bus_state_ = DefaultBusState;
|
||||||
set_device_output(bus_state_);
|
set_device_output(bus_state_);
|
||||||
|
|
||||||
LOG("---Done---");
|
log_.info().append("---Done---");
|
||||||
}
|
}
|
||||||
|
@@ -12,8 +12,6 @@
|
|||||||
|
|
||||||
#include "../../Analyser/Static/ZXSpectrum/Target.hpp"
|
#include "../../Analyser/Static/ZXSpectrum/Target.hpp"
|
||||||
#include "../../Machines/Sinclair/ZXSpectrum/State.hpp"
|
#include "../../Machines/Sinclair/ZXSpectrum/State.hpp"
|
||||||
|
|
||||||
#define LOG_PREFIX "[SZX] "
|
|
||||||
#include "../../Outputs/Log.hpp"
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
@@ -25,6 +23,7 @@ namespace {
|
|||||||
constexpr uint32_t block(const char *str) {
|
constexpr uint32_t block(const char *str) {
|
||||||
return uint32_t(str[0] | (str[1] << 8) | (str[2] << 16) | (str[3] << 24));
|
return uint32_t(str[0] | (str[1] << 8) | (str[2] << 16) | (str[3] << 24));
|
||||||
}
|
}
|
||||||
|
Log::Logger<Log::Source::SZX> logger;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +80,7 @@ std::unique_ptr<Analyser::Static::Target> SZX::load(const std::string &file_name
|
|||||||
|
|
||||||
switch(blockID) {
|
switch(blockID) {
|
||||||
default:
|
default:
|
||||||
LOG("Unhandled block " << char(blockID) << char(blockID >> 8) << char(blockID >> 16) << char(blockID >> 24));
|
logger.info().append("Unhandled block %c%c%c%c", char(blockID), char(blockID >> 8), char(blockID >> 16), char(blockID >> 24));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// ZXSTZ80REGS
|
// ZXSTZ80REGS
|
||||||
|
@@ -14,8 +14,11 @@
|
|||||||
using namespace Storage::Tape;
|
using namespace Storage::Tape;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const unsigned int StandardTZXClock = 3500000;
|
|
||||||
const unsigned int TZXClockMSMultiplier = 3500;
|
constexpr unsigned int StandardTZXClock = 3500000;
|
||||||
|
constexpr unsigned int TZXClockMSMultiplier = 3500;
|
||||||
|
Log::Logger<Log::Source::TZX> logger;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TZX::TZX(const std::string &file_name) :
|
TZX::TZX(const std::string &file_name) :
|
||||||
@@ -92,7 +95,7 @@ void TZX::get_next_pulses() {
|
|||||||
default:
|
default:
|
||||||
// In TZX each chunk has a different way of stating or implying its length,
|
// In TZX each chunk has a different way of stating or implying its length,
|
||||||
// so there is no route past an unimplemented chunk.
|
// so there is no route past an unimplemented chunk.
|
||||||
LOG("Unknown TZX chunk: " << PADHEX(4) << chunk_id);
|
logger.error().append("Unknown TZX chunk: %04x", chunk_id);
|
||||||
set_is_at_end(true);
|
set_is_at_end(true);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@@ -12,9 +12,14 @@
|
|||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
#define LOG_PREFIX "[UEF] "
|
|
||||||
#include "../../../Outputs/Log.hpp"
|
#include "../../../Outputs/Log.hpp"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
Log::Logger<Log::Source::TapeUEF> logger;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: - ZLib extensions
|
// MARK: - ZLib extensions
|
||||||
|
|
||||||
static float gzgetfloat(gzFile file) {
|
static float gzgetfloat(gzFile file) {
|
||||||
@@ -156,7 +161,7 @@ void UEF::get_next_pulses() {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
LOG("Skipping chunk of type " << PADHEX(4) << next_chunk.id);
|
logger.info().append("Skipping chunk of type %04x", next_chunk.id);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user