1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-07 23:29:06 +00:00
CLK/Components/5380/ncr5380.hpp
Thomas Harte 960b289e70 Edges closer towards proper DMA operation.
Specifically: differentiates the three kinds of DMA operation. Still doesn't act correctly with regard to DACK though, and leaves the bus instantaneously improperly formed. Which I'm tempted to try to fix on the target side by properly obeying delays.
2019-09-15 15:03:06 -04:00

96 lines
2.2 KiB
C++

//
// ncr5380.hpp
// Clock Signal
//
// Created by Thomas Harte on 10/08/2019.
// Copyright © 2019 Thomas Harte. All rights reserved.
//
#ifndef ncr5380_hpp
#define ncr5380_hpp
#include <cstdint>
#include "../../Storage/MassStorage/SCSI/SCSI.hpp"
#include "../../ClockReceiver/ClockReceiver.hpp"
#include "../../ClockReceiver/ClockingHintSource.hpp"
namespace NCR {
namespace NCR5380 {
/*!
Models the NCR 5380, a SCSI interface chip.
*/
class NCR5380 final: public ClockingHint::Source {
public:
NCR5380(SCSI::Bus &bus, int clock_rate);
/*! Writes @c value to @c address. */
void write(int address, uint8_t value, bool dma_acknowledge = false);
/*! Reads from @c address. */
uint8_t read(int address, bool dma_acknowledge = false);
/*!
As per its design manual:
"The NCR 5380 is a clockless device. Delays such as bus
free delay, bus set delay and bus settle delay are
implemented using gate delays."
Therefore this fictitious implementation of an NCR5380 needs
a way to track time even though the real one doesn't take in
a clock. This is provided by `run_for`.
Nevertheless, the clocking doesn't need to be very precise.
Please provide a clock that is close to 200,000 Hz.
*/
void run_for(Cycles);
/// As per ClockingHint::Source.
ClockingHint::Preference preferred_clocking() final;
private:
SCSI::Bus &bus_;
const int clock_rate_;
size_t device_id_;
SCSI::BusState bus_output_ = SCSI::DefaultBusState;
SCSI::BusState expected_phase_ = SCSI::DefaultBusState;
uint8_t mode_ = 0xff;
uint8_t initiator_command_ = 0xff;
uint8_t data_bus_ = 0xff;
uint8_t target_command_ = 0xff;
bool test_mode_ = false;
bool assert_data_bus_ = false;
bool dma_request_ = false;
bool dma_acknowledge_ = false;
enum class ExecutionState {
None,
WatchingBusy,
PerformingDMA,
} state_ = ExecutionState::None;
enum class DMAOperation {
Ready,
Send,
TargetReceive,
InitiatorReceive
} dma_operation_ = DMAOperation::Ready;
int time_in_state_ = 0;
bool lost_arbitration_ = false, arbitration_in_progress_ = false;
void set_execution_state(ExecutionState state);
SCSI::BusState target_output();
void update_control_output();
};
}
}
#endif /* ncr5380_hpp */