Program Listing for File fromhost_buffer_file.cpp
↰ Return to documentation for file (fromhost_buffer_file.cpp
)
#include "fromhost_buffer.hpp"
#include "log.hpp"
#include <cstdint>
FileFromHostBuffer::FileFromHostBuffer(std::shared_ptr<Device> d, std::string &filename, bool fifo)
: FromHostBuffer(d),
m_file(filename, m_encoder.get_block_size(), DiskIO::FWRITE, fifo),
m_rd_odd(false),
m_wr_odd(false){};
FileFromHostBuffer::~FileFromHostBuffer()
{
m_reader_thread.join();
LOG_INFO("Reader thread joined");
}
void FileFromHostBuffer::allocate_buffer(size_t size,
const std::string &name,
bool vmem, bool free_previous_cmem)
{
m_size = size;
if (vmem)
{
m_buffer = std::make_unique<VmemBuffer>(size);
}
else
{
m_buffer = std::make_unique<CmemBuffer>(size, name, free_previous_cmem);
}
uint8_t *vaddr = reinterpret_cast<uint8_t *>(m_buffer->vaddr);
m_encoder.set_destination_parameters(vaddr, m_buffer->size);
}
void FileFromHostBuffer::dma_start_continuous()
{
m_buffer->pend = m_buffer->paddr + m_buffer->size;
m_buffer->pc_ptr = m_buffer->paddr;
m_buffer->emu_fw_ptr = m_buffer->paddr;
LOG_INFO(" cmem buffer [0x%x,0x%x] %lu Blocks", m_buffer->paddr, m_buffer->pend, m_buffer->size/1024);
LOG_INFO(" cmem virtual address 0x%x", m_buffer->vaddr);
LOG_INFO(" fw_ptr 0x%x", m_buffer->emu_fw_ptr);
LOG_INFO(" pc_ptr 0x%x", m_buffer->pc_ptr);
LOG_INFO("Spawning buffer-to-file reader thread...");
m_reader_thread = std::thread(&FileFromHostBuffer::copy_from_dma_buffer_to_file, this);
}
void FileFromHostBuffer::dma_start_circular_trickle_buffer()
{
std::unique_lock<std::shared_mutex> lock(m_driver_mutex);
m_buffer->emu_fw_ptr = m_buffer->paddr;
m_buffer->pend = m_buffer->paddr + m_trickle_config_size;
m_fw_reading_trickle.store(true);
}
size_t FileFromHostBuffer::dma_free_bytes()
{
std::shared_lock<std::shared_mutex> lock(m_driver_mutex);
bool even = (m_rd_odd == m_wr_odd);
return dma_compute_free_bytes(m_buffer->emu_fw_ptr, m_buffer->pc_ptr, even);
}
bool FileFromHostBuffer::dma_is_full()
{
std::shared_lock<std::shared_mutex> lock(m_driver_mutex);
return ((m_buffer->emu_fw_ptr == m_buffer->pc_ptr) and (m_rd_odd != m_wr_odd));
}
bool FileFromHostBuffer::dma_is_empty()
{
std::shared_lock<std::shared_mutex> lock(m_driver_mutex);
return ((m_buffer->emu_fw_ptr == m_buffer->pc_ptr) and (m_rd_odd == m_wr_odd));
}
// offset read (fw emu)
uint64_t FileFromHostBuffer::dma_get_read_offset()
{
std::shared_lock<std::shared_mutex> lock(m_driver_mutex);
return (m_buffer->emu_fw_ptr - m_buffer->paddr);
}
// offset write (pc)
uint64_t FileFromHostBuffer::dma_get_write_offset()
{
std::shared_lock<std::shared_mutex> lock(m_driver_mutex);
return (m_buffer->pc_ptr - m_buffer->paddr);
}
// offset write (pc)
void FileFromHostBuffer::dma_set_write_offset(uint64_t offset)
{
uint64_t p_addr = m_buffer->paddr + offset;
set_write_ptr_paddr(p_addr);
}
// vaddr
uint64_t FileFromHostBuffer::dma_get_write_ptr()
{
std::shared_lock<std::shared_mutex> lock(m_driver_mutex);
return (m_buffer->pc_ptr - m_buffer->paddr + m_buffer->vaddr);
}
void FileFromHostBuffer::dma_advance_write_ptr(size_t bytes)
{
if (bytes == 0)
{
return;
}
std::scoped_lock<std::shared_mutex> lock(m_driver_mutex);
m_buffer->emu_fw_ptr += bytes;
if (m_buffer->emu_fw_ptr == m_buffer->pend)
{
m_buffer->emu_fw_ptr = m_buffer->paddr;
m_wr_odd = !m_wr_odd;
}
}
void FileFromHostBuffer::set_write_ptr_paddr(uint64_t p_addr)
{
// write ptr := pc_ptr
std::scoped_lock<std::shared_mutex> lock(m_driver_mutex);
if (p_addr == m_buffer->pc_ptr)
{
return;
}
if (p_addr < m_buffer->pc_ptr)
{
unsigned int diff = (p_addr - m_buffer->pc_ptr);
if (diff > 0.1 * m_buffer->size)
{
m_wr_odd = !m_wr_odd;
}
}
m_buffer->pc_ptr = p_addr;
m_reader_cond.notify_one();
}
void FileFromHostBuffer::copy_from_dma_buffer_to_file()
{
LOG_INFO("read_from_dma_buffer thread started");
uint64_t data_offset;
int blocks_to_copy(0), copied_blocks(0);
while (m_run_flag.load())
{
{
// wait for data in the FromHost DMA buffer
std::unique_lock<std::mutex> lk(m_wake_reader_mutex);
using namespace std::chrono_literals;
m_reader_cond.wait_for(lk, 500ms, [&] { return !dma_is_empty(); });
}
{
// copy current addresses
std::shared_lock<std::shared_mutex> lock(m_driver_mutex);
bool even = (m_rd_odd == m_wr_odd);
data_offset = m_buffer->emu_fw_ptr - m_buffer->paddr;
blocks_to_copy = (m_buffer->size - dma_compute_free_bytes(m_buffer->emu_fw_ptr, m_buffer->pc_ptr, even)) / m_encoder.get_block_size();
}
LOG_TRACE("Blocks to copy %lu", blocks_to_copy);
// What it does: if there is no trickle mode, it works normally. All the blocks are copied and the read pointer is advanced.
// If the trickle mode is active (m_fw_reading_trickle is TRUE), it emulates the firmware by reading the buffer a maximum of 100 times to avoid an endless loop.
int n_copies = 0;
do
{
copied_blocks = 0;
while (blocks_to_copy > copied_blocks)
{
uint64_t input = (data_offset + copied_blocks * m_encoder.get_block_size()) % m_buffer->size;
void *input_ptr = reinterpret_cast<void *>(input + m_buffer->vaddr);
size_t max_blocks = blocks_to_copy - copied_blocks;
LOG_DBG("input ptr 0x%lx, buffer start 0x%lx, end 0x%lx size 0%lu", input_ptr, m_buffer->vaddr, m_buffer->vaddr + m_buffer->size, m_buffer->size);
copied_blocks += m_file.block_write(input_ptr, max_blocks);
LOG_DBG("%lu blocks copied to disk", copied_blocks);
}
}
while (m_fw_reading_trickle.load() && n_copies++ < 100);
dma_advance_read_ptr(copied_blocks * m_encoder.get_block_size());
}
}
void FileFromHostBuffer::dma_advance_read_ptr(size_t bytes)
{
LOG_TRACE("Advancing of %lu bytes", bytes);
if (bytes == 0)
{
return;
}
std::scoped_lock<std::shared_mutex> lock(m_driver_mutex);
m_buffer->emu_fw_ptr += bytes;
if (m_buffer->emu_fw_ptr == m_buffer->pend)
{
m_buffer->emu_fw_ptr = m_buffer->paddr;
m_rd_odd = !m_rd_odd;
}
}