#include<cstdio>
#include<cstring>
#include<sys/ioctl.h>
#include<linux/ioctl.h>
#include<vector>
#include<string>
#include <algorithm>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdint.h>
#include "ftplib.h"
#include <ctime>
using namespace std;
#define DMA_ALLOC_DEV "/dev/axidma_alloc"
#define __ALIGNED(x) __attribute__ ((aligned (x)))
#define BIT(x) (1<<(x))
#define XILINX_DMA_NUM_APP_WORDS 0x5
int32_t fpga_fd;
int32_t axidma_tx_fd;
int32_t axidma_rx_fd;
int32_t axidma_sg_tx_fd;
char *RX_AXI_DMAC_VIRTUAL;
char *TX_AXI_DMAC_VIRTUAL;
char *TX_SG_DMAC_VIRTUAL;
uint32_t *FPGA_VIRTUAL;
typedef bool completed;
#define RX_AXI_DMAC_BASE 0x40400000
#define TX_AXI_DMAC_BASE 0x40420000
#define FPGA_CTR_BASE 0x43c10000
#define TX_SG_DMAC_BASE 0x40410000
#define WFPGA(offset,val) *(volatile uint32_t*)(FPGA_VIRTUAL+(offset)) = val
#define RFPGA(offset) *(volatile uint32_t*)(FPGA_VIRTUAL+(offset))
#define RX_AXI_DMA_WRITE(offset,val) *(volatile uint32_t*)(RX_AXI_DMAC_VIRTUAL+(offset))=val
#define RX_AXI_DMA_READ(offset) *(volatile uint32_t*)(RX_AXI_DMAC_VIRTUAL+(offset))
#define TX_AXI_DMA_WRITE(offset,val) *(volatile uint32_t*)(TX_AXI_DMAC_VIRTUAL+(offset)) = val
#define TX_AXI_DMA_READ(offset) *(volatile uint32_t*)(TX_AXI_DMAC_VIRTUAL+(offset))
#define TX_AXI_SG_DMA_WRITE(offset,val) *(volatile uint32_t*)(TX_SG_DMAC_VIRTUAL+(offset))=val
#define TX_AXI_SG_DMA_READ(offset) *(volatile uint32_t*)(TX_SG_DMAC_VIRTUAL+(offset))
#define FATAL do { fprintf(stderr, "Error at line %d, file %s (%d) [%s]\n", \
__LINE__, __FILE__, errno, strerror(errno)); exit(1); } while(0)
#define XILINX_DMA_MM2S_CTRL_OFFSET 0x0000
#define XILINX_DMA_S2MM_CTRL_OFFSET 0x0030
#define XILINX_DMA_REG_DMACR 0x0000
#define XILINX_DMA_REG_DMASR 0x0004
#define XILINX_DMACR_RESET BIT(2)
#define XILINX_SAMPLE_DMA_MM2S_SA 0x18
#define XILINX_SAMPLE_DMA_MM2S_LENGTH 0x28
#define XILINX_SAMPLE_DMA_S2MM_SA 0x48
#define XILINX_SAMPLE_DMA_S2MM_LENGTH 0x58
#define DMAC_REGISTER_SET 0x17003
#define COMPLETED_DMA_OPT 0x2
#define XAXIDMA_DESC_LSB_MASK 0xFFFFFFC0f
#define XAXIDMA_BD_CTRL_TXSOF_MASK 0x08000000
#define XAXIDMA_BD_CTRL_TXEOF_MASK 0x04000000
#define XAXIDMA_IRQ_IOC_MASK 0x00001000
#define XAXIDMA_IRQ_DELAY_MASK 0x00002000
#define XAXIDMA_IRQ_ERROR_MASK 0x00004000
#define XAXIDMA_IRQ_ALL_MASK 0x00007000
#define XAXIDMA_CDESC_OFFSET 0x00000008
#define XAXIDMA_TDESC_OFFSET 0x00000010
#define XAXIDMA_CYCLIC_BD_EN BIT(4)
completed dma_reciver(uint32_t phy, uint32_t lenth);
struct fpga{
uint32_t offset;
uint32_t value;
};
struct dma_addr_t{
size_t size;
uint32_t phy_dma_addr;
};
struct Ftp{
std::string get_filename;
std::string login_name;
std::string login_password;
std::string ftp_addr;
std::string put_filename;
Ftp(){}
Ftp(std::string f,std::string ln,std::string lp,std::string fa,std::string pf):get_filename(f), \
login_name(ln),login_password(lp),ftp_addr(fa),put_filename(pf){}
int32_t ftp_get();
int32_t ftp_put(char* buf,uint32_t size);
};
struct xilinx_axidma_desc_hw{
uint32_t next_desc;
uint32_t next_desc_msb;
uint32_t buf_addr;
uint32_t buf_addr_msb;
uint32_t reserved1;
uint32_t reserved2;
uint32_t control;
uint32_t status;
uint32_t app[XILINX_DMA_NUM_APP_WORDS];
}__ALIGNED(64);
#define FPGA_MAG 'C'
#define FPGA_READ _IOC(_IOC_READ,FPGA_MAG,2,sizeof(struct fpga))
template<class T>
void mem_write(T address,T value){
void *map_base,*virt_addr;
char dev_name[] = "/dev/mem";
int fd;
unsigned page_size,mapped_size,offset_in_page;
off_t target = address;
fd = open(dev_name,O_RDWR|O_SYNC);
if(fd < 0) FATAL;
mapped_size = page_size = sysconf(_SC_PAGESIZE);
offset_in_page = (unsigned)target & (page_size -1);
if((offset_in_page + 32) > page_size){
mapped_size *=2;
}
map_base = mmap(NULL,mapped_size,PROT_READ|PROT_WRITE, MAP_SHARED,fd,target &~(off_t)(page_size-1));
virt_addr = (char*)map_base + offset_in_page;
if(virt_addr == (void*)-1) FATAL;
*(volatile T*)virt_addr = value;
if(munmap(map_base,mapped_size) == -1) FATAL;
close(fd);
}
template<class T>
void mem_read(T address,T& value){
void *map_base,*virt_addr;
char dev_name[] = "/dev/mem";
int fd;
unsigned page_size,mapped_size,offset_in_page;
off_t target = address;
fd = open(dev_name,O_RDWR|O_SYNC);
if(fd < 0) FATAL;
mapped_size = page_size = sysconf(_SC_PAGESIZE);
offset_in_page = (unsigned)target & (page_size -1);
if((offset_in_page + 32) > page_size){
mapped_size *=2;
}
map_base = mmap(NULL,mapped_size,PROT_READ|PROT_WRITE, MAP_SHARED,fd,target &~(off_t)(page_size-1));
virt_addr = (char*)map_base + offset_in_page;
if(virt_addr == (void*)-1) FATAL;
value = *(volatile T*)virt_addr;
if(munmap(map_base,mapped_size) == -1) FATAL;
close(fd);
}
template<class T>
void mem_write(std::vector<std::pair<T,T>> w){
for(int i = 0 ; i < w.size(); i++){
mem_write<T>(w[i].first,w[i].second);
}
}
template<class T>
void mem_read(std::vector<std::pair<T,T&>> r){
for(int i = 0 ; i < r.size(); i++){
mem_read<T>(r[i].first,r[i].second);
}
}
void* dma_mem_alloc(int &fd,int32_t size){
fd = open(DMA_ALLOC_DEV,O_RDWR);
return mmap(NULL,size,PROT_READ|PROT_WRITE, MAP_SHARED,fd,0);
}
void dma_phy_addr_get(int32_t fd,uint32_t& phy,uint32_t& size){
dma_addr_t dma_phy;
ioctl(fd,FPGA_READ,&dma_phy);
phy = dma_phy.phy_dma_addr;
size = dma_phy.size;
}
template<class T>
T *phy_mem_alloc(int32_t& fd,uint32_t phyaddr, int32_t& size) {
void *map_base, *virt_addr;
char dev_name[] = "/dev/mem";
unsigned page_size, mapped_size, offset_in_page;
off_t target = phyaddr;
fd = open(dev_name, O_RDWR | O_SYNC);
if (fd < 0) FATAL;
mapped_size = page_size = sysconf(_SC_PAGESIZE);
mapped_size += size;
offset_in_page = (unsigned) target & (page_size - 1);
if ((offset_in_page + 32) > page_size) {
mapped_size *= 2;
}
mapped_size = size;
map_base = mmap(NULL, mapped_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, target & ~(off_t) (page_size - 1));
virt_addr = (char *) map_base + offset_in_page;
if (virt_addr == (void *) -1) FATAL;
return (T*)virt_addr;
}
template<class T>
void phy_mem_free(T *mem, int32_t size,int fd) {
if (munmap(mem, size) == -1)
printf("phy mem free error: %s\n", strerror(errno));
close(fd);
}
void init_dam_mmap(){
int32_t fpga_alloc_size = 0x1000,tx_axi_dma_size = 0x1000,rx_axi_dma_size = 0x1000;
int32_t tx_sg_dma_size = 0x1000;
FPGA_VIRTUAL = phy_mem_alloc<uint32_t>(fpga_fd,FPGA_CTR_BASE,fpga_alloc_size);
try{
if(FPGA_VIRTUAL == (void *)-1){
printf("Fpga Mmap Error\n");
throw fpga_fd;
}
TX_AXI_DMAC_VIRTUAL = phy_mem_alloc<char>(axidma_tx_fd,TX_AXI_DMAC_BASE,tx_axi_dma_size);
if(TX_AXI_DMAC_VIRTUAL == (void*)-1){
printf("Tx Axi Dmac Mmap Error \n");
throw axidma_tx_fd;
}
RX_AXI_DMAC_VIRTUAL = phy_mem_alloc<char>(axidma_rx_fd,RX_AXI_DMAC_BASE,rx_axi_dma_size);
if(RX_AXI_DMAC_VIRTUAL == (void*)-1){
printf("Rx Axi Dmac Mmmap Error\n");
throw axidma_rx_fd;
}
TX_SG_DMAC_VIRTUAL = phy_mem_alloc<char>(axidma_sg_tx_fd,TX_SG_DMAC_BASE,tx_sg_dma_size);
if(TX_SG_DMAC_VIRTUAL == (void*)-1){
printf("Tx Sg Axi Dmac Mmap Error\n");
throw axidma_sg_tx_fd;
}
}catch(int32_t ffd){
close(ffd);
exit(1);
}
}
completed dma_transfer(uint32_t phy, uint32_t lenth){
TX_AXI_DMA_WRITE(XILINX_DMA_MM2S_CTRL_OFFSET,0x4);
TX_AXI_DMA_WRITE(XILINX_DMA_MM2S_CTRL_OFFSET,DMAC_REGISTER_SET);
TX_AXI_DMA_WRITE(XILINX_SAMPLE_DMA_MM2S_SA,phy);
TX_AXI_DMA_WRITE(XILINX_SAMPLE_DMA_MM2S_LENGTH,lenth);
while(!TX_AXI_DMA_READ(XILINX_DMA_REG_DMASR)&COMPLETED_DMA_OPT){
}
return true;
}
void send_buf(){
char* buf = (char*)dma_mem_alloc(axidma_tx_fd,0xa00000);
#ifndef FTP_GET
Ftp ftp;
ftp.login_name = "admin";
ftp.login_password = "admin";
ftp.ftp_addr = "192.168.1.33";
ftp.get_filename = "IQ_200M.bin";
int32_t file_size = ftp.ftp_get();
int ffd = open(ftp.get_filename.c_str(),O_RDWR);
void* buffer = mmap(0,file_size,PROT_READ,MAP_SHARED,ffd,0);
memcpy(buf,(char*)buffer,file_size);
#endif
#ifdef _DMA_DATA_DEBUG
size_t len = 0xa00000;
int32_t index = 0;
unsigned char srand_numbers = 0;
while(len--){
buf[index++] = ((unsigned short)srand_numbers > 0xFF) ? 0 : srand_numbers++;
}
#endif
uint32_t phy;
uint32_t size;
dma_phy_addr_get(axidma_tx_fd,phy,size);
printf("START SAMPLE DMA MODE MM2S .... ...\n");
while(1){
if(dma_transfer(phy,size)){
printf("MM2S SEND COMPLETED \n");
}else{
printf("MM2S SEND TIMEOUT\n");
}
}
printf("START DMA MM2S END ... ... \n");
}
void recv_buffer(){
char* buf = (char*)dma_mem_alloc(axidma_tx_fd,0xa00000);
uint32_t phy;
uint32_t size;
dma_phy_addr_get(axidma_tx_fd,phy,size);
if(dma_reciver(phy,size)){
printf("S2MM COMPLETED \n");
}else{
printf("S2MM TIME OUT\n");
}
printf("Put data ftp >>> remote ... ...\n");
Ftp ftp;
ftp.login_name = "admin";
ftp.login_password = "admin";
ftp.ftp_addr = "192.168.1.33";
ftp.put_filename = "CAP_IQ_DATA.bin";
ftp.ftp_put(buf,size);
}
int32_t Ftp::ftp_get() {
int ret = 0;
ftplib *ftp = new ftplib();
ret = ftp->Connect(this->ftp_addr.c_str());
if(!ret){
printf("Can't connect to ftp server %s\n",this->ftp_addr.c_str());
exit(1);
}
ret = ftp->Login(this->login_name.c_str(),this->login_password.c_str());
if(!ret){
printf("logged in error username or password error\n");
exit(1);
}
int32_t size;
ret = ftp->Get(this->get_filename.c_str(),this->get_filename.c_str(),ftplib::image);
if(ret < 0){
printf("Can't Get file [ %s ] from remote \n",this->get_filename.c_str());
exit(1);
}
ret = ftp->Size(this->get_filename.c_str(),&size,ftplib::image);
if (!ret){
printf("ftp get file size error \n");
exit(1);
}
delete ftp;
return size;
}
int32_t Ftp::ftp_put(char* buf,uint32_t size){
int ret = 0;
printf("Write buffer to romte file \n");
ftplib *ftp = new ftplib();
ret = ftp->Connect(this->ftp_addr.c_str());
if(!ret){
printf("Can't connect to ftp server %s\n",this->ftp_addr.c_str());
exit(1);
}
ret = ftp->Login(this->login_name.c_str(),this->login_password.c_str());
if(!ret){
printf("logged in error username or password error\n");
exit(1);
}
ftphandle* romte_file = ftp->RawOpen(this->put_filename.c_str(),ftplib::filewrite,ftplib::image);
ftp->RawWrite(buf,(int32_t)size,romte_file);
ftp->RawClose(romte_file);
delete ftp;
return ret;
}
#define AXI_CLOCK_LTE_REG 0XF8000170
#define AXI_CLOCK_LTE_200M_CLOCK 0x00100500
void clock_check(){
uint32_t fpga_clock_t;
mem_read<uint32_t>(AXI_CLOCK_LTE_REG,fpga_clock_t);
if(fpga_clock_t != AXI_CLOCK_LTE_200M_CLOCK) {
printf("axi bus clock is error, now change to right");
mem_write<uint32_t>(AXI_CLOCK_LTE_REG,AXI_CLOCK_LTE_200M_CLOCK);
}else{
printf("axi buf clock is right \n");
}
}
void print_bd(xilinx_axidma_desc_hw desc){
printf("\t\n**Bd completed status: %#08x**\n",desc.status);
printf("\t\n**Bd control : %#08x**\n",desc.control);
printf("\t\n**Bd next_desc: %#08x**\n",desc.next_desc);
}
void check_bd_status(char* buf,int32_t size){
xilinx_axidma_desc_hw res;
memcpy(&res,buf,size);
print_bd(res);
}
completed tx_sg_transfer(char* buf,uint32_t phy,uint32_t size){
TX_AXI_SG_DMA_WRITE(XILINX_DMA_MM2S_CTRL_OFFSET,XILINX_DMACR_RESET);
TX_AXI_SG_DMA_WRITE(XILINX_DMA_MM2S_CTRL_OFFSET,(XAXIDMA_CYCLIC_BD_EN|XAXIDMA_IRQ_ALL_MASK));
TX_AXI_SG_DMA_WRITE(XAXIDMA_CDESC_OFFSET,phy);
TX_AXI_SG_DMA_WRITE(XILINX_DMA_MM2S_CTRL_OFFSET,(TX_AXI_SG_DMA_READ(XILINX_DMA_MM2S_CTRL_OFFSET)|0x1));
printf("SG MODE REG ST:%#08x\n",TX_AXI_DMA_READ(XILINX_DMA_MM2S_CTRL_OFFSET));
TX_AXI_SG_DMA_WRITE(XAXIDMA_TDESC_OFFSET,phy);
check_bd_status(buf,64);
return true;
}
void tx_bd_send(){
printf("Tx Sg Mode Start\n");
char* buf = (char*)dma_mem_alloc(axidma_sg_tx_fd,0xa00000);
#ifndef FTP_GET
Ftp ftp;
ftp.login_name = "admin";
ftp.login_password = "admin";
ftp.ftp_addr = "192.168.1.33";
ftp.get_filename = "IQ_200M.bin";
int32_t file_size = ftp.ftp_get();
int ffd = open(ftp.get_filename.c_str(),O_RDWR);
void* buffer = mmap(0,file_size,PROT_READ,MAP_SHARED,ffd,0);
memcpy((buf+0x40),(char*)buffer,file_size);
size_t tlen = file_size;
#endif
#ifdef _DMA_DATA_DEBUG
size_t tlen = 0xa00000-0x40;
size_t len = 0xa00000-0x40;
int32_t index = 0;
unsigned char srand_numbers = 0;
char* pkts = buf+0x40;
while(len--){
pkts[index++] = ((uint16_t)srand_numbers > 0xFF) ? 0 : srand_numbers++;
}
#endif
uint32_t phy,size;
dma_phy_addr_get(axidma_sg_tx_fd,phy,size);
xilinx_axidma_desc_hw desc = {
.next_desc = (phy&XAXIDMA_DESC_LSB_MASK),
.next_desc_msb = 0x0,
.buf_addr = (phy+0x40),
.buf_addr_msb = 0x0,
.reserved1 = 0x0,
.reserved2 = 0x0,
.control = (tlen|(XAXIDMA_BD_CTRL_TXEOF_MASK+XAXIDMA_BD_CTRL_TXSOF_MASK)),
.status = tlen,
};
memset(&desc.app,0,sizeof(desc.app));
memcpy(buf,&desc,64);
while(1){
tx_sg_transfer(buf,phy,size);
}
}
completed dma_reciver(uint32_t phy, uint32_t lenth){
RX_AXI_DMA_WRITE(XILINX_DMA_S2MM_CTRL_OFFSET,0x4);
RX_AXI_DMA_WRITE(XILINX_DMA_S2MM_CTRL_OFFSET,DMAC_REGISTER_SET);
RX_AXI_DMA_WRITE(XILINX_SAMPLE_DMA_S2MM_SA,phy);
#ifndef SAMPLE_DMA_TX
send_buf();
#else
tx_bd_send();
#endif
RX_AXI_DMA_WRITE(XILINX_SAMPLE_DMA_S2MM_LENGTH,lenth);
while (!RX_AXI_DMA_READ(XILINX_DMA_S2MM_CTRL_OFFSET|XILINX_DMA_REG_DMASR ))
{
}
return true;
}
int main(int argc,char** argv){
init_dam_mmap();
clock_check();
try{
if(argv[1] == nullptr){
throw 1;
}
if(!strcmp(argv[1],"-d")){
WFPGA(0x18c,0x1);
send_buf();
}else if(!strcmp(argv[1],"-s")){
WFPGA(0x18c,0x0);
tx_bd_send();
}else{
throw 1;
}
}catch(int fd){
printf("Sample Tx Mode: [\"-s\" | \"-d\"] \n");
printf("-s is sg mod | -d is direct mod\n");
return 1;
}
return 0;
}