PoC: Add LED toggling interrupt example

Add example firmware for demoing interrupts on Tkey hardware.
This commit is contained in:
Mikael Ågren 2024-12-06 16:45:24 +01:00
parent 5e15b40a86
commit 5dfe549969
No known key found for this signature in database
GPG Key ID: E02DA3D397792C46
5 changed files with 221 additions and 0 deletions

View File

@ -149,6 +149,10 @@ IRQPOC_OBJS = \
$(P)/fw/irqpoc/main.o \ $(P)/fw/irqpoc/main.o \
$(P)/fw/irqpoc/start.o $(P)/fw/irqpoc/start.o
IRQPOC_LED_TOGGLE_OBJS = \
$(P)/fw/irqpoc_led_toggle/main.o \
$(P)/fw/irqpoc_led_toggle/start.o
#------------------------------------------------------------------- #-------------------------------------------------------------------
# All: Complete build of HW and FW. # All: Complete build of HW and FW.
#------------------------------------------------------------------- #-------------------------------------------------------------------
@ -186,6 +190,7 @@ LDFLAGS = -T $(P)/fw/tk1/firmware.lds
$(FIRMWARE_OBJS): $(FIRMWARE_DEPS) $(FIRMWARE_OBJS): $(FIRMWARE_DEPS)
$(TESTFW_OBJS): $(FIRMWARE_DEPS) $(TESTFW_OBJS): $(FIRMWARE_DEPS)
$(IRQPOC_OBJS): $(FIRMWARE_DEPS) $(IRQPOC_OBJS): $(FIRMWARE_DEPS)
$(IRQPOC_LED_TOGGLE_OBJS): $(FIRMWARE_DEPS)
firmware.elf: $(FIRMWARE_OBJS) $(P)/fw/tk1/firmware.lds firmware.elf: $(FIRMWARE_OBJS) $(P)/fw/tk1/firmware.lds
$(CC) $(CFLAGS) $(FIRMWARE_OBJS) $(LDFLAGS) -o $@ $(CC) $(CFLAGS) $(FIRMWARE_OBJS) $(LDFLAGS) -o $@
@ -231,6 +236,9 @@ testfw.elf: $(TESTFW_OBJS) $(P)/fw/tk1/firmware.lds
irqpoc.elf: $(IRQPOC_OBJS) $(P)/fw/tk1/firmware.lds irqpoc.elf: $(IRQPOC_OBJS) $(P)/fw/tk1/firmware.lds
$(CC) $(CFLAGS) $(IRQPOC_OBJS) $(LDFLAGS) -o $@ $(CC) $(CFLAGS) $(IRQPOC_OBJS) $(LDFLAGS) -o $@
irqpoc_led_toggle.elf: $(IRQPOC_LED_TOGGLE_OBJS) $(P)/fw/tk1/firmware.lds
$(CC) $(CFLAGS) $(IRQPOC_LED_TOGGLE_OBJS) $(LDFLAGS) -o $@
# Generate a fake BRAM file that will be filled in later after place-n-route # Generate a fake BRAM file that will be filled in later after place-n-route
bram_fw.hex: bram_fw.hex:
$(ICESTORM_PATH)icebram -v -g 32 $(BRAM_FW_SIZE) > $@ $(ICESTORM_PATH)icebram -v -g 32 $(BRAM_FW_SIZE) > $@
@ -510,6 +518,7 @@ clean_fw:
rm -f testfw.{elf,elf.map,bin,hex} rm -f testfw.{elf,elf.map,bin,hex}
rm -f $(TESTFW_OBJS) rm -f $(TESTFW_OBJS)
rm -f $(IRQPOC_OBJS) rm -f $(IRQPOC_OBJS)
rm -f $(IRQPOC_LED_TOGGLE_OBJS)
rm -f qemu_firmware.elf rm -f qemu_firmware.elf
.PHONY: clean_fw .PHONY: clean_fw

View File

@ -0,0 +1,9 @@
# Uses ../.clang-format
FMTFILES=main.c
.PHONY: fmt
fmt:
clang-format --dry-run --ferror-limit=0 $(FMTFILES)
clang-format --verbose -i $(FMTFILES)
.PHONY: checkfmt
checkfmt:
clang-format --dry-run --ferror-limit=0 --Werror $(FMTFILES)

View File

@ -0,0 +1,102 @@
// This is free and unencumbered software released into the public domain.
//
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
#define regnum_q0 0
#define regnum_q1 1
#define regnum_q2 2
#define regnum_q3 3
#define regnum_x0 0
#define regnum_x1 1
#define regnum_x2 2
#define regnum_x3 3
#define regnum_x4 4
#define regnum_x5 5
#define regnum_x6 6
#define regnum_x7 7
#define regnum_x8 8
#define regnum_x9 9
#define regnum_x10 10
#define regnum_x11 11
#define regnum_x12 12
#define regnum_x13 13
#define regnum_x14 14
#define regnum_x15 15
#define regnum_x16 16
#define regnum_x17 17
#define regnum_x18 18
#define regnum_x19 19
#define regnum_x20 20
#define regnum_x21 21
#define regnum_x22 22
#define regnum_x23 23
#define regnum_x24 24
#define regnum_x25 25
#define regnum_x26 26
#define regnum_x27 27
#define regnum_x28 28
#define regnum_x29 29
#define regnum_x30 30
#define regnum_x31 31
#define regnum_zero 0
#define regnum_ra 1
#define regnum_sp 2
#define regnum_gp 3
#define regnum_tp 4
#define regnum_t0 5
#define regnum_t1 6
#define regnum_t2 7
#define regnum_s0 8
#define regnum_s1 9
#define regnum_a0 10
#define regnum_a1 11
#define regnum_a2 12
#define regnum_a3 13
#define regnum_a4 14
#define regnum_a5 15
#define regnum_a6 16
#define regnum_a7 17
#define regnum_s2 18
#define regnum_s3 19
#define regnum_s4 20
#define regnum_s5 21
#define regnum_s6 22
#define regnum_s7 23
#define regnum_s8 24
#define regnum_s9 25
#define regnum_s10 26
#define regnum_s11 27
#define regnum_t3 28
#define regnum_t4 29
#define regnum_t5 30
#define regnum_t6 31
// x8 is s0 and also fp
#define regnum_fp 8
#define r_type_insn(_f7, _rs2, _rs1, _f3, _rd, _opc) \
.word (((_f7) << 25) | ((_rs2) << 20) | ((_rs1) << 15) | ((_f3) << 12) | ((_rd) << 7) | ((_opc) << 0))
#define picorv32_getq_insn(_rd, _qs) \
r_type_insn(0b0000000, 0, regnum_ ## _qs, 0b100, regnum_ ## _rd, 0b0001011)
#define picorv32_setq_insn(_qd, _rs) \
r_type_insn(0b0000001, 0, regnum_ ## _rs, 0b010, regnum_ ## _qd, 0b0001011)
#define picorv32_retirq_insn() \
r_type_insn(0b0000010, 0, 0, 0b000, 0, 0b0001011)
#define picorv32_maskirq_insn(_rd, _rs) \
r_type_insn(0b0000011, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)
#define picorv32_waitirq_insn(_rd) \
r_type_insn(0b0000100, 0, 0, 0b100, regnum_ ## _rd, 0b0001011)
#define picorv32_timer_insn(_rd, _rs) \
r_type_insn(0b0000101, 0, regnum_ ## _rs, 0b110, regnum_ ## _rd, 0b0001011)

View File

@ -0,0 +1,10 @@
/*
* Copyright (C) 2022, 2023 - Tillitis AB
* SPDX-License-Identifier: GPL-2.0-only
*/
int main(void)
{
while (1) {
}
}

View File

@ -0,0 +1,91 @@
/*
* Copyright (C) 2022, 2023 - Tillitis AB
* SPDX-License-Identifier: GPL-2.0-only
*/
// Triggers both interrupts, one after the other, in an endless loop. The
// interrupt handler updates the LED color depending on which interrupt
// was triggered.
// The LED color will alterate between blue and green.
//
// | IRQ number | Color |
// |------------|-------|
// | 30 | Blue |
// | 31 | Green |
// | Unexpected | Red |
//
#include "custom_ops.S" // PicoRV32 custom instructions
.section ".text.init"
.globl _start
_start:
j init
.=0x10 // IRQ handler at fixed address 0x10
irq_handler:
// PicoRV32 stores the IRQ bitmask in x4.
// If bit 31 is 1: IRQ31 was triggered.
// If bit 30 is 1: IRQ30 was triggered.
irq30_check:
li t4, (1 << 30)
bne x4, t4, irq31_check
call led_blue
call delay
j irq_source_check_done
irq31_check:
li t4, (1 << 31)
bne x4, t4, unexpected_irq
call led_green
call delay
j irq_source_check_done
unexpected_irq:
call led_red
call delay
irq_source_check_done:
picorv32_retirq_insn() // Return from interrupt
init:
li t0, 0x3fffffff // IRQ31 & IRQ30 mask
picorv32_maskirq_insn(zero, t0) // Enable IRQs
irq_trigger_loop:
li t0, 0xe1000000 // IRQ31 trigger address
sw zero, 0(t0) // Raise IRQ by writing to interrupt trigger address.
// Writing any data triggers an interrupt.
li t0, 0xe0000000 // IRQ30 trigger address
sw zero, 0(t0) // Raise IRQ by writing to interrupt trigger address.
// Writing any data triggers an interrupt.
j irq_trigger_loop
led_red:
li t2, 0xff000024
li t3, (1 << 2)
sw t3, 0(t2)
ret
led_green:
li t2, 0xff000024
li t3, (1 << 1)
sw t3, 0(t2)
ret
led_blue:
li t2, 0xff000024
li t3, (1 << 0)
sw t3, 0(t2)
ret
delay:
li t5, 0x100000
delay_dec:
addi t5, t5, -1
bne t5, zero, delay_dec
ret
.align 4 // Padding to please makehex.py which requires even 4-byte file
// sizes.