TLM设计实例——简易DMA设计在一个SoC芯片中,一般由处理器、DMA控制器、中断控制器、存储器、各种接口如UART、USB等组成。DMA往往是总线的主设备,它可以发起存储器之间的数据传输。同时DMA也是总线的从设备,DMA中有若干个控制寄存器,当配置这些寄存器的时候DMA作为总线的从设备。因此DMA(和总线之间有两种接口,一种是主设备接口master_if,另一种则是从设备接口slave_if。作为TLM设计实例的简易DMA(以下简称DMA)中有五个寄存器。DMA使能寄存器用来使能DMA模块,burst传输长度控制器控制每个burst传输的长度,传输控制器控制总的传输长度。源地址寄存器和目的地址寄存器中分别设置数据传输的源地址和目的地址。在DMA中以burst的方式先从源地址读取数据并缓存到DMA内部的buffer中,然后将数据写到目的地址中去。在下面的内容中将给出两种DMA事务级建模的方法。在第一种模型中没有时钟,而第二种模型是周期精确的。在这两种事务级模型中,都有三种端口分别是初始化端口、总线主设备接口和总线从设备接口。在没有时钟的事务级模型中有三个进程分别是main_action进程、dma_fsm进程和dma_rst进程。其中main_action进程和dma_fsm进程定义为SC_THREAD类型,在SC_THREAD进程没有时钟。由于进程间的通信需要通过通道,因此定义了两个信号用于进行间的通信,信号是通道的一种。DMA.h文件如下:#ifndef_dma_h#define_dma_h#includesystemc.h#includeslave_if.h#includemaster_if.henumstate_type{idle,read_state,write_state};SC_MODULE(dma){public://portssc_inboolrst;//初始化信号sc_portmaster_ifmaster_port;//总线主设备接口sc_portslave_ifslave_port;//总线从设备接口//signalsc_signalunsignedintmy_state;//用来做进程间通信sc_signalunsignedintdma_enable;//用来做进程间通信SC_HAS_PROCESS(dma);//macrodefinition//DMA构造函数dma(sc_module_namename_,unsignedintstart_address,unsignedintend_address):sc_module(name_),reg_start_address(start_address),reg_end_address(end_address){//processdeclarationSC_THREAD(main_action);sensitivemy_state;SC_THREAD(dma_fsm);sensitivemy_statedma_enable;SC_METHOD(dma_rst);sensitive_negrst;}//processvoidmain_action();voiddma_fsm();voiddma_rst();//slaveinterfaceboolslave_read(int*data,unsignedintaddress);boolslave_write(int*data,unsignedintaddress);boolslave_select(unsignedaddress);private:unsignedintdma_en;//dma_en寄存器;unsignedinttransfer_size;//transfersize寄存器;unsignedintburst_length;//burstlength寄存器;unsignedintsource_address;//sourceaddress寄存器;unsignedintdestin_address;//destinationaddress寄存器;state_typestate;//DMA状态:初始化状态、读状态、写状态intdma_buffer[16];//DMA缓存int*buffer;//DMA缓存指针unsignedintreg_start_address;//DMA寄存器地址空间首地址unsignedintreg_end_address;//DMA寄存器地址空间末地址};#endifDMA总线主设备接口中定义了两个读写函数master_read和master_write。Master_if.h文件如下:ifndef__master_if_h#define__master_if_h#includesystemc.hclassmaster_if:publicvirtualsc_interface{public://masterinterfacevirtualboolmaster_read(int*data,unsignedintaddress)=0;virtualboolmaster_write(int*data,unsignedintaddress)=0;};//endclassmaster_if#endifDMA总线从设备接口除了定义读写函数外,还定义了一个slave_select函数。该函数用来当从设备被选中时对总线的一个回应。Slave_if.h文件如下:#ifndef__slave_if_h#define__slave_if_h#includesystemc.hclassslave_if:publicvirtualsc_interface{public://Slaveinterfacevirtualboolslave_read(int*data,unsignedintaddress)=0;virtualboolslave_write(int*data,unsignedintaddress)=0;virtualboolslave_select(unsignedintaddress)=0;};//endclassslave_if#endif在dma.cpp文件中实现了从设备接口中定义的方法和dma的进程方法。#includedma.hvoiddma::main_action()//dma数据读写函数{unsignedintread_cnt=burst_length;unsignedintwrite_cnt=burst_length;while(dma_en&&(~rst)){wait();if(state==idle){buffer=dma_buffer;}if(state==read_state){//readthedatafromslave_awhile(read_cnt){master_port-master_read(buffer,source_address);read_cnt--;source_address++;buffer++;}read_cnt=burst_length;}if(state==write_state){//writethedatatoslave_bwhile(write_cnt){master_port-master_write(buffer,destin_address);write_cnt--;destin_address++;buffer++;}write_cnt=burst_length;}}}voiddma::dma_fsm()//dma状态机{dma_enable=dma_en;while(dma_en&&(~rst)&&(transfer_size0)){wait();if(state==idle){wait(10,SC_NS);state=read_state;my_state=state;buffer=dma_buffer;}if(state==read_state){wait(80,SC_NS);state=write_state;my_state=state;buffer=dma_buffer;}if(state==write_state){wait(80,SC_NS);transfer_size=transfer_size-burst_length;state=idle;my_state=state;}}//end_while}//end_dma_fsmvoiddma::dma_rst()//初始化函数{state=idle;//状态初始化dma_en=0;//寄存器清0操作transfer_size=0;burst_length=0;source_address=0;destin_address=0;}booldma::slave_read(int*data,unsignedintaddress)//从设备接口的读方法{switch(address){case4:*data=source_address;//sourceaddress寄存器地址为4break;case8:*data=destin_address;break;case12:*data=burst_length;break;case16:*data=transfer_size;breakcase20:*data=dma_en;break;}return1;}booldma::slave_write(int*data,unsignedintaddress)/从设备接口的写方法{switch(address){case4:source_address=*data;//写寄存器break;case8:destin_address=*data;break;case12:burst_length=*data;break;case16:transfer_size=*data;break;case20:dma_en=*data;break;}return1;}booldma::slave_select(unsignedaddress)//判断DMA是否被选中{if((address=reg_start_address)&&(address=reg_end_address))return1;elsereturn0;}周期精确的DMA模型定义了时钟,所有的进程都是SC_METHOD进程。在SC_METHOD进程之间没有通信机制,都通过时钟作为敏感变量触发。dma.h文件如下:#ifndef_dma_h#define_dma_h#includesystemc.h#includeslave_if.h#includemaster_if.henumstate_type{idle,read_state,write_state};SC_MODULE(dma){public://portssc_in_clockclk;//输入时钟sc_inboolrst;//初始化信号sc_portmaster_ifmaster_port;//总线主设备接口sc_portslave_ifslave_port;//总线从设备接口SC_HAS_PROCESS(dma);//macrodefinition//DMA构造函数dma(sc_module_namename_,unsignedintstart_address,unsignedintend_address):sc_module(name_),reg_start_address(start_address),reg_end_address(end_address){//processdeclarationSC_METHOD(main_action);sensitive_posclk;SC_METHOD(dma_fsm);sensitive_posclk;SC_M