本系列文章是参加第四届“复微杯”全国大学生电子设计大赛 FPGA 赛道的作品,该平台基于 RISCV,要求在 FPGA 平台可以实现指令执行,设计思路清晰, 具体如下:
仿真文件Testbench中仅提供时钟和复位信号输入,复位信号结束后,rom里面的程序便开始运行,通过设置寄存器26和27来观察运行结果的正确性。仿真结束前会查看寄存器26和27的值,并根据执行情况打印pass或fail。
附录1中的代码经过编译后,由verilog运行时由ROM模块读取,仿真程序运行后终端打印结果如下,为pass,表面信息在经过RSA的加密解密后能恢复出原始信息。
Rib总线读写数据波形如图11所示,写数据时we_i信号线拉高,输入32为长度的addr_i和data_i数据,将地址为addr_i的寄存器写入数据data_i;读数据时we_i信号拉低,输入32位长度的addr_i地址数据,返回地址为addr_i寄存器的数据data_o。
函数inverter_init(p,q);执行的波形情况如图12所示。基于地址数据信号位宽只有32位的限制,一次载入、读取只能传输16bit的数据,对于1024比特位宽的数据,一次载入、读取需要64次写、读操作。可以看到,其中大部分时间用在载入p和q,生成e和d只需要很短一段时间。生成e和d的仿真信号放大后如图,Reset信号为高后的一个时钟沿开始运行invert模块,经过10个时钟周期结束。
信号 | 含义 | 信号 | 含义 |
---|---|---|---|
inst_i | 地址指针 | invert_finish | Invert模块运行结束信号 |
isnt_addr_i | 从rom里取出的立即数 | msg_in_reg | 输入数据寄存器 |
we_i | 连接rib总线的读写信号线 | msg_out_reg | 输出数据寄存器 |
addr_i | 连接rib总线的地址信号线 | reset1 | Mod模块开始运行信号 |
data_i | 连接rib总线的数据输入 | mod_exp_finish | Mod模块运行结束信号 |
data_o | 连接rib总线的数据输出 | encrypt_decrypt_reg | 加解密寄存器,信号为高表示加密,反之为解密 |
Reset | Invert模块开始运行信号 |
函数jiami_p = encrypt(code,jiami);执行的波形情况如图13所示。可以看到加密时间非常短,经过7个时钟周期加密结束,大部分时间用在载入明文数据和读取密文数据中。
函数ans_p = decrypt(jiami_p,ans);执行的波形情况如图14所示。经过1022个时钟周期后解密结束,可以看出解密速度远大于加密速度,但与载入密文和读取明文的时间相比依然较少。
整体仿真波形如图15所示。加密前后数据如图中a标注箭头所示,解密前后数据如图中b标注箭头所示。可以看到,加密后的密文已被成功读取并重新载入写msg_in_reg,密文经过解密后成功恢复出明文。
尽管在 FPGA 验证的时候可以通过将程序预先存储在指令存储器中进行验证,但这会导致每次更改软件代码重新编译后,还需要重新生成 FPGA 烧录程序。本小组通过采用串口传输指令进行程序下载和调试功能,可以将软件代码在运行前下载到指令 ROM 中,并且可以实时对 SoC 进行一些简单的调试。上位机连接一个 USB 转串口工具即可。串口实现采用 python语言,更加易于使用者理解并更改,更方便自定义协议,根据需要,随时增加或者删除某些不必要的协议以减少面积。
验证流程:第一,进行 Verilog 代码功能仿真、时序管脚约束。 第二,后端综合和实现,并生成 Bitstream 文件。 第三,将 Bitstream 文件下载到 FPGA 开发板上。观察到led闪烁。
由于小组技术能力有限,本段仅队串口通信功能进行硬件测试。串口通信的C语言代码主函数如下,经过编译完成后生成二进制文件,通过电脑终端命令使用python语言编写的串口下载程序将二进制文件下载进FPGA的rom中,下载时需按下c程序下载键,下载过程如图16所示,FPGA开发板实物图如图17所示。
int main()
{
uart_init();
xprintf("hello world\n");
while (1);
}
下载完成后,按下复位键程序开始运行,程序的功能是将hello world字符串通过串口发送到电脑上,电脑上会有串口消息打印在串口调试助手上,如图18所示。
本小组在充分了解RISC-V内核的基础上实现了RSA模块的建模与仿真,并将uart功能在硬件设备上通过测试。在开源平台tinyrics-v上测试了基本指令的运行,新增了RSA模块用来实现加密,并编写与之配套的C语言代码来实现这一过程。最后通过仿真结果和波形来判断程序的正确性。
本小组在RSA模块中在加密过程中使用了1024位乘法器,导致综合过程不可实现。后续学习了Montgomery模乘算法硬件实现,但在验证的过程中数据出现错误并无法找出原因。后来将互为质数的p和q长度改为长度为32位长度,但在硬件调试过程中始终无法正确的生成密钥。于是放弃了后面的工作,综合过程中仅对uart模块的功能进行测试。
比赛赛程2022年
[1] 郑东,赵庆兰;张应辉.密码学综述[J],西安邮电大学学报,2013年06期,1~10
[2] 司红伟,汤斌.RSA应用现状以及其在文件加密中的应用[J].华东理工大学,电脑与电信Computer&Telecommunication,2009年06期:76~78
[3] 杨涛. 基于公钥加密算法RSA问题实现方法的研究[J]. 科教文汇,2009 年 11期:282~283
[4] 梁鹏飞.基于流水线的Montgomery模乘算法硬件实现[D].华南理工大学硕士论文,2011年
[5] Chakraborty S.Vivado Design Tools[M].In Xilinx inc.2017:17–21.
[6] 雷思磊.RISC-V架构的开源处理器及SoC研究综述[J].单片机与嵌入式系统应用,2017,17(2):56-60.
[7] 季永辉. 基于 RISC-V 处理器的卷积加速 SoC 系统设计[D]. 山东工商学院, 2021.
[8] 胡振波.手把手教你设计CPU——RISC-V处理器篇[M].In人民邮电出版社.2018
[9] Raveendran A,Patil V,Selvakumar D,et al.A RISC-V instruction set processor-micro-architecturedesign and analysis[C].2016:1–7
[10] 张榜,来金梅.一种基于FPGA的卷积神经网络加速器的设计与实现[J].复旦学报:自然科学版,2018,57(2):236–242.
#define D 1024
int main()
{
char e[D];
char d[D];
char jiami[D];
char ans[D];
char code[] = "This is a message encrypted with RSA to verify that the information encrypted by RSA can be restored to the same!";
char * e_p;
char * d_p;
char * jiami_p;
char * ans_p;
char p[] =
"90l38k8kn666jom067m3078l959o7129mm7km88n5441j023jn631o62o3281k7n554nj67j6k8n5j3ml1997mmn06l34ko3onll1l40094kokm85282k5lm1nl73o91";
char q[] =
"n677mo2lj7845613m0lomnln59m04nnnk2453nj4608971839ln7173j99ln61l70268m6774188nokn6om40m2m444om0k8lk5lkmn559570n8l1342j01m3omn1k01";
inverter_init(p,q);
e_p = get_e(e);
d_p = get_d(d);
jiami_p = encrypt(code,jiami);
RSA_REG(RSA_ENCRYPT_TO_DECRYPT) = 1; //清除msg_in数据
ans_p = decrypt(jiami_p,ans);
if (*ans_p == 'T')
set_test_pass();
else
set_test_fail();
return 0;
}
Uart数据寄存器 | 地址 | 含义 |
---|---|---|
uart_ctrl[31:0] | 0x00 | bit[0]: tx enable, 1 = enable, 0 = disablebit[1]: rx enable, 1 = enable, 0 = disable |
uart_status[31:0] | 0x04 | bit[0]: tx busy, 1 = busy, 0 = idlebit[1]: rx over, 1 = over, 0 = receiving |
uart_baud[31:0] | 0x08 | clk div |
uart_rx[31:0] | 0x10 | rx data |
宏定义 | 地址 |
---|---|
RSA_BASE | (0x50000000)(基地址) |
RSA_P | (RSA_BASE + (0x00))(偏移地址) |
RSA_Q | (RSA_BASE + (0x04)) |
RSA_IN | (RSA_BASE + (0x08)) |
RSA_OUT | (RSA_BASE + (0x0c)) |
RSA_E | (RSA_BASE + (0x10)) |
RSA_D | (RSA_BASE + (0x14)) |
RSA_INVERTER_STATUS | (RSA_BASE + (0x18)) |
RSA_MOD_STATUS | (RSA_BASE + (0x1c)) |
RSA_INVETER_FINISH | (RSA_BASE + (0x20)) |
RSA_MOD_FINISH | (RSA_BASE + (0x24)) |
RSA_ENCRYPT_DECRYPT | (RSA_BASE + (0x28)) |
RSA_REG(addr) | (*((volatile uint32_t *)addr))(设置地址对应的数据) |
RSA数据寄存器 | 地址 | 含义 |
---|---|---|
p_reg[`WIDTH -1 :0] | 0x00 | 输入素数p |
q_reg; | 0x04 | 输入素数q |
msg_in_reg; | 0x08 | 输入加密/解密数据 |
msg_out_reg; | 0x0c | 输出加密/解密后的数据 |
e_reg; | 0x10 | |
d_reg; | 0x14 | |
inverter_status_reg; | 0x18 | Inverter模块开始工作 |
mod_status_reg; | 0x1c | Mod模块开始工作 |
inverter_finish_reg; | 0x20 | Inverter模块结束工作 |