-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpc_dma.cpp
More file actions
108 lines (75 loc) · 2.39 KB
/
pc_dma.cpp
File metadata and controls
108 lines (75 loc) · 2.39 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
#include "pc_dma.hpp"
#include <cstdint>
#include "os_realmem.hpp"
#include "pc_bus.hpp"
using std::uint8_t;
using std::uint16_t;
using std::uint32_t;
namespace rqdq {
namespace {
inline uint8_t lo(uint16_t value) { return value & 0x00ff; }
inline uint8_t hi(uint16_t value) { return value >> 8; }
} // namespace
namespace pc {
DMABuffer::DMABuffer(std::uint16_t sizeInWords)
:realMem_(sizeInWords*2*2),
sizeInWords_(sizeInWords) {
uint32_t phy = realMem_.GetRealAddr();
uint32_t rel = phy % 65536;
if ((rel + (sizeInWords*2)) > 65536) {
// if the start addr would cross
// a 64k page boundary, advance
// to the start of the next page
phy = (phy+65536) & 0xff0000; }
addr_ = phy; }
const int pagePorts[8] = {
0x87, 0x83, 0x81, 0x82,
0x00, 0x8b, 0x89, 0x8a };
DMAChannel::DMAChannel(int dcn)
:controllerNum_(dcn < 4 ? 0 : 1),
channelNum_(dcn < 4 ? dcn : dcn - 4),
ioBase_(controllerNum_ == 0 ? 0x00 : 0xc0),
stride_(controllerNum_ == 0 ? 1 : 2),
maskPort_(ioBase_ + 0x0a*stride_),
modePort_(ioBase_ + 0x0b*stride_),
clearPtrPort_(ioBase_ + 0x0c*stride_),
baseAddrPort_(ioBase_+channelNum_*2*stride_),
countPort_(ioBase_+channelNum_*2*stride_+stride_),
pagePort_(pagePorts[dcn]),
stopMask_(channelNum_ + 0x04),
startMask_(channelNum_ + 0x00),
mode_(channelNum_ + 0x58) {} // 010110xx
DMAChannel::~DMAChannel() {
Stop(); }
void DMAChannel::Setup(const DMABuffer& buf) const {
Stop();
ClearFlipFlop();
SetMode();
SetMemoryAddr(buf);
SetMemorySize(buf);
Start(); }
inline void DMAChannel::ClearFlipFlop() const {
OutB(clearPtrPort_, 0x00); }
inline void DMAChannel::SetMode() const {
OutB(modePort_, mode_); }
void DMAChannel::SetMemoryAddr(const DMABuffer& buf) const {
if (controllerNum_ == 0) {
OutB(baseAddrPort_, lo(buf.addr_%65536));
OutB(baseAddrPort_, hi(buf.addr_%65536)); }
else {
OutB(baseAddrPort_, lo(buf.Offset16()));
OutB(baseAddrPort_, hi(buf.Offset16())); }
OutB(pagePort_, buf.Page()); }
void DMAChannel::SetMemorySize(const DMABuffer& buf) const {
if (controllerNum_ == 0) {
OutB(countPort_, lo(buf.sizeInWords_*2 - 1));
OutB(countPort_, hi(buf.sizeInWords_*2 - 1)); }
else {
OutB(countPort_, lo(buf.sizeInWords_ - 1));
OutB(countPort_, hi(buf.sizeInWords_ - 1)); }}
void DMAChannel::Stop() const {
OutB(maskPort_, stopMask_); }
void DMAChannel::Start() const {
OutB(maskPort_, startMask_); }
} // namespace pc
} // namespace rqdq