.. _program_listing_file_tohost_buffer.hpp: Program Listing for File tohost_buffer.hpp ========================================== |exhale_lsh| :ref:`Return to documentation for file ` (``tohost_buffer.hpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef TOHOST_BUFFER_H_ #define TOHOST_BUFFER_H_ #include #include #include #include #include #include #include #include #include "device.hpp" #include "cmem_buffer.hpp" #include "block.hpp" #if REGMAP_VERSION < 0x500 #define IRQ_WRAP_AROUND_FROM_HOST 0 #define IRQ_WRAP_AROUND_TO_HOST 1 #define IRQ_DATA_AVAILABLE 2 #define IRQ_FIFO_FULL_FROM_HOST 3 #define IRQ_BUSY_CHANGE_TO_HOST 6 #define IRQ_FIFO_FULL_TO_HOST 7 #else #define IRQ_DATA_AVAILABLE 0 #define IRQ_XOFF_TO_HOST 5 #define IRQ_BUSY_CHANGE_TO_HOST 6 #define IRQ_FIFO_FULL_TO_HOST 7 #endif #define MIN(X, Y) (((X) < (Y)) ? (X) : (Y)) class ToHostBuffer { public: ToHostBuffer(int dmaid, std::shared_ptr d); //Interrupts void irq_data_enable() {m_device->irq_enable(m_irq_on_data);} void irq_data_disable(){m_device->irq_disable(m_irq_on_data);} void irq_busy_enable() {m_device->irq_enable(IRQ_BUSY_CHANGE_TO_HOST);} void irq_busy_disable(){m_device->irq_disable(IRQ_BUSY_CHANGE_TO_HOST);} std::shared_ptr get_device(){return m_device;} int get_dmaid() const {return m_dmaid;} std::vector get_elinks(){return m_device->read_enabled_elinks(m_dmaid);} std::vector get_elinks_of_type(elink_type_t t){return m_device->get_enabled_elinks_of_type(m_dmaid, t);}; std::vector> split_elinks_of_type(elink_type_t t, size_t n); //DMA buffer operations virtual void allocate_buffer(size_t size, const std::string& name, bool vmem, bool free_previous_cmem=true) = 0; virtual void dma_start_continuous() = 0; //start_circular_dma virtual void dma_wait_for_data_irq() = 0; //wait_data_available virtual size_t dma_bytes_available() = 0; //bytes_available virtual size_t dma_bytes_available_nowrap() = 0; //bytes_available_to_read virtual bool dma_is_full() = 0; virtual uint64_t dma_get_write_ptr() = 0; virtual uint64_t dma_get_read_ptr() = 0; virtual void dma_set_read_ptr_vaddr(uint64_t v_addr) = 0; virtual void dma_set_read_ptr_paddr(uint64_t p_addr) = 0; virtual uint64_t dma_get_read_offset() = 0; virtual uint64_t dma_get_write_offset() = 0; virtual void dma_advance_read_ptr(size_t bytes) = 0; uint64_t dma_get_vaddr(){return m_buffer->vaddr;} size_t dma_get_size(){return m_buffer->size;} uint32_t reader_register(bool zc_flag); bool reader_is_data_available(uint32_t reader_id); size_t reader_get_available_bytes(uint32_t reader_id); std::span reader_get_available_blocks(uint32_t reader_id); void reader_advance_read_ptr(uint32_t reader_id, uint32_t read_bytes, uint32_t sent_bytes); bool has_zero_copy_reader() const {return m_has_zero_copy_reader;} void set_zero_copy_reader(){m_has_zero_copy_reader = true;} void stop(){m_stop_flag = true;} bool is_stopped() const {return m_stop_flag;} uint32_t dma_get_free_MB(); void dma_increase_irq_counter(){++m_irq_counter;} uint64_t dma_get_irq_counter() const {return m_irq_counter;} protected: int m_dmaid; std::shared_ptr m_device; unsigned int m_block_size; int m_irq_on_data; //IRQ_DATA_AVAILABLE + m_dmaid; uint64_t m_irq_counter; size_t m_size; bool m_stop_flag; //stop flag for readers bool m_has_zero_copy_reader; size_t m_min_bytes_sent; std::mutex m_mutex; std::unique_ptr m_buffer; //support for multiple ToHostBufferReader std::vector m_bytes_read; //read from DMA buffer std::vector m_bytes_sent; //different from read only for zc mode size_t dma_compute_bytes_to_read(uint64_t rd_ptr, uint64_t wr_ptr, bool even); }; inline size_t ToHostBuffer::dma_compute_bytes_to_read(uint64_t rd_ptr, uint64_t wr_ptr, bool even) { if( wr_ptr > rd_ptr ) { return wr_ptr - rd_ptr; } else if( wr_ptr < rd_ptr ) { return m_buffer->size + wr_ptr -rd_ptr; } else { // dma_ptr == buf->pc_ptr if( even ) { return 0; // Buffer empty } else { return m_buffer->size; // Buffer full } } } class FlxToHostBuffer : public ToHostBuffer { public: FlxToHostBuffer(int m_dmaid, std::shared_ptr d); ~FlxToHostBuffer(); void allocate_buffer(size_t size, const std::string& name, bool vmem, bool free_previous_cmem=false) override; void dma_start_continuous() override; void dma_wait_for_data_irq() override; size_t dma_bytes_available() override; //uint32_t dma_get_free_MB() override; size_t dma_bytes_available_nowrap() override; bool dma_is_full() override; uint64_t dma_get_write_ptr() override; uint64_t dma_get_read_ptr() override; void dma_set_read_ptr_vaddr(uint64_t v_addr) override; void dma_set_read_ptr_paddr(uint64_t p_addr) override; uint64_t dma_get_read_offset() override; uint64_t dma_get_write_offset() override; void dma_advance_read_ptr(size_t bytes) override; }; class FileToHostBuffer : public ToHostBuffer { public: FileToHostBuffer(int m_dmaid, std::shared_ptr d, std::string& filename, unsigned int block_rate, bool repeat); ~FileToHostBuffer(); void allocate_buffer(size_t size, const std::string& name, bool vmem, bool free_previous_cmem=true) override; void dma_start_continuous() override; void dma_wait_for_data_irq() override; size_t dma_bytes_available() override; //uint32_t dma_get_free_MB() override; size_t dma_bytes_available_nowrap() override; bool dma_is_full() override; uint64_t dma_get_write_ptr() override; uint64_t dma_get_read_ptr() override; void dma_set_read_ptr_vaddr(uint64_t v_addr) override; void dma_set_read_ptr_paddr(uint64_t p_addr) override; uint64_t dma_get_read_offset() override; uint64_t dma_get_write_offset() override; void dma_advance_read_ptr(size_t bytes) override; private: void set_read_ptr_paddr(uint64_t p_addr); void write_in_dma_buffer(); size_t limit_block_rate(size_t max_blocks); size_t blocks_to_write(uint64_t rd_ptr, uint64_t wr_ptr, bool even); void throttle_writer(const std::chrono::nanoseconds &elapsed, size_t count); void writer_updates_fw_ptr(size_t written_blocks); bool reset_file(); private: //regulate the concurrent access to read and write pointers mutable std::shared_mutex m_driver_mutex; //emulate MSI-X on_data interrupts std::condition_variable m_irq_cond; mutable std::mutex m_irq_mutex; //suspend the card emulator thread when the DMA is full std::condition_variable m_writer_cond; mutable std::mutex m_stop_writer_mutex; unsigned int m_block_rate; bool m_repeat; bool m_rd_odd; bool m_wr_odd; FILE* m_fp; std::thread m_writer_thread; }; #endif /* TOHOST_BUFFER_H_ */