LS1C102学习板有LED1、LED2两个LED灯
上电,LED2常亮,LED1可编程点亮、熄灭
一.准备工作
编译工具 loongide
烧录工具 flashrom
1.创建本实验源码目录/home/linlin/ls1c102/
2.在loongide新建项目名myls1c102,将向导生成的…/myls1c102/ls1c102/include/regdef.h(通用寄存器定义)和…/myls1c102/ld.script(链接脚本)复制到/home/linlin/ls1c102/
3.在WINE/DOS下运行命令(编译、链接等等)
4.参考
<linux/wine64/wow64运行32位win程序龙芯嵌入式开发工具> ( https://blog.51cto.com/u_13752418/10735509)
<龙芯LS1C102单片机学习板(1)–烧录> ( https://blog.51cto.com/u_13752418/10819318)
5.文档
1)架构->处理器核->cpu
如LS1C102、LS1C103是loongarch架构,LS1C101是MIPS架构
如LS2K500是LA264核,LS2K2000是LA364核,两者同为loongarch 64位架构
<龙芯架构参考手册–基础架构>(应含64位、32位)、<龙芯架构32位精简版参考手册>
<龙芯1C102处理器用户手册>
<LS1C102学习板原理图>
下文分别简称:
<基础架构手册>、<架构32位精简版手册>
<处理器手册>
<原理图>
<处理器手册>中的’阅读指南’说到’请参阅<龙芯LA132处理器核用户手册>',但没见龙芯公司公开处理器核手册
<原理图>
LED1接gpio20
LED2接3.3V
2)LS1C102和LS1C101的异同
首先,两者架构、指令集完全不同
但是,对比<龙芯1C102处理器用户手册>和<龙芯1C101处理器用户手册>两者文档内容,几乎一模一样,这可从硬件寄存器功能、地址空间分布、位域定义看出,怀疑LS1C102仅在LS1C101基础上更换指令集而已,以达C源码级兼容
2.1)地址空间分布起始地址
其它的spi、i2c等等硬件寄存器地址就不一一列出了,LS1C101和LS1C102完全相同,LS1C103不同于前两者
地址空间分布,loongarch文档列出的是物理地址,MIPS文档列出的是虚拟地址(MIPS资料常作程序地址)
MIPS的程序地址0x80000000 ~ 0x9fffffff(可cache)和0xa0000000 ~ 0xbfffffff(不可cache)截断最高前三位得物理地址,以LS1C101为例,0xa0000000/0x80000000直接映射到物理地址0x0
LS1C103、LS2K500等新产品明显看出是物理地址
LS1C102的boot也明显是物理地址,但RAM、硬件寄存器地址不知是物理地址还是虚拟地址?
所以要完全弄明白loongarch,还是以新产品LS1C103为好
cpu复位,loongarch是进入物理地址空间,MIPS是进入虚拟地址空间
loongarch可从物理地址空间切换到虚拟地址空间,以LS1C103的UART0为例,在编写程序代码中,物理地址空间必须写为0x00009000,虚拟地址空间必须写为0x80009000或0xa0009000(根据设置的直接映射配置窗口)
MIPS以程序地址运行,不以物理地址,以LS1C101的UART0为例,在编写程序代码中,必须写为0xbfe80000(cpu自动映射到0x1fe80000物理地址),不能写为0x1fe80000
LS1C102是单片机,以物理地址空间运行就可,没必要切换到虚拟地址空间(如何切换,手册没介绍,可参考LS2K500的uboot源码、loongide)
2.2)寄存器位域
LS1C102和LS1C101相同的硬件寄存器,其位域定义基本一致,仅有极少部分寄存器某位域略有差别,如<处理器手册>章节 3.2.1芯片全局配置 的位域[27]、[14:12]、[11]两CPU不同
2.3)中断
<处理器手册>章节 4.1中断结构
IP0、IP2~7功能定义两CPU相同
<处理器手册>章节 4.2中断处理 说’CPU所有中断和例外的处理入口为0x1c000000’(这个地址是boot,令人迷惑)
以上IP及入口的异同,更确切地说,是MIPS和loongarch的异同
<架构手册>比<处理器手册>多了IP12(核间中断)
<基础架构手册>比<架构32位精简版手册>多了IP10(性能监测计数溢出中断)
2.4)CPU定时器
<处理器手册>第六章 定时器 的定时器是硬件寄存器,LS1C101和LS1C102相同,没有本质上区别
本小节的CPU定时器是指架构上自带的定时器,LS1C101和LS1C102(实为MIPS和loongarch)迥乎不同,需参考<架构手册>
<架构手册>章节 7.1控制状态寄存器一览
控制状态寄存器地址是独立编址,读写也是独立一套指令,不同于内存编址、访问指令
控制状态寄存器有很多,CPU定时器便是其中之一,下面仅列出CPU定时器相关的控制状态寄存器
<架构32位精简版手册>上定义的控制状态寄存器远少于<基础架构手册>
一个cpu的实现应满足<架构手册>最低要求,龙芯各cpu产品的处理器手册都没叙述控制状态寄存器,所以某具体cpu添加了<架构手册>之外控制状态寄存器不为人知
<处理器手册>章节 4.1中断结构 说’CPU定时器。清中断通过写compare寄存器来实现’,在<架构手册>和loongIDE没见有compare控制状态寄存器,怀疑系照抄<龙芯1C101处理器用户手册>之误
LS1C102的CPU定时器清中断应该通过TICLR
二.实验目的
用定时器产生中断,了解中断处理过程
看门狗设置约400秒,没喂狗,400秒足够验证中断实验
三.实验过程
操作GPIO(即LED灯)和定时器
1.GPIO
1.1 )
LS1C102共64个GPIO,操作GPIO,通常的做法是分成两组,每组共32位域,输入输出分不同的地址硬件寄存器,寄存器32位对应32个GPIO,即每一位对应一个GPIO
对输入地址写32位整型值便是同时对32个GPIO输入电平
对输出地址写32位整型值便是同时使32个GPIO输出电平
1.2 )
本实验不要求同时点亮/熄灭多个LED,所以用另一种方式,即采用LS1C102提供的GPIO位访问端口方式,很为方便
LS1C102提供64个字节的空间,对应64个GPIO,需按字节访问,即每一个字节对应一个GPIO
第0位应该是输入/输出高低电平,对应本实验值1为亮,值0为灭
第1位应该是方向,对应本实验值1为输出电平
第2~7位<处理器手册>没说明
第一个GPIO是gpio00,其GPIO位访问端口地址是0xbfeb0080
2.定时器
2.1 )
LS1C102集成的硬件控制UART、SPI、I2C等都有硬件寄存器,定时器也不例外
LS1C102提供了硬件定时器,包括计数寄存器、比较寄存器、步进寄存器
硬件寄存器和内存是统一编址,所以读写硬件寄存器内容通过ld.w、ld.b、st.w、st.b指令访问地址
2.2)LS1C102是loongarch架构,提供了CPU定时器,其读写是通过csrrd、csrwr、csrxchg指令,不同于硬件定时器
2.3)本实验是CPU定时器中断,没用硬件定时器,所以下文的定时器是指CPU定时器
3.验证
LED1灯即为gpio20
说明能发生中断并返回到断点while(1)
四.
1.源代码
代码文件为irqtime.S,放在/home/linlin/ls1c102/下
2.解析
1)必须regdef.h
去掉#1处一行的regdef.h,编译出错,如下
2)定时器相关的寄存器
见<架构手册>
2.1)TID
loongide没见设置TID,所以本实验也不设置
2.2)TCFG
<架构手册>位域[n-1:2] 说’定时器倒计时自减计数的初始值。要求该初始值必须是4的整倍数。硬件将自动在该域数值的最低位补上两比特0后再使用’
不大明白手册位域[n-1:2]数值表达的意思,是域数值=初始值?还是域数值*4=初始值?
根据下面TVAL[n-1:0],TCFG[n-1:2]意思应该为(初始值/4)也即域值*4=计数初始值
2.3)TVAL
n-1:0 当前定时器的计数值
31:n 只读恒为0,写被忽略
2.4)计数初始值
因为不知LS1C102的n是多少,所以本实验取计数初始值尽量不要取太大
3)<架构手册>章节 7.4基础控制状态寄存器
除了定时器,还经常用到以下
4)#4处为中断入口地址,链接的时候应该会安排其下面语句到此地址,最终0x1c000000(链接开始地址)+0x1000=0x1c001000
5)正常中断处理需判断区分例外类型,分别处理不同类型,本实验省略了(因为设了中断屏蔽只CPU定时器中断)
3.编译
不用管 err
已编译生成irqtime.o
4.链接
5.转换为二进制格式
6.烧写
使用flashrom工具
板上闪存为4194304 B(4M),需用dd命令将irqtime.bin填满到4M
计算填充大小
4194304-4120=4190184
五.后记
1.中断入口地址
本人一开始是以<架构32位精简版手册>为参考,掉入坑
1)精简版手册章节 7.4.8 例外入口地址(EENTRY)
所以一开始按MIPS传统相对boot偏移0x0380(满足低6位为0)作为中断入口
即#3处改为
li.w t0,0x1c000380
也#4处改为
.org 0x380
然后实验现象
上电->LED1亮–3秒–>LED1灭(while里)–10秒->LED1常亮(没灭过)
根据现象,猜测可能原因
情况1:能进入0x380处(点亮),但中断返回又立即发生中断(反复),没能返回到断点while(1)
情况2:没进入0x380处,但第一次应该确实是发生定时器中断,然后后续不断发生例外(是否中断标志未清?是否是其它例外不是定时器中断?),进入0x1c000000(反复),但没进入while(1)
情况1是当没清中断标志时,所以可以排除
情况2原先认为进入0x1c000000是复位,但如果是复位,则必定会再进入while(1)并10秒后发生定时器中断,所以很困惑
后来看到<处理器手册>说’CPU所有中断和例外的处理入口为0x1c000000’,所以判定情况2为例外而不是复位
最后各种实验(gpio35外接led灯,关中断代码前后亮灭gpio35),判断0x380为非法中断入口,然后发生例外,进入0x1c000000(然后又好像是在关中断发生例外?反反复复),个人理解
2)后先参考loongide的入口0x80000000,但这个是内存地址,所以硬编码把中断代码复制到0x80000000开始处,实验成功
即#3处改为
li.w t0,0x80000000
在#2处添加(复制中断处理指令到内存)
3)后又参考原厂自带程序,发现其入口是相对boot偏移0x1000,好像必须满足低12位都为0
4)再后参考<基础架构手册>章节 7.4.10 例外入口地址,入口的定义完全和精简版手册不同
5)页
精简版手册章节 5.4.2 TLB的表项 说’龙芯架构32位精简版只支持4KB和4MB两种页大小’
而基础手册章节 5.4.2 TLB的表项 的页大小不止4KB和4MB,好像常见为16KB
我不大明白入口地址页号是不是指TLB’页’?
LS1C102无cache,无TLB,我不懂LS1C102是否具备有’页’?
6)入口地址举例
6.1)相对boot偏移0x0380
明显不满足基础手册
6.2)相对boot偏移0x1000
而且低12位为0,说满足精简版也说得过去
4KB/页=0x1000
页号1*4KB/页+页内偏移0 刚好等于0x1000这个入口地址(偏移)
所以LS1C102是不是例外入口地址寄存器的域值[31:0]满足低12位为0(刚好4KB/页)就是入口地址?
7)EENTRY值
按基础手册,该寄存器域值[31:0]只是代表含有页号部分,不一定就是地址
例如EENTRY值0x1c001000
按16KB/页,那0x1c001 * 16KB+0=0x70004000才是入口地址?
按 4KB/页,那0x1c001 * 4KB+0 =0x1c001000就是入口地址等同EENTRY值
2.原厂自带程序片段
3.loongide代码片断
主要是有关CPU定时器中断部分
1)启动
1.1)/home/linlin/loongprj/myls1c102/core/start.S
1.2)/home/linlin/loongprj/myls1c102/core/bsp_start.c
2)CPU定时器
主要是为实现延时功能
2.1)/home/linlin/loongprj/myls1c102/core/tick.c
delay_us代码略去,实际用循环,没用到中断
delay_ms代码的Clock_driver_ticks由中断产生,但仍然循环读
调用关系
3)中断处理框架
3.1)/home/linlin/loongprj/myls1c102/core/irq.c
LS1C102各中断是共同的入口地址,所以需读取ESTAT(例外状态寄存器)区分
这是loongide 1.2正式版生成代码,可以看出是先处理中断,后清除中断标志
3.2)loongide另一版本生成的代码,却是先清中断再处理
4 )
4.1)/home/linlin/loongprj/myls1c102/ls1c102/include/cpu.h
4.2 )
在loongide界面搜索菜单查找打开的工程项目是搜不到__csrxchg_w定义
工程项目是有引用/home/linlin/.wine/drive_c/LoongIDE/la32-tool/lib/gcc/loongarch32-newlib-elf/8.3.0/include/的
可能loongide界面搜索菜单查找功能只搜项目自身源码,不会搜引用的文件
到文件管理器搜索/home/linlin/.wine/drive_c/LoongIDE/目录下文件含__csrxchg_w内容
搜索到在/home/linlin/.wine/drive_c/LoongIDE/la32-tool/lib/gcc/loongarch32-newlib-elf/8.3.0/include/larchintrin.h
继续搜索/home/linlin/.wine/drive_c/LoongIDE/目录下文件含__builtin_loongarch_csrxchg_w内容,但是搜不到定义
难道__builtin_的意思是内置在编译器?为什么不用源码内嵌汇编宏定义形式?
因此下面干脆就自己写一段C代码反汇编看看
5)开中断
已见到loongarch_interrupt_enable()对应是
6)关中断
编译、链接后,反汇编
已见到loongarch_interrupt_disable()对应是
4.addi.w
反汇编addi.w显示的格式 -5(0xffb),应该是针对12位立即数显示0xffb,表示的数学意义是减去5或等效加上0xFFFFFffb,不是表达加上0xffb
12位数范围-0x800 ~ -1,0 ~ 0x7ff
编写汇编源码会要求按范围格式,如
1 )
addi.w t0,zero, 0x800 // -0x801、0xffb、0x800等都为Immediate overflow
gcc编译结果出错
main.S: Assembler messages:
main.S:3: Fatal error: Immediate overflow.
format: s
2 )
addi.w t0,zero, 0x7ff
编译成功
3 )
addi.w t0,zero, -0x800
编译成功、反汇编结果
4 )
addi.w t0,zero, -0x7ff
指令编码的第21:10为立即数