OXYGENHUB
◆ main openmsx / src / fdc / WD2793.hh
4.5 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
1
#ifndef WD2793_HH
2
#define WD2793_HH
3
4
#include "RawTrack.hh"
5
6
#include "DynamicClock.hh"
7
#include "EmuTime.hh"
8
#include "Schedulable.hh"
9
#include "serialize_meta.hh"
10
11
#include "CRC16.hh"
12
13
namespace openmsx {
14
15
class Scheduler;
16
class DiskDrive;
17
class MSXCliComm;
18
19
class WD2793 final : public Schedulable
20
{
21
public:
22
	WD2793(Scheduler& scheduler, DiskDrive& drive, MSXCliComm& cliComm,
23
	       EmuTime time, bool isWD1770);
24
25
	void reset(EmuTime time);
26
27
	[[nodiscard]] uint8_t getStatusReg(EmuTime time);
28
	[[nodiscard]] uint8_t getTrackReg (EmuTime time) const;
29
	[[nodiscard]] uint8_t getSectorReg(EmuTime time) const;
30
	[[nodiscard]] uint8_t getDataReg  (EmuTime time);
31
32
	[[nodiscard]] uint8_t peekStatusReg(EmuTime time) const;
33
	[[nodiscard]] uint8_t peekTrackReg (EmuTime time) const;
34
	[[nodiscard]] uint8_t peekSectorReg(EmuTime time) const;
35
	[[nodiscard]] uint8_t peekDataReg  (EmuTime time) const;
36
37
	void setCommandReg(uint8_t value, EmuTime time);
38
	void setTrackReg  (uint8_t value, EmuTime time);
39
	void setSectorReg (uint8_t value, EmuTime time);
40
	void setDataReg   (uint8_t value, EmuTime time);
41
42
	[[nodiscard]] bool getIRQ (EmuTime time) const;
43
	[[nodiscard]] bool getDTRQ(EmuTime time) const;
44
45
	[[nodiscard]] bool peekIRQ (EmuTime time) const;
46
	[[nodiscard]] bool peekDTRQ(EmuTime time) const;
47
48
	template<typename Archive>
49
	void serialize(Archive& ar, unsigned version);
50
51
	// public for serialize
52
	enum class FSM : uint8_t {
53
		NONE,
54
		SEEK,
55
		TYPE2_LOADED,
56
		TYPE2_NOT_FOUND,
57
		TYPE2_ROTATED,
58
		CHECK_WRITE,
59
		PRE_WRITE_SECTOR,
60
		WRITE_SECTOR,
61
		POST_WRITE_SECTOR,
62
		TYPE3_LOADED,
63
		TYPE3_ROTATED,
64
		WRITE_TRACK,
65
		READ_TRACK,
66
		IDX_IRQ
67
	};
68
69
private:
70
	void executeUntil(EmuTime time) override;
71
72
	void startType1Cmd(EmuTime time);
73
74
	void seek(EmuTime time);
75
	void step(EmuTime time);
76
	void seekNext(EmuTime time);
77
	void endType1Cmd(EmuTime time);
78
79
	void startType2Cmd   (EmuTime time);
80
	void type2Loaded     (EmuTime time);
81
	void type2Search     (EmuTime time);
82
	void type2NotFound   (EmuTime time);
83
	void type2Rotated    (EmuTime time);
84
	void startReadSector (EmuTime time);
85
	void startWriteSector(EmuTime time);
86
	void checkStartWrite (EmuTime time);
87
	void preWriteSector  (EmuTime time);
88
	void writeSectorData (EmuTime time);
89
	void postWriteSector (EmuTime time);
90
91
	void startType3Cmd   (EmuTime time);
92
	void type3Loaded     (EmuTime time);
93
	void type3Rotated    (EmuTime time);
94
	void readAddressCmd  (EmuTime time);
95
	void readTrackCmd    (EmuTime time);
96
	void startWriteTrack (EmuTime time);
97
	void writeTrackData  (EmuTime time);
98
99
	void startType4Cmd(EmuTime time);
100
101
	void endCmd(EmuTime time);
102
103
	void setDrqRate(unsigned trackLength);
104
	[[nodiscard]] bool isReady() const;
105
106
	void schedule(FSM state, EmuTime time);
107
108
private:
109
	DiskDrive& drive;
110
	MSXCliComm& cliComm;
111
112
	// DRQ is high iff current time is past this time.
113
	//  This clock ticks at the 'byte-rate' of the current track,
114
	//  typically '6250 bytes/rotation * 5 rotations/second'.
115
	DynamicClock drqTime{EmuTime::infinity()};
116
117
	// INTRQ is high iff current time is past this time.
118
	EmuTime irqTime = EmuTime::infinity();
119
120
	EmuTime pulse5 = EmuTime::infinity(); // time at which the 5th index pulse will be received
121
122
	// HLD/HLT timing
123
	// 1) now < hldTime   (typically: hldTime == EmuTime::infinity)
124
	//     ==> HLD=false, WD2793 did not request head to be loaded
125
	// 2) hldTime <= now < hldTime + LOAD
126
	//     ==> HLD=true, HLT=false, head loading is in progress
127
	// 3) hldTime + LOAD <= now < hldTime + LOAD + IDLE
128
	//     ==> HLD=true, HLT=true, head is loaded
129
	// 4) hldTime + LOAD + IDLE <= now
130
	//     ==> HLD=false, idle for 15 revolutions HLD made deactive again
131
	// Note: is all MSX machines I've checked so far, WD2793 pins
132
	//  - HLD (pin 28) is unconnected
133
	//  - HLT (pin 40) is connected to +5V
134
	// This means there is no head-load delay, or IOW as soon as the WD2793
135
	// requests to load the disk head, the drive responds with "ok, done".
136
	// So 'LOAD' is zero, and phase 2) doesn't exist. Therefor the current
137
	// implementation mostly ignores 'LOAD'.
138
	EmuTime hldTime = EmuTime::infinity(); // HLD=false
139
140
	RawTrack::Sector sectorInfo;
141
	int dataCurrent   = 0; // which byte in track is next to be read/write
142
	int dataAvailable = 0; // how many bytes left to read/write
143
144
	CRC16 crc;
145
146
	FSM fsmState;
147
	uint8_t statusReg;
148
	uint8_t commandReg = 0;
149
	uint8_t sectorReg;
150
	uint8_t trackReg;
151
	uint8_t dataReg;
152
	uint8_t dataOutReg = 0;
153
154
	bool directionIn;
155
	bool immediateIRQ;
156
	bool lastWasA1 = false;
157
	bool dataRegWritten = false;
158
	bool lastWasCRC = false;
159
160
	const bool isWD1770;
161
};
162
SERIALIZE_CLASS_VERSION(WD2793, 12);
163
164
} // namespace openmsx
165
166
#endif