-
Notifications
You must be signed in to change notification settings - Fork 16
/
ZynqBufferManager.cpp
105 lines (87 loc) · 3.44 KB
/
ZynqBufferManager.cpp
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
// Copyright (c) 2013-2014 Josh Blum
// SPDX-License-Identifier: BSL-1.0
#include "ZynqDMASupport.hpp"
#include <Pothos/Util/OrderedQueue.hpp>
#include <memory>
#include <iostream>
template <pzdud_dir_t dir>
class ZynqDMABufferManager :
public Pothos::BufferManager,
public std::enable_shared_from_this<ZynqDMABufferManager<dir>>
{
public:
ZynqDMABufferManager(std::shared_ptr<pzdud_t> engine):
_engine(engine)
{
return;
}
~ZynqDMABufferManager(void)
{
if (this->isInitialized())
{
pzdud_halt(_engine.get());
pzdud_free(_engine.get());
}
}
void init(const Pothos::BufferManagerArgs &args)
{
_readyBuffs = Pothos::Util::OrderedQueue<Pothos::ManagedBuffer>(args.numBuffers);
int ret = pzdud_alloc(_engine.get(), args.numBuffers, args.bufferSize);
if (ret != PZDUD_OK) throw Pothos::Exception("ZynqBufferManager::pzdud_alloc()", std::to_string(ret));
ret = pzdud_init(_engine.get(), false/*no initial release*/);
if (ret != PZDUD_OK) throw Pothos::Exception("ZynqBufferManager::pzdud_init()", std::to_string(ret));
//this will flag the manager as initialized after the allocation above
Pothos::BufferManager::init(args);
//create all the buffer containers...
for (size_t handle = 0; handle < args.numBuffers; handle++)
{
auto container = std::make_shared<int>(0);
void *addr = pzdud_addr(_engine.get(), handle);
auto sharedBuff = Pothos::SharedBuffer(size_t(addr), args.bufferSize, container);
Pothos::ManagedBuffer buffer;
buffer.reset(this->shared_from_this(), sharedBuff, handle);
}
}
bool empty(void) const
{
return _readyBuffs.empty();
}
void pop(const size_t numBytes)
{
//boiler-plate to pop from the queue and set the front buffer
assert(not _readyBuffs.empty());
auto buff = _readyBuffs.front();
_readyBuffs.pop();
//prepare the next buffer in the queue
if (_readyBuffs.empty()) this->setFrontBuffer(Pothos::BufferChunk::null());
else this->setFrontBuffer(_readyBuffs.front());
//pop == release in the dma to stream direction
//this manager in an output port upstream of dma sink
if (dir == PZDUD_MM2S)
{
pzdud_release(_engine.get(), buff.getSlabIndex(), numBytes);
}
}
void push(const Pothos::ManagedBuffer &buff)
{
assert(buff.getSlabIndex() < _readyBuffs.capacity());
_readyBuffs.push(buff, buff.getSlabIndex());
//prepare the next buffer in the queue
if (not _readyBuffs.empty()) this->setFrontBuffer(_readyBuffs.front());
//push == release in the stream to DMA direction
//this manager in the output port on the dma source
if (dir == PZDUD_S2MM)
{
pzdud_release(_engine.get(), buff.getSlabIndex(), 0/*unused*/);
}
}
private:
Pothos::Util::OrderedQueue<Pothos::ManagedBuffer> _readyBuffs;
std::shared_ptr<pzdud_t> _engine;
};
Pothos::BufferManager::Sptr makeZynqDMABufferManager(std::shared_ptr<pzdud_t> engine, const pzdud_dir_t dir)
{
if (dir == PZDUD_S2MM) return Pothos::BufferManager::Sptr(new ZynqDMABufferManager<PZDUD_S2MM>(engine));
if (dir == PZDUD_MM2S) return Pothos::BufferManager::Sptr(new ZynqDMABufferManager<PZDUD_MM2S>(engine));
return Pothos::BufferManager::Sptr();
}