1 /*
2  *  Copyright (C) 2002-2021  The DOSBox Team
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License along
15  *  with this program; if not, write to the Free Software Foundation, Inc.,
16  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #ifndef DOSBOX_DMA_H
20 #define DOSBOX_DMA_H
21 
22 #include "dosbox.h"
23 
24 #include <cassert>
25 #include <functional>
26 
27 #include "inout.h"
28 #include "support.h"
29 
30 enum DMAEvent {
31 	DMA_REACHED_TC,
32 	DMA_MASKED,
33 	DMA_UNMASKED,
34 };
35 
36 class DmaChannel;
37 using DMA_CallBack = std::function<void(DmaChannel *chan, DMAEvent event)>;
38 
39 class DmaChannel {
40 public:
41 	Bit32u pagebase;
42 	Bit16u baseaddr;
43 	Bit32u curraddr;
44 	Bit16u basecnt;
45 	Bit16u currcnt;
46 	Bit8u channum;
47 	Bit8u pagenum;
48 	Bit8u DMA16;
49 	bool increment;
50 	bool autoinit;
51 //	Bit8u trantype; //Not used at the moment
52 	bool masked;
53 	bool tcount;
54 	bool request;
55 	DMA_CallBack callback;
56 
57 	DmaChannel(uint8_t num, bool dma16);
58 
DoCallBack(DMAEvent event)59 	void DoCallBack(DMAEvent event) {
60 		if (callback)
61 			callback(this, event);
62 	}
SetMask(bool _mask)63 	void SetMask(bool _mask) {
64 		masked=_mask;
65 		DoCallBack(masked ? DMA_MASKED : DMA_UNMASKED);
66 	}
Register_Callback(DMA_CallBack _cb)67 	void Register_Callback(DMA_CallBack _cb) {
68 		callback = _cb;
69 		SetMask(masked);
70 		if (callback) Raise_Request();
71 		else Clear_Request();
72 	}
ReachedTC(void)73 	void ReachedTC(void) {
74 		tcount=true;
75 		DoCallBack(DMA_REACHED_TC);
76 	}
SetPage(Bit8u val)77 	void SetPage(Bit8u val) {
78 		pagenum=val;
79 		pagebase=(pagenum >> DMA16) << (16+DMA16);
80 	}
Raise_Request(void)81 	void Raise_Request(void) {
82 		request=true;
83 	}
Clear_Request(void)84 	void Clear_Request(void) {
85 		request=false;
86 	}
87 	Bitu Read(Bitu size, Bit8u * buffer);
88 	Bitu Write(Bitu size, Bit8u * buffer);
89 };
90 
91 class DmaController {
92 private:
93 	bool flipflop;
94 	DmaChannel *dma_channels[4];
95 
96 public:
97 	IO_ReadHandleObject DMA_ReadHandler[0x12];
98 	IO_WriteHandleObject DMA_WriteHandler[0x12];
99 
DmaController(uint8_t ctrl)100 	DmaController(uint8_t ctrl) : flipflop(false)
101 	{
102 		assert(ctrl == 0 || ctrl == 1); // first or second DMA controller
103 		constexpr auto n = ARRAY_LEN(dma_channels);
104 		for (uint8_t i = 0; i < n; ++i)
105 			dma_channels[i] = new DmaChannel(i + ctrl * n, ctrl == 1);
106 	}
107 
108 	DmaController(const DmaController &) = delete; // prevent copy
109 	DmaController &operator=(const DmaController &) = delete; // prevent assignment
110 
~DmaController()111 	~DmaController()
112 	{
113 		for (auto *channel : dma_channels)
114 			delete channel;
115 	}
116 
GetChannel(uint8_t chan)117 	DmaChannel *GetChannel(uint8_t chan) const
118 	{
119 		constexpr auto n = ARRAY_LEN(dma_channels);
120 		if (chan < n)
121 			return dma_channels[chan];
122 		else
123 			return nullptr;
124 	}
125 
126 	void WriteControllerReg(io_port_t reg, io_val_t value, io_width_t width);
127 	uint16_t ReadControllerReg(io_port_t reg, io_width_t width);
128 };
129 
130 DmaChannel * GetDMAChannel(Bit8u chan);
131 
132 void CloseSecondDMAController(void);
133 bool SecondDMAControllerAvailable(void);
134 
135 void DMA_SetWrapping(Bitu wrap);
136 
137 #endif
138