前提
RISC-V的SOC在没有总线的情况下和外设连接的话,core就需要直接与外设直接连接交互了
处理器核core直接与每个外设进行交互。假设一个外设有一条地址总线和一条数据总线,总共有N个外设,那么处理器核就有N条地址总线和N条数据总线,而且每增加一个外设就要修改(改动还不小)core的代码。有了总线之后,处理器核只需要一条地址总线和一条数据总线,大大简化了处理器核与外设之间的连接。
1.总线(实践项目采用单总线结构rib.v)
计算机(实际上RISC-V处理器就相当于一个小的计算机)所有功能的实现过程就是各种信息在计算机内各大功能部件之间进行交换的过程,因此,总线出现了为部件之间构筑了信息传输的公共通路。
目前已经有不少成熟、标准的总线,比如AMBA、wishbone、AXI等。设计CPU时大可以直接使用其中某一种,以节省开发时间。但是为了追求简单,实践项目并没有使用这些总线,而是自主设计了一种名为RIB(RISC-V Internal Bus)的总线。RIB总线支持多主多从连接,但是同一时刻只支持一主一从通信。RIB总线上的各个主设备之间采用固定优先级仲裁机制。
1.单总线结构
在单总线结构的系统中只有一条系统总线,因此所有的外设都只能连接在这一条总线上构成完整的系统。
RIB总线本质上是一个多路选择器,从多个主设备中选择其中一个来访问对应的从设备。
RIB总线地址的最高4位决定要访问的是哪一个从设备,因此最多支持16个从设备。
注意:RIB总线上不同的主设备切换是需要一个时钟周期的,因此如果想要在执行阶段读取到外设的数据,则需要在译码阶段就发出总线访问请求。
2.总线的仲裁方式(实践项目采用的是作者自己设计的类似状态机的方式:固定优先级仲裁机制,有点意思的这个,可以去网上看看这种仲裁方式)
总线的仲裁也称总线的控制。因为总线为多个部件共享,为防止有多个部件同时使用总线导致数据冲突,需要有一个总线控制机构来解决总线使用权的仲裁,以某种方式选 择其中一个设备作为主设备。总线控制机构,又称总线控制器,它的组成与总线控制方式有关。
3.总线的定时方式
总线的一次信息传送有地址传送和数据传送两个过程,四个阶段
1.总线请求与仲裁:需要使用总线的主部件(或源部件)提出请求,由总线控制器确定将下一个总线使用权分配给哪一个请求者。(在rib.v里面有主设备请求)
2.寻址阶段:取得使用权的主部件通过总线发出本次要访问的从部件(或目的部件)的存储器地址或1/。端口地址及有关命令,启动相应的目的部件。
3.信息传送阶段:主从部件之间进行数据传输。
4.rib.v(RIB总线模块)
rib总线有很强的主从关系且很类似所有感觉没必要列太多。RIB总线实际是多路选择器,主选从。
序号 信号名 输入/输出 位宽(bits) 说明 1 m0_addr_i 输入 32 主设备0读写外设地址 2 m0_data_i 输入 32 主设备0写外设数据 3 m0_data_o 输出 32 主设备0读取到的数据 4 m0_ack_o 输出 1 主设备0访问完成标志 5 m0_req_i 输入 1 主设备0访问请求标志 6 m0_we_i 输入 1 主设备0写标志 7 s0_addr_o 输出 32 从设备0读、写地址 8 s0_data_o 输出 32 从设备0写数据 9 s0_data_i 输入 32 从设备0读取到的数据 10 s0_ack_i 输入 1 从设备0访问完成标志 11 s0_req_o 输出 1 从设备0访问请求标志 12 s0_we_o 输出 1 从设备0写标志 注意:RIB总线上不同的主设备切换是需要一个时钟周期的,因此如果想要在执行阶段读取到外设的数据,则需要在译码阶段就发出总线访问请求。
注释:这里是主设备优先仲裁,顺序对应依次为uart串口模块(uart.v)、执行模块(ex.v)、jtag模块(jtag_top.v)、PC寄存器模块(pc_reg.v),其中除了pc_reg外其他主设备访问总线都需要流水线停顿。
2.外设
1.ROM(rom.v)
ROM:只读存储器,存储内容在制造时就固定的存储器,此后的内容仅可读。
功能
存储指令码,根据PC寄存器输出的地址码向外输出指令码。(在取指篇会详细讲)
2.RAM(ram.v,RAM模块的实现和ROM一样)
RAM:随机存取存储器又称作“随机存储器”,是与CPU直接交换数据的内部存储器,也叫主存(内存),存储单元的内容可按需随意取出或存入,且存取的速度与存储单元的位置无关的存储器。
1.SRAM
SRAM:静态随机存取储存器,具有静止存取功能的内存
2.DRAM
DRAM:动态随机存取存储器,每隔一段时间,固定要对DRAM刷新充电一次,否则内部的数据即会消失。将实践项目移植到PGL22G的时候,DRAM资源不够,无法像项目作者在原来代码里面一样直接使用定义reg的方式来构造存储器,必须要使用BRAM的ip核。
3.TIMER(timer.v)
TIMER:在这里我理解为总线定时用的32位计数器,用于触发定时器中断的。
序号 信号名 输入/输出 位宽(bits) 说明 1 clk 输入 1 时钟输入信号 2 rst 输入 1 复位输入信号 3 data_i 输入 32 计数器读数据,来源于rib.v的s2_data_o 4 addr_i 输入 32 计数器数据读地址,来源于rib.v的s2_addr_o 5 we_i 输入 1 计数器写标志,来源于rib.v的s2_we_o 6 data_o 输出 32 计数器写数据,输出到rib.v的s2_data_i
7 int_sig_o 输出 1 定时器中断信号,最终会流向if_id.v的int_flag_i
1.三个寄存器的定义:
1.REG_CTRL(控制寄存器):
1)[0]:计数器计时使能
2)[1]:定时器中断使能
3)[2]:计时器等待使能,置1清0
4)地址偏移量:0x00
2.REG_COUNT(计数器阈值寄存器):
3.REG_VALUE:
1)计数器预期值(阈值)
2)地址偏移量:0x08
2.定时器中断信号设置
定时器中断使能且定时器等待使能时赋值为1,否者赋值为0。
3.定时器计数
每个周期时钟自增1,达到阈值(或者异常情况)后归零。
4.写寄存器
定时器使能赋值,定时器中断使能赋值,计时器等待使能赋值(置1清0),计数器使能且定时器计数达到阈值时,计数器计时使能失效,计时器等待使能失效,以此判断定时器中断触发。
5.读寄存器
4.UART(uart.v)
UART:通用异步收发器。
1.UART通信的异步通信机制
UART:一种常用的串行通信协议,广泛应用于单片机或各种嵌入式设备之间的通信。
注释:1.TX:发送数据端,要接另一设备的RX
2.RX:接收数据端,要接另一设备的TX
UART通信是一种异步串行通信方式,原理是通过数据线传输二进制数据位。UART通信系统主要由发送端和接收端两部分组成。UART通信采用异步通信方式,即发送端和接收端之间通过数据线进行数据传输。在异步通信中,发送端和接收端不需要同时处于激活状态,而是通过起始位和停止位来标识数据帧的开始和结束。具体来说,当发送端产生起始位后,发送一个数据位;然后等待接收端的起始位,如果接收到起始位,则继续发送下一个数据位;如果没有接收到起始位,则认为数据帧传输失败。同样,当接收端产生停止位后,发送一个校验位;然后等待发送端的停止位,如果接收到停止位,则认为数据帧传输成功。
2.UART通信协议
1.起始位:数据传输开始时发送方要先发出一个低电平’0’来表示传输字符的开始,空闲位一直是高电平,开始第一次通讯时先发送一个明显区别于空闲状态的信号即为低电平。
2.数据位:通常是5-9位数据(在实践项目中是8位数据)构成一个字符。先发送低位再发高位。
3.奇偶检验位:一般为0-1位
4.停止位:一般为1-2位的高电平。
3.UART的波特率
波特率表示单位时间内通过线路传输的二进制数据的位数,通常用bps表示,波特率为9600bps,则每秒钟可以传输9600个比特位的数据。串口传输数据的波特率是单片机的时钟系统来产生的,因此它和单片机的系统时钟存在算式关系如下:
波特率= (16 * 时钟频率) / (32 * 采样时间) + (1 * 时钟频率) / (32 * 采样时间) - (1 * 时钟频率) / (64 * 采样时间)
注释:采样时间指上次起始位到本次的间隔时间
序号 信号名 输入/输出 位宽(bits) 说明 1 clk 输入 1 时钟输入信号 2 rst 输入 1 复位输入信号 3 we_i 输入 1 串口写标志,来源于rib.v的s3_we_o 4 addr_i 输入 32 串口数据读地址,来源于rib.v的s3_addr_o 5 data_i 输入 32 串口读数据,来源于rib.v的s3_data_o 6 data_o 输出 32 串口写数据,输出到rib.v的s3_data_i 7 tx_pin 输出 1 串口的tx接口,直接接到tinyriscv_soc_top 8 rx_pin 输入 1 串口的rx接口,直接接到tinyriscv_soc_top
1.S_IDLE:串口闲置使能地址
2.S_START:串口通信开始使能地址
3.S_SEND_BYTE:串口发送数据使能地址
4.S_STOP:串口通信结束使能地址
串口寄存器地址定义
串口的TX发送
当复位信号来临时,串口状态赋为空闲状态,其余赋0
当串口状态为空闲时,发送端置1;发送的数据有效时,状态更新为串口通信开始,要发送的数据写入UART_TXDATA寄存器,发送端置0(计数周期)
串口的RX接收
检测信号在这里使用下降沿触发,我看了其他博主的文章他们给出的解释是类似按键触发时会触发大量毛刺一样,为了保证检测的准确性,使用下降沿触发有效屏蔽毛刺带来的影响。
而这里就是检测信号的赋值,这里采用了非阻塞型赋值,这样q1就会等于的是未被pin赋值前的q0,有效避免了逻辑上的错误:(下图配合UART通信协议的图2看的话会更好理解。)
接收数据时钟到9时,8bit数据接收完毕
5.GPIO(gpio.v)
GPIO:输入/输出接口,可以配置成输出模式来控制外部设备,也可以配置成输入模式来读取外部信号。(玩过stm32或者树莓派吧,上面一堆接口,FPGA开发板上也有一堆接口)
6.SPI(spi.v)
SPI:串行外围设备接口,是一种高速的,全双工,同步的通信总线。主要应用于EEPROM(带电可擦可编程只读存储器),FLASH,RTC(实时时钟),AD转换器,还有数字信号处理器和数字信号解码器。
1.SPI通信协议
SPI是一个同步的数据总线,也就是说它是用单独的数据线和一个单独的时钟信号来保证发送端和接收端的完美同步。
整体的传输大概可以分为以下几个过程:
1.主机先将
NSS
信号拉低,这样保证开始接收数据;2.当接收端检测到时钟的边沿信号时,它将立即读取数据线上的信号,这样就得到了一位数据(1
bit
);
由于时钟是随数据一起发送的,因此指定数据的传输速度并不重要,尽管设备将具有可以运行的最高速度(稍后我们将讨论选择合适的时钟边沿和速度)。
3.主机发送到从机时:主机产生相应的时钟信号,然后数据一位一位地将从
MOSI
信号线上进行发送到从机;4.主机接收从机数据:如果从机需要将数据发送回主机,则主机将继续生成预定数量的时钟信号,并且从机会将数据通过
MISO
信号线发送;
SPI总线包括4条逻辑线:
1.SCLK: 串行时钟信号,主设备产生。
2.MOSI:主机输出,从机输入(数据来自主机)。
3.MISO:主机输入,从机输出(数据来自从机)。
4.SS:片选信号,用于主机发送片选CS信号,选择控制的从设备,常是低电平有效。