复制04_arduino_step03到05_interrupt_step01,修改工程名字。
本例程先跑通一个简单的实现。
硬件实现的功能包括:
说明:
module core (
...
input wire ext_int,
output wire int_active,
...
);
其中int_active用于表示当前处于中断处理状态,目前没用上。
采用FSM的方式进行中断处理。
代码段1:
//FSM section 1
localparam S_INT_IDLE = 0, S_INT_TRIGGERED = 1, S_INT_ACTIVE=2, S_INT_MRET=3;
reg [1:0] current_state = 0, next_state;
always @(negedge core_clk or negedge reset_n) begin
if (!reset_n) begin
current_state <= S_INT_IDLE;
end else begin
current_state <= next_state;
end
end
解读:声明四种状态。用core_clk的下降沿触发切换状态。
普通状态是S_INT_IDLE,当输入的中断请求信号有效(高电平)时,core_clk的下降沿触发切换进入S_INT_TRIGGERED状态。
之所以使用core_clk下降沿触发,是因为这时当前指令的执行动作已基本完成(除了回写和STORE操作也是由下降沿触发),下一条指令的地址也已确定。这时触发中断可以保证当前指令完成以及明确断点位置。
代码段2:
//FSM section 2
//ctrl signal
reg ctrl_int_triggered;
reg ctrl_int_mret;
always @(*) begin
next_state = 0;
ctrl_int_triggered = 0;
ctrl_int_mret = 0;
case (current_state)
S_INT_IDLE: begin
if (ext_int) begin
next_state <= S_INT_TRIGGERED;
end else begin
next_state <= S_INT_IDLE;
end
end
S_INT_TRIGGERED : begin
ctrl_int_triggered = 1'b1;
next_state <= S_INT_ACTIVE;
end
S_INT_ACTIVE : begin
if (inst_MRET) begin
next_state <= S_INT_MRET;
end else begin
next_state <= S_INT_ACTIVE;
end
end
S_INT_MRET : begin
ctrl_int_mret = 1'b1;
next_state <= S_INT_IDLE;
end
default: begin
next_state <= S_INT_IDLE;
end
endcase
end
//FSM section 3
always @(posedge ctrl_int_triggered) begin
csr_mepc <= pc_next;
end
解读:
S_INT_IDLE: begin
if (ext_int) begin
next_state <= S_INT_TRIGGERED;
S_INT_TRIGGERED : begin
ctrl_int_triggered = 1'b1;
next_state <= S_INT_ACTIVE;
always @(posedge ctrl_int_triggered) begin
csr_mepc <= pc_next;
end
S_INT_ACTIVE : begin
if (inst_MRET) begin
next_state <= S_INT_MRET;
将入口地址固定为0x80002e00。
wire [31:0] isr_entrance = 32'h80002e00;
assign pc_next_with_int = (ctrl_int_triggered) ? isr_entrance : pc_next;
修改原有的pc代码,将送PC寄存器的值由pc_next改为pc_next_with_int。这样当ctrl_int_triggered即S_INT_TRIGGERED状态下,下一PC值为isr_entrance:
//PC
reg [31:0] program_counter;
wire [31:0] pc_next;
wire [31:0] pc_next_with_int;
always @(posedge core_clk or negedge reset_n) begin
if (~reset_n) begin
program_counter <= 32'b0;
end
else begin
// program_counter <= pc_next;
program_counter <= pc_next_with_int;
end
end
译码:
wire opcode_SYSTEM = (opcode == 7'b1110011);
wire inst_MRET = opcode_SYSTEM & (funct12 == 12'b001100000010);
执行,将断点(csr_mepc)送pc_next:
assign pc_next = (~reset_n_sync) ? 32'b0 :
branch_in_effect ? program_counter + i_imm_B :
inst_JALR ? rs1_plus_imm_i :
inst_JAL ? program_counter + i_imm_J :
inst_MRET ? csr_mepc : pc_plus_four;
本例程中演示按键0的中断。
首先将按键0的按下事件产生一个wire_clk宽度的脉冲,采用移位寄存器实现:
//external interrupt
reg [1:0] int_delay;
always @(posedge core_clk) begin
int_delay <= {int_delay[0], button[0]};
end
wire ext_int_pulse = int_delay[1] & (~int_delay[0]);
然后将脉冲信号送core:
core m_core (
...
.ext_int(ext_int_pulse),
//
.monitor_port(monitor_port)
);
致谢:中断矢量表和中断服务入口程序的实现参考了esp32c3的开源代码。
软件的主要问题是要增加一个section,放置中断矢量表和中断服务程序。然后需要修改链接配置文件使该section的代码出现在指定位置(硬件写死了在0x80002e00)。
在arduino的环境下,hardware\riscv\tangnano9k\cores\riscv目录下,新增vectors.S文件。
.section .exception_vectors.text,"a"
其中,"a"标志表示该段包含“ALLOC”属性,为可执行段,在由elf转hex时要包含。
没有该标志,则hex文件中不会有该section中的代码(即使在elf中有)。我在这上面折腾了很长时间。
.balign 0x100
.global _vector_table
.type _vector_table, @function
_vector_table:
.rept (16)
j _interrupt_handler
.endr
填充了16个中服入口,都指向_interrupt_handler。
.global _global_interrupt_handler
.global _interrupt_handler
.type _interrupt_handler, @function
_interrupt_handler:
save_general_regs
jal _global_interrupt_handler
restore_general_regs
mret
保护现场,然后调用c代码的_global_interrupt_handler函数,然后恢复现场,然后执行mret指令。
保护现场
.equ SAVE_REGS, 8
.equ CONTEXT_SIZE, (SAVE_REGS * 4)
.macro save_general_regs cxt_size=CONTEXT_SIZE
addi sp, sp, -\cxt_size
sw ra, 0(sp)
sw a0, 4(sp)
sw a1, 8(sp)
sw a2, 12(sp)
sw a3, 16(sp)
sw a4, 20(sp)
sw a5, 24(sp)
sw a6, 28(sp)
.endm
恢复现场
.macro restore_general_regs cxt_size=CONTEXT_SIZE
lw ra, 0(sp)
lw a0, 4(sp)
lw a1, 8(sp)
lw a2, 12(sp)
lw a3, 16(sp)
lw a4, 20(sp)
lw a5, 24(sp)
lw a6, 28(sp)
addi sp,sp, \cxt_size
.endm
通用寄存器组本来还有很多寄存器的,先保护用上了的一部分。
调试过程中发现vectors.S中的内容没有被链接上(那时section后面没加"a"),临时找到一个变通办法,让main()调用这里的一个空函数。
#let main() call this to link this file
.global donothing
.type donothing, @function
donothing:
ret
在cores\riscv目录下新增interrupt.c文件。
在其中实现_global_interrupt_handler函数:
/* called from vectors.S */
#include "halTangnanoTiny.h"
void _global_interrupt_handler(){
halUartSend(0x31);
}
这里是按键中断的功能实现,向串口发一个0x31字符。
将来可以扩展为调用ino文件中用户定义的回调函数。
修改cores\riscv目录下的main.c文件,先调用.S文件中的donothing()。
#include "Arduino.h"
extern void donothing();
int main(){
donothing(); //for linking the vectors.S
setup();
while (1) {
loop();
}
return 0;
}
修改hardware\riscv\tangnano9k\variants\generic\Reindeer.ld,在data-segment前面增加.exception_vectors section的链接地址:
. = SEGMENT_START("exception-segment", 0x80002E00);
.exception_vectors :
{
*(.exception_vectors.text .exception_vectors.text.* .exception_vectors.*)
}
. = SEGMENT_START("data-segment", 0x00000400);
由于需要对.S文件进行汇编,原来的环境中缺少riscv-none-elf-as.exe文件。该文件已经上传到仓库里。下载放到:hardware\riscv\tangnano9k\tools\gcc\bin目录下。
修改platform.txt,增加:
compiler.S.flags=
compiler.S.cmd=riscv-none-elf-as
recipe.S.o.pattern="{compiler.path}{compiler.S.cmd}" {compiler.S.flags} {build.extra_flags} -I{build.path}/sketch {includes} "{source_file}" -o "{object_file}"
先烧写fpga工程,然后下载arduino工程(blink03)。
打开串口助手,可以看到正常情况下周期性地上传递增数据(同时led变化)。
按下button0,可以在串口收到0x31。
Blink03.ino.elf: file format elf32-littleriscv
Disassembly of section .text:
80002000 <_start>:
80002000: 00001137 lui sp,0x1
80002004: 0680006f j 8000206c <main>
80002008 <_fini>:
80002008: 0000006f j 80002008 <_fini>
8000200c <setup>:
8000200c: 00008067 ret
80002010 <loop>:
80002010: ff010113 addi sp,sp,-16 # ff0 <__global_pointer$+0x3ec>
80002014: 00112623 sw ra,12(sp)
80002018: 40402503 lw a0,1028(zero) # 404 <gCount>
8000201c: 00150513 addi a0,a0,1
80002020: 40a02223 sw a0,1028(zero) # 404 <gCount>
80002024: 018000ef jal ra,8000203c <halUartSend>
80002028: 00a00513 li a0,10
8000202c: 028000ef jal ra,80002054 <halDelay>
80002030: 00c12083 lw ra,12(sp)
80002034: 01010113 addi sp,sp,16
80002038: 00008067 ret
8000203c <halUartSend>:
8000203c: ff010113 addi sp,sp,-16
80002040: 00a12623 sw a0,12(sp)
80002044: 00c12783 lw a5,12(sp)
80002048: 00f02823 sw a5,16(zero) # 10 <SAVE_REGS+0x8>
8000204c: 01010113 addi sp,sp,16
80002050: 00008067 ret
80002054 <halDelay>:
80002054: 00050a63 beqz a0,80002068 <halDelay+0x14>
80002058: 00000793 li a5,0
8000205c: 00000013 nop
80002060: 00178793 addi a5,a5,1
80002064: fef51ce3 bne a0,a5,8000205c <halDelay+0x8>
80002068: 00008067 ret
8000206c <main>:
8000206c: ff010113 addi sp,sp,-16
80002070: 00112623 sw ra,12(sp)
80002074: 61d000ef jal ra,80002e90 <donothing>
80002078: f95ff0ef jal ra,8000200c <setup>
8000207c: f95ff0ef jal ra,80002010 <loop>
80002080: ffdff06f j 8000207c <main+0x10>
80002084 <_global_interrupt_handler>:
80002084: ff010113 addi sp,sp,-16
80002088: 00112623 sw ra,12(sp)
8000208c: 03100513 li a0,49
80002090: fadff0ef jal ra,8000203c <halUartSend>
80002094: 00c12083 lw ra,12(sp)
80002098: 01010113 addi sp,sp,16
8000209c: 00008067 ret
Disassembly of section .exception_vectors:
80002e00 <_vector_table>:
80002e00: 0400006f j 80002e40 <_interrupt_handler>
80002e04: 03c0006f j 80002e40 <_interrupt_handler>
80002e08: 0380006f j 80002e40 <_interrupt_handler>
80002e0c: 0340006f j 80002e40 <_interrupt_handler>
80002e10: 0300006f j 80002e40 <_interrupt_handler>
80002e14: 02c0006f j 80002e40 <_interrupt_handler>
80002e18: 0280006f j 80002e40 <_interrupt_handler>
80002e1c: 0240006f j 80002e40 <_interrupt_handler>
80002e20: 0200006f j 80002e40 <_interrupt_handler>
80002e24: 01c0006f j 80002e40 <_interrupt_handler>
80002e28: 0180006f j 80002e40 <_interrupt_handler>
80002e2c: 0140006f j 80002e40 <_interrupt_handler>
80002e30: 0100006f j 80002e40 <_interrupt_handler>
80002e34: 00c0006f j 80002e40 <_interrupt_handler>
80002e38: 0080006f j 80002e40 <_interrupt_handler>
80002e3c: 0040006f j 80002e40 <_interrupt_handler>
80002e40 <_interrupt_handler>:
80002e40: fe010113 addi sp,sp,-32
80002e44: 00112023 sw ra,0(sp)
80002e48: 00a12223 sw a0,4(sp)
80002e4c: 00b12423 sw a1,8(sp)
80002e50: 00c12623 sw a2,12(sp)
80002e54: 00d12823 sw a3,16(sp)
80002e58: 00e12a23 sw a4,20(sp)
80002e5c: 00f12c23 sw a5,24(sp)
80002e60: 01012e23 sw a6,28(sp)
80002e64: a20ff0ef jal ra,80002084 <_global_interrupt_handler>
80002e68: 00012083 lw ra,0(sp)
80002e6c: 00412503 lw a0,4(sp)
80002e70: 00812583 lw a1,8(sp)
80002e74: 00c12603 lw a2,12(sp)
80002e78: 01012683 lw a3,16(sp)
80002e7c: 01412703 lw a4,20(sp)
80002e80: 01812783 lw a5,24(sp)
80002e84: 01c12803 lw a6,28(sp)
80002e88: 02010113 addi sp,sp,32
80002e8c: 30200073 mret
80002e90 <donothing>:
80002e90: 00008067 ret
Disassembly of section .eh_frame:
00000400 <__FRAME_END__>:
400: 0000 .2byte 0x0
...
Disassembly of section .sbss:
00000404 <gCount>:
404: 0000 .2byte 0x0
...
:0404000000000000F8
:0200000480007A
:10200000371100006F0080066F000000678000003D
:10201000130101FF2326110003254040130515007D
:102020002322A040EF0080011305A000EF008002F2
:102030008320C1001301010167800000130101FF2B
:102040002326A1008327C1002328F00013010101EA
:1020500067800000630A050093070000130000007A
:1020600093871700E31CF5FE67800000130101FF52
:1020700023261100EF00D061EFF05FF9EFF05FF978
:102080006FF0DFFF130101FF23261100130510037A
:10209000EFF0DFFA8320C100130101016780000027
:102E00006F0000046F00C0036F0080036F00400379
:102E10006F0000036F00C0026F0080026F0040026D
:102E20006F0000026F00C0016F0080016F00400161
:102E30006F0000016F00C0006F0080006F00400055
:102E4000130101FE232011002322A1002324B1003D
:102E50002326C1002328D100232AE100232CF100DE
:102E6000232E0101EFF00FA2832001000325410072
:102E7000832581000326C100832601010327410128
:102E8000832781010328C10113010102730020304F
:042E90006780000057
:040000058000200057
:00000001FF
>C:\Arduino\hardware\riscv\tangnano9k\tools\gcc\bin\riscv-none-elf-objdump.exe -h Blink03.ino.elf
Blink03.ino.elf: file format elf32-littleriscv
Sections:
Idx Name Size VMA LMA File off Algn
0 .text 000000a0 80002000 80002000 00001000 2**2
CONTENTS, ALLOC, LOAD, READONLY, CODE
1 .exception_vectors 00000094 80002e00 80002e00 00001e00 2**8
CONTENTS, ALLOC, LOAD, READONLY, DATA
2 .eh_frame 00000004 00000400 00000400 00000400 2**2
CONTENTS, ALLOC, LOAD, DATA
3 .sbss 00000004 00000404 00000404 00000404 2**2
ALLOC
4 .comment 00000033 00000000 00000000 00001e94 2**0
CONTENTS, READONLY
5 .riscv.attributes 00000020 00000000 00000000 00001ec7 2**0
CONTENTS, READONLY
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。