570 likes | 758 Views
计算机系统综合课程设计. 基于 MIPS32 的 SOC 设计实践 ( 下 ) (Verilog+Quartus Ⅱ+Cyclone 版 ) 主讲 杨全胜 东南大学计算机科学与工程学院. 第 3 章 外围电路及控制系统设计. 为 MiniSys 加 I/O 功能 16 位定时 / 计数器 16 位脉冲宽度调制 PWM 4×4 键盘扫描电路 4 位 7 段 LED 显示控制 简单 UART 控制 看门狗控制 中断的设计. 为 MiniSys 加 I/O 功能( 1 ). MiniSys 为 I/O 统一编址方式。
E N D
计算机系统综合课程设计 基于MIPS32的SOC设计实践(下) (Verilog+Quartus Ⅱ+Cyclone版) 主讲 杨全胜 东南大学计算机科学与工程学院
第3章 外围电路及控制系统设计 • 为MiniSys加I/O功能 • 16位定时/计数器 • 16位脉冲宽度调制PWM • 4×4键盘扫描电路 • 4位7段LED显示控制 • 简单UART控制 • 看门狗控制 • 中断的设计
为MiniSys加I/O功能(1) • MiniSys为I/O统一编址方式。 • 将DATA RAM地址分区,其中高256个字节用来做IO,一共是128个16位端口。 0000H 4KBRAM 0FFFH FF00H 256BYTE FFFFH
为MiniSys加I/O功能(2) • IO端口地址分配原则(可自行决定) • 将8根IO端口线(16位地址线的低8位,高8位为全1)的高4位用来译码得到最多16个接口电路的片选信号。 • 低4位组成每个接口电路的16个字节端口地址,由于Minisys只有16位数据处理能力。所以每个接口电路实际上是有8个字端口地址。
为MiniSys加I/O功能(3) • 对MiniSys的修改 • 修改MemWrite和MemRead信号的逻辑。增加IORead和IOWrite信号,改MemtoReg为MemorIOtoReg。 assign RegWrite = (R_format || Lw || Jalc || I_data) && !(Jrn) ; // 需要写寄存器的指令 assign MemWrite =((Sw==1 ) && (ImmediatHigh[9:2] != 8’b11111111)) ? 1:0 ; // 写存储器, ImmediatHigh[9:0] 是新增的输入信号=instructions[15..6] assign MemRead = ((Lw==1) && (ImmediatHigh[9:2] != 8’b11111111)) ? 1:0 ; // 读存储器 assign MemorIOtoReg = IORead || MemRead; // 读操作需要从端口或存储器读数据到寄存器 assign IOWrite = ((Sw==1)&& (ImmediatHigh[9:2] == 8’b11111111)) ? 1:0 ; // 写端口 assign IORead = ((Lw==1) && (ImmediatHigh[9:2] == 8’b11111111)) ? 1:0 ; // 读端口, ImmediatHigh[9:0] 就是instructions[15:6]
为MiniSys加I/O功能(4) • 增加一个MEMorIO模块 译码单元 wdata rdata 存储单元 Address 运算单元
为MiniSys加I/O功能(5) • 增加一个MEMorIO模块 译码单元 mwdata 存储单元 mrdata mAddress rdata MEMorIO wdata 运算单元 Address iwdata PortNumber Irdata 注意它 片选信号
为MiniSys加I/O功能(6) 具体端口分配
16位定时/计数器(1) • 功能 • 两个定时/计数器CNT0和CNT1。 • 具有计数和定时两个功能。 • 计数方式下可以对输入的外部脉冲进行计数,当计数到初值寄存器的值的时候,设置状态寄存器的相应位。 • 定时方式下,在时钟作用下计时器做减1,到1的时候设置状态寄存器的相应位,并在相应的COUT脚输出一个时钟的低电平(平时COUT是高电平)。 • 状态寄存器在被读取后被清零。
16位定时/计数器(2) • CNT0方式寄存器(FF20H) • CNT1方式寄存器(FF22H) ;两个寄存器均为只可写 0 1 15 0:非循环 1:循环 0:定时 1:计数
16位定时/计数器(3) • CNT0状态寄存器(FF20H) • CNT1状态寄存器(FF22H) ;两个寄存器均为只可读,读取后被清0 0 1 15 1:定时到 1:计数到 0:定时/计数未开始 1:定时/计数开始
16位定时/计数器(4) • CNT0初值寄存器(O)/当前值寄存器(I) (FF24H) • CNT1初值寄存器(O)/当前值寄存器(I) (FF26H) 0 15 两个寄存器通过读/写线区别
16位定时/计数器(5) • 输入输出安排 • rdata15~rdata0(O)用于CPU读数据 • wdata15~wdata0(I)用于CPU写数据 • CS(I) 片选端 • CLK(I) 时钟信号 • Reset(I)复位信号 • pulse0, pulse1(I)两个CNT的外部脉冲信号 • address3~address0(I)端口地址 • IOW(I)写信号 • IOR(I)读信号 • COUT0, COUT1(O)定时/计数器输出
脉冲宽度调制PWM(1) • 功能 • 内部一个16位计数器和一个16位对比值,计数器周而复始的加1计数,计数到计数器的最大值(默认为FFFFH)的时候转为0再计数。当计数器的值大于对比值,输出端输出低电平,否则输出高电平。 • 对比值(默认为7FFFH)的不同决定了输出脉冲的占空比。 • 计数器的最大值可以由软件设定,以便确定PWM的输出脉冲的调制频率。
脉冲宽度调制PWM(2) • 输入输出安排 • RESET(I) 初始化 • address2~address0(I)端口地址 • D15~D0(I)用于写入对比值和最大值 • CS(I) 片选端 • CLK(I) 时钟信号 • IOW(I)写信号 • PWM(O)输出端
脉冲宽度调制PWM(3) • 内部寄存器 • 最大值寄存器(FF30H)(只写) • 对比值寄存器(FF32H)(只写) • 使能寄存器(FF34H)(只写) 0 15 默认为0 0:不许输出脉冲 1:允许输出脉冲
4×4键盘扫描电路设计(1) • 功能自动扫描4×4的键盘,当有键按下的时候扫描键值,将键值记录到键值寄存器,并置位状态寄存器中的“有键”标志。当CPU读出键值后,将“有键”标志清除。
4×4键盘扫描电路设计(2) • 输入输出安排 • D15~D0(O)用于读出数据 • CS(I) 片选端 • CLK(I) 时钟信号 • line3~line0(I)键盘行输出线 • col3~col0(O)键盘列输入线 • address1~address0(I)端口地址 • IOR(I)读信号
4×4键盘扫描电路设计(3) • 内部寄存器 • 键值寄存器(FF10H)(只读) • 状态寄存器(FF12H)(只读) 0 15 0:无键 1:有键
4位7段LED显示控制(1) • 功能通过向该控制电路写16位数据,经过译码控制共阳极的7段LED显示。16位数每半个字节控制一位7段LED,从高位到地位排列。 0 15 LED1 LED0 LED3 LED2
a b f g e c d 4位7段LED显示控制(2) • 7段共阳极LED需要点亮的笔画需要输出0。 • 将a~g分别接输出的7位数据的位0~位6
4位7段LED显示控制(3) • 输入输出安排 • Reset (I) 初始化 • D15~D0 (I)用于写数据 • CS (I) 片选端 • IOW(I)写信号 • led00~led06 0位led输出线 • led10~led16 1位led输出线 • led20~led26 2位led输出线 • led30~led36 3位led输出线 • 内部寄存器 • 数据锁存器(FF00H)
简单UART控制(1) • 功能负责控制将CPU来的8位数据并转串,然后按照异步串行通信数据格式输出,将串口来的8位串行数据串转并,并在CPU请求的时候输入给CPU。
简单UART控制(2) • 设计时注意事项 • XTAL可以是单独的时钟信号,和系统的CLK不一样。 • 假设外部时钟XTAL的频率是波特率的16倍(本设计采用固定波特率9600b/s) • 接收器接收数据的采样率也是波特率的16倍(既XTAL频率)采用中间值采样的原则,也就是一个数据位占16个接收时钟宽度,在第8个时钟的时候采样。 • 数据格式固定为1位起始位,8位数据位和1位停止位。起始位为0,停止位为1。串行输出线空闲状态为1。
简单UART控制(3) • 输入输出安排 • rdata7~rdata0(O)用于CPU读数据 • wdata7~wdata0(I)用于CPU写数据 • CS(I) 片选端 • XTAL(I) 外部时钟信号 • TxD(O)串行输出 • RxD(I)外部串行输入 • address2~address0(I)端口地址 • IOW(I)写信号 • IOR(I)读信号 • RESET(I)复位信号
简单UART控制(4) • 内部寄存器 • 输出锁存器(FF40H)(只用8位) • 输入缓冲器(FF40H)(只用8位) • 状态寄存器(FF42H) 0 15 1:输出完 1:输入完 状态寄存器在读出输入缓冲器后清D1位,在写入输出锁存器后清D0位。
看门狗电路(1) • 功能 • 内含一个16位定时器,系统复位后计数值为FFFFH,之后每时钟计数值减1,当减到0的时候,向CPU发4个时钟周期的RESET信号,同时计数值恢复到FFFFH并继续计数。 • 通过软件不断地定期写看门狗端口来复位看门狗,使计数器重新从FFFFH开始计数。 • 注意增加看门狗电路后,CPU的RESET输入脚应该是系统复位信号和看门狗发出的复位信号的组合。
看门狗电路(2) • 输入输出安排 • wdata7~wdata0(I)用于CPU写数据 • CS(I) 片选端 • CLK(I) 外部时钟信号 • RST(O)输出给CPU的复位信号 • IOW(I)写信号 • RESET(I)系统复位信号
看门狗电路(3) • 内部逻辑只要CS, IOW同时有效,看门狗电路就被复位,看门狗电路访问的端口地址是FF50H
中断的设计(1) • 为Minisys增加两个中断功能——中断0和中断1,中断0优先级大于中断1,不支持同级中断嵌套。 • 将$26和$27设计为两个中断返回地址存放寄存器,分别在中断0和中断1到来的时候存放返回地址。它们分别称为$i0和$i1。这两个寄存器也改为系统寄存器,用户不可访问。
中断的设计(2) • 增加一个中断屏蔽寄存器IMASKR。 0 15 0:允许中断1 1:屏蔽中断1 0:允许中断0 1:屏蔽中断0 这两位的置和清由硬件自动实现,当中断到来,跳转到服务子程序的时候置位,执行jr $i0或jr $i1的时候清相应的位。
中断的设计(3) • 中断处理 • 中断向量的制定将4KB 程序ROM的FF8H~FFBH作为中断0的向量,FFCH~FFFH作为中断1的向量。用户程序应该在这两个地址放上j语句,跳转到真正的中断处理程序入口,如果没有中断处理程序,也要分别放上jr $i0和jr $i1
中断的设计(4) • 中断处理 • 中断响应的过程1)将下一条指令的PC值存放到$i0或$i12)设置IMASKR的相应位,屏蔽有关中断3)跳转到FF8或FFC • 中断返回过程(对jr $i0和jr $i1的处理)1)清IMASKR的相应位,打开有关中断2)执行jr $i0或jr $i1
中断的设计(5) • 中断处理 • 中断优先权中断0优先于中断1,当两个中断同时到来,先处理中断0。 • 中断嵌套不允许同级中断嵌套,中断0可以嵌套在中断1中,也就是说中断0能够中断中断1的处理程序。
中断的设计(6) • 中断请求信号 • 中断请求信号源CTC16、KEY16、UART均可以发中断请求,可自选两个改成中断方式。 • 中断请求信号属性尽量采用电平触发,而且尽量使用多时钟周期的高电平触发。这样可以避免干扰信号的误判。多时钟周期高电平的实现可以考虑使用一个时钟计数器和状态机。
第4章 软件设计 • 伪指令 • 堆栈的实现 • 汇编编译程序 • 测试与应用程序
伪指令(1) • 绝对地址定义 • ORG_DATA 32位数据区双字地址定义下一语句在数据RAM中的绝对地址。例:ORG_DATA 0000 buf DD 0000ffff, 55aa1234; • ORG_CODE 32位代码区双字地址定义下一语句在程序ROM中的绝对地址。例:ORG_CODE FF8 j int0
伪指令(2) • 变量定义(仅支持32位变量定义,用十六进制表示值, 变量名就是地址)变量名 DW 值1, 值2, ……值n(值都以16进制表示)例如:buf DW 0000ffff, 55aa1234; …… lw $V0, buf($Zero) ;load 0000FFFF • 注释符; 英文的注释文字
伪指令(3) • 标号定义与使用(标号名是地址)标号名: 语句例如:int0: lw $t0, 12($t1)j int0 ……
段定义伪指令(1) • 数据段定义伪指令DATA SEG ; 数据段开始DATA ENDS ; 数据段结束例:DATA SEG ; 数据段开始buf DD 0000ffff, 55aa1234DATA ENDS ; 数据段结束
段定义伪指令(2) • 代码段定义伪指令CODE SEG ; 代码段开始CODE ENDS ; 代码段结束例:CODE SEG ; 数据段开始lw $t0, buff($t1) ……CODE ENDS ; 数据段结束
程序结束伪指令 • 格式END 标号注意这里的标号一定要在汇编程序中出现过,程序结束伪指令不仅表明程序结束,更重要的是告诉汇编器,程序的第1句是哪一句。因此这里的标号应该是程序第1句的标号。
堆栈的实现(1) • 使用数据RAM的一部分作为堆栈由于数据是32位的,所以堆栈总共有128个单元。堆栈的操作以及堆栈越界检查全由软件实现。 0000H 3584B数据区 0E00H 512B堆栈 0FFFH
堆栈的实现(2) • 堆栈操作(初始$SP=0FFFH)压栈操作 出栈操作sw $t0, 0($sp) addi $sp, $sp, 4 addi $sp, $sp, -4 lw $t0, 0($sp)
汇编编译程序(1) • 目标将用MiniSys汇编语言编写的MiniSys程序(含伪指令)编译成.mif文件,其中代码部分编译成prgmip32.mif,数据部分编译成dmem32.mif。注意mif文件中不要出现任何中文,包括注释中也不要用中文。
汇编编译程序(2) • 要求 • 编译结果正确,格式正确。具有错误报告功能,可定位到错误语句的行。可直接用于Quartus II中进行芯片编译。 • 在prgmip32.mif中,对于每条翻译过的指令码,用注释的方法将源代码及源代码后的注释附在后面以便调试的时候对照。(不能用中文) • 编译程序可以用C、C++、JAVA、DELPHI、Power Builder等任何一种语言来实现。 • MiniSys汇编指令书写格式参见指令系统的指令举例,汇编程序书写格式见后。
汇编编译程序(3) ORG_DATA 0000 ; The start address of data BUF DW 000000FF, 55005500 ORG_CODE 0000 ; The start address of code start:addi $t0, $Zero, 0 ;A label for the first statement, $t0=0 lw $v0, buf ($t0) ; $v0=000000FF (buf[0]) addi $t0, $t0, 4 lw $v1, buf($t0) ; $v1=55005500 (buf[4]) add $v0, v0, v1 ; $v0=$v0+$v1=550055FF addi $t0, $t0, 4 sw $v0, buf($t0) ; buf[8]=550055FF j start end start ;The label for end statement is as the same as the one for the first statement. • MiniSys汇编程序书写格式举例
汇编编译程序(4) • prgmip32.mif文件 DEPTH = 1024; -- 10 bits of data line, 210=1024 WIDTH = 32; -- the width of data is 32 bits ADDRESS_RADIX = HEX; -- describe address in hex DATA_RADIX = HEX; -- describe data in hex CONTENT BEGIN 0 : 8c020000; --lw $2 0($0) 1 : 8c030002; --lw $3 2($0) [2..3FD] : 00000000; 3FE : 01800008; -- jr $i0 ;(jr $26) 3FF : 01C00008; -- jr $i1 ;(jr $27) END;
汇编编译程序(5) • dmem32.mif文件 DEPTH = 1024; --10 bits of data line, 210=1024 WIDTH = 32; -- the width of data is 32 bits ADDRESS_RADIX = HEX; -- describe address in hex DATA_RADIX = HEX; -- describe data in hex CONTENT BEGIN 0 : 00000055; 1 : 000000AA; [2..3FF] : 0000; END;
汇编编译程序(6) • 注意地址对应关系 • 对于代码部分ORG_CODE的翻译源程序的代码部分ORG_CODE后的地址是实际的32位双字地址,而在prgmip32.mif中的地址是实际双字地址除以4后取低10位的结果。也就是address[11..2]。例如:ORG_CODE 0FF8 jr $i0应该翻译为3FE : 01800008; -- jr $i0 翻译前的地址 翻译后的地址 翻译后的指令