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