根据我对documentation,2.8.2的理解,启动内核1的过程是通过FIFO发送一个值序列,最后的3个值是向量表、堆栈指针和入口点,而内核1会将这些值回送给您。
从文档提供的C代码中,我写出了这个程序集:
.cpu cortex-m0
.thumb
ent:
ldr r0, =0x20001000
mov sp, r0 @init stack pointer
ldr r0, =0xe000ed08
ldr r3, [r0] @vector table offset register
core:
mov r7, pc
b fifo_drain
sev
mov r1, #0
mov r7, pc
b fifo_writ
mov r7, pc
b fifo_read
cmp r1, #0
bne core
mov r7, pc
b fifo_drain
sev
mov r1, #0
mov r7, pc
b fifo_writ
mov r7, pc
b fifo_read
cmp r1, #0
bne core
mov r1, #1
mov r7, pc
b fifo_writ
mov r7, pc
b fifo_read
cmp r1, #1
bne core
mov r1, r3 @vector table
mov r7, pc
b fifo_writ
mov r7, pc
b fifo_read
cmp r1, r3
bne core
mov r1, sp @stack pointer
mov r7, pc
b fifo_writ
mov r7, pc
b fifo_read
cmp r1, sp
bne core
mov r1, pc
add r1, #2 @entry point
mov r7, pc
b fifo_writ
mov r7, pc
b fifo_read
ldr r0, =0xd0000000
ldr r1, [r0]
cmp r1, #1
beq led
通过FIFO发送的值序列为{0,0,1,vt,sp,ent},当值没有返回时,序列重新开始。入口点仅为最后4行,内核从SIO读取CPUID寄存器,如果CPU id为1,则打开LED(GPIO 25)。
这个序列似乎在向量表的循环中卡住了,这是有道理的,因为我几乎不理解它,FIFO只是不回显它。而且,文档在入口点旁边有一个注解,上面写着“不要忘记thumb位!",不管这是什么意思。
编辑:
更新代码,相同问题:
.cpu cortex-m0
.thumb
ent:
ldr r0, =0x20001000
mov sp, r0 @init stack pointer
ldr r0, =0xe000ed08
ldr r1, =0x20000000
str r1, [r0] @init vtor
ldr r0, =0xd0000000
ldr r1, [r0]
cmp r1, #1
beq led
b core
.thumb_func
core:
mov r7, pc
b fifo_drain
mov r1, #0
mov r7, pc
b fifo_writ
mov r7, pc
b fifo_read
cmp r1, #0
bne core
mov r7, pc
b fifo_drain
mov r1, #0
mov r7, pc
b fifo_writ
mov r7, pc
b fifo_read
cmp r1, #0
bne core
mov r1, #1
mov r7, pc
b fifo_writ
mov r7, pc
b fifo_read
cmp r1, #1
bne core
ldr r3, =0x20000000
mov r1, r3 @vector table
mov r7, pc
b fifo_writ
mov r7, pc
b fifo_read
cmp r1, r3
bne core
mov r1, sp @stack pointer
mov r7, pc
b fifo_writ
mov r7, pc
b fifo_read
cmp r1, sp
bne core
ldr r3, =0x20000001
mov r1, r3 @entry point
mov r7, pc
b fifo_writ
mov r7, pc
b fifo_read
cmp r1, r3
bne core
b loop
.thumb_func
fifo_stat:
ldr r0, =0xd0000050
ldr r1, [r0]
mov r2, #15
and r1, r1, r2
mov pc, r7
.thumb_func
fifo_writ:
ldr r0, =0xd0000050
ldr r3, [r0]
mov r2, #2
and r3, r3, r2
beq fifo_writ
ldr r0, =0xd0000054
str r1, [r0]
sev
mov pc, r7
.thumb_func
fifo_read:
ldr r0, =0xd0000050
ldr r3, [r0]
mov r2, #1
and r3, r3, r2
beq _wfe
ldr r0, =0xd0000058
ldr r1, [r0]
mov pc, r7
.thumb_func
fifo_drain:
ldr r0, =0xd0000058
ldr r1, [r0]
ldr r0, =0xd0000050
ldr r1, [r0]
mov r2, #1
and r1, r1, r2
bne fifo_drain
sev
mov pc, r7
.thumb_func
_wfe:
wfe
b fifo_read
.thumb_func
led:
movs r1, #32 @io_bank
ldr r0, =0x4000f000
str r1, [r0] @release reset on io_bank
movs r1, #5 @sio
ldr r0, =0x400140cc
str r1, [r0] @assign sio to gpio25_ctrl
movs r1, #1
lsl r1, r1, #25
ldr r0, =0xd0000024
str r1, [r0] @enable output
ldr r0, =0xd0000014
str r1, [r0] @turn on the led
.thumb_func
loop:
nop
b loop
1条答案
按热度按时间eoxn13cs1#
我的核心零代码是C和汇编语言的混合体。我想我们可以解决你的问题。
我的引导程序看起来像这样
我链接了0x 20000000,并为sram/0x 20000000构建了uf 2文件,作为二进制文件的目的地。
我的核心零代码看起来像这样
如果感兴趣的话,我的核心代码看起来像这样
thumb位是什么意思?如果您查看ARM文档中的bx指令或其他相关信息(armv 6-m架构参考手册)。这回到了可以运行arm和thumb代码的全尺寸核心。由于两种模式中的指令是对齐的,因此它们选择使用lsbit用于按地址分支,以确定在分支目的地使用的模式(最初只有bx指令,但后来pop和其他指令)。如果lsbit被设置,则它分支到thumb指令,如果被重置,则分支到arm指令。
他们选择的cortex-ms采用向量表(根据产品的目标市场而定),而不是像之前的全尺寸内核(ARM 7、ARM9、ARM 10、ARM 11)那样采用硬编码地址。正如架构参考手册中所述,第一个字是一个值,放入堆栈指针中以保存 Boot 过程中的该步骤,第二个字是复位向量。
现在ARM选择这样做,你必须把一个thumb函数指针地址在那里,这意味着lsbit是ORRed与一。我强调ORRed与一,而不是加一,因为如果你使用你的工具正确(IMO),然后工具将设置lsbit和加一,你会打破它。
让工具完成工作
(This不工作在一个皮科,这是一个什么是拇指它的意思)。
.thumb_func使它在代码中找到的下一个标签成为thumb函数地址,而不仅仅是普通的旧地址。
因此,这给出了
为不同的MCU构建和链接,而不是pci。重置在0x 00200040,挂起在0x 00200046。工具已经为我们完成了工作,因为我们使用了.thumb_func,并将地址orred与一个放在一起。
一切都很好,这个MCU将 Boot ,或者至少它不会挂后重置的权利。
更长的方法是,没有.arm_func,所以对于ARM和thumb,您可以改为
它不一定要紧接在标签之前,但您必须做额外的工作来键入标签名称。
如果我把你的代码改成这样:
然后我得到
该工具已创建了核心1的入口点地址,并设置了lsbit。20000065
接下来的问题是
在核心0执行的这一点上,您正在获取核心0堆栈指针地址,并为核心1设置该地址。如果在启动核心1后在无限循环中结束核心0,那么这就可以了,但是如果你想继续用核心0做事情,你需要给予核心1它自己的堆栈指针。在我的示例中,您可以看到,我将内核0指定为0x 20002000,将内核1指定为0x 20003000。这将非常难以调试,因为内核1将启动,但每次更改代码时,都会出现随机混乱。
还有你的VTOR问题。我也试过只阅读VTOR,但它不起作用。最初我的代码有一个特殊的向量表:
我设置了向量表,而不是读取它
对于core zero,它可能是从我写的其他皮科代码中借用的,这些代码可能实际上使用了这个表。b重置是因为我们实际上没有使用core zero的重置向量,所以这是我的组装。可以做对齐的工作,并将向量表放在内存中的其他地方(是的,对于两个内核,最初我自己设置了堆栈指针,但对于上面的示例,假设内核1自己设置)。
并对核心1使用相同的地址vector_table。在这种情况下,我可以读取它,它会工作。您只提供了一个分数,因此我们不知道您在此代码之前对核心0的VTOR做了什么,但我假设您没有设置它,因为您的代码不工作。
在这些例子中,你/我们没有使用向量表,所以只需要让它高兴,所以我只是强制0x 20000000,然后它就工作了。
我相信你需要修正所有三个地址,向量表,入口点,和堆栈指针,以获得成功。
根据你的重写,我做了这些修改。
首先,在一些地方,你使用r3来保存你想在写和阅读回之后进行比较的值。但是r3在写和读中都被使用,所以它的内容丢失了。
第二,程序大于0x 100字节,有一些奇怪的东西,我必须了解我是如何弄清楚的,所以通过避免边界,然后它的工作。
正如上面使用的sp不需要去r4,但我这样做是为了猎枪的问题。
如果我删除不需要的项(写入VTOR,a B核心在前面。我使用bl和bx lr来调用和返回,这节省了足够的指令,使二进制小于0x 100字节。它可以在没有边界的情况下使用。
请注意,指令集允许执行以下操作:
不像蛮力和简单的阅读,但节省指令。
对于一个刚刚学习ARM汇编语言的人来说,我认为rp 2040在同一时间。我印象深刻,继续出色的工作。这个特别的MCU非常非常酷,但也很差的文件。ARM指令集是有文件的,但与ARM对比拇指,然后统一语法对比没有(幸运的是你没有击中差异)。而这个0x 100字节的东西,我不记得我是怎么弄明白的,我想我看了他们的代码,并从中弄明白了,但我得重新调查一下如果你想亲自确认取一个0x 100字节以下的版本,然后在正文中的某个地方添加一些nop,使其延伸到0x 100字节以上。请注意所描述的简单更改,并删除未使用的/我把你的密码弄到了
216字节......
最低限度。
你对这三个参数的想法是正确的,但它们需要一些工作。然后是一个简单的哎呀,在一个函数调用之外使用一个寄存器,在一个函数调用之内使用。然后是疯狂的0x 100字节的事情。这是裸机的事情,很难调试,必须磨你的方式通过,不要给予。
mov r7,pc的事情,我其实印象深刻,而不是批评-很多人会挣扎与两个指令提前的事情。