Improved IRQ documentation, added assembler macros

This commit is contained in:
Clifford Wolf 2015-06-28 02:10:45 +02:00
parent 792baeabcf
commit 818faffe25
12 changed files with 182 additions and 77 deletions

View File

@ -47,9 +47,9 @@ tests/%.o: tests/%.S tests/riscv_test.h tests/test_macros.h
-DTEST_FUNC_TXT='"$(notdir $(basename $<))"' -DTEST_FUNC_RET=$(notdir $(basename $<))_ret $< -DTEST_FUNC_TXT='"$(notdir $(basename $<))"' -DTEST_FUNC_RET=$(notdir $(basename $<))_ret $<
clean: clean:
rm -vrf $(TEST_OBJS) firmware/firmware.elf firmware/firmware.bin firmware/firmware.hex \ rm -vrf $(FIRMWARE_OBJS) $(TEST_OBJS) \
firmware/firmware.map testbench*.exe testbench.vcd .Xil fsm_encoding.os \ firmware/firmware.{elf,bin,hex,map} \
synth_vivado.log synth_vivado_*.backup.log synth_vivado.v testbench{,_sp,_axi}.exe testbench.vcd
.PHONY: test test_sp test_axi clean .PHONY: test test_sp test_axi clean

View File

@ -206,53 +206,51 @@ one bit is set in `q1`.
Registers `q2` and `q3` are uninitialized and can be used as temporary storage Registers `q2` and `q3` are uninitialized and can be used as temporary storage
when saving/restoring register values in the IRQ handler. when saving/restoring register values in the IRQ handler.
All of the following instructions are encoded under the `custom0` opcode. All of the following instructions are encoded under the `custom0` opcode. The f3
and rs2 fields are ignored in all this instructions.
See [firmware/custom_ops.S](firmware/custom_ops.S) for GNU assembler macros that
implement mnemonics for this instructions.
See [firmware/start.S](firmware/start.S) for an example implementaion of an
interrupt handler assember wrapper, and [firmware/irq.c](firmware/irq.c) for
the actual interrupt handler.
#### getq rd, qs #### getq rd, qs
This instruction copies the value from a q-register to a general-purpose This instruction copies the value from a q-register to a general-purpose
register. register.
0000000 00000 000XX 000 XXXXX 0001011 0000000 ----- 000XX --- XXXXX 0001011
f7 rs2 qs f3 rd opcode f7 rs2 qs f3 rd opcode
Example assembler code using the `custom0` mnemonic: Example:
| Instruction | Assember Code | getq x5, q2
| ------------------| --------------------|
| getq x5, q2 | custom0 5, 2, 0, 0 |
| getq x3, q0 | custom0 3, 0, 0, 0 |
| getq x1, q3 | custom0 1, 3, 0, 0 |
#### setq qd, rs #### setq qd, rs
This instruction copies the value from a general-purpose register to a This instruction copies the value from a general-purpose register to a
q-register. q-register.
0000001 00000 XXXXX 000 000XX 0001011 0000001 ----- XXXXX --- 000XX 0001011
f7 rs2 rs f3 qd opcode f7 rs2 rs f3 qd opcode
Example assembler code using the `custom0` mnemonic: Example:
| Instruction | Assember Code | setq q2, x5
| ------------------| --------------------|
| setq q2, x5 | custom0 2, 5, 0, 1 |
| setq q0, x3 | custom0 0, 3, 0, 1 |
| setq q3, x1 | custom0 3, 1, 0, 1 |
#### retirq #### retirq
Return from interrupt. This instruction copies the value from `q0` Return from interrupt. This instruction copies the value from `q0`
to the program counter and re-enables interrupts. to the program counter and re-enables interrupts.
0000010 00000 00000 000 00000 0001011 0000010 ----- 00000 --- 00000 0001011
f7 rs2 rs f3 rd opcode f7 rs2 rs f3 rd opcode
Example assembler code using the `custom0` mnemonic: Example:
| Instruction | Assember Code | retirq
| ------------------| --------------------|
| retirq | custom0 0, 0, 0, 2 |
#### maskirq #### maskirq
@ -260,14 +258,12 @@ The "IRQ Mask" register contains a bitmask of masked (disabled) interrupts.
This instruction writes a new value to the irq mask register and reads the old This instruction writes a new value to the irq mask register and reads the old
value. value.
0000011 00000 XXXXX 000 XXXXX 0001011 0000011 ----- XXXXX --- XXXXX 0001011
f7 rs2 rs f3 rd opcode f7 rs2 rs f3 rd opcode
Example assembler code using the `custom0` mnemonic: Example:
| Instruction | Assember Code | maskirq x1, x2
| ------------------| --------------------|
| maskirq x1, x2 | custom0 1, 2, 0, 3 |
The processor starts with all interrupts disabled. The processor starts with all interrupts disabled.
@ -276,17 +272,15 @@ interrupt is disabled will cause the processor to halt.
#### waitirq #### waitirq
Pause execution until an interrupt triggers. The bitmask of pending IRQs is Pause execution until an interrupt becomes pending. The bitmask of pending IRQs
written to `rd`. is written to `rd`.
0000100 00000 00000 000 XXXXX 0001011 0000100 ----- 00000 --- XXXXX 0001011
f7 rs2 rs f3 rd opcode f7 rs2 rs f3 rd opcode
Example assembler code using the `custom0` mnemonic: Example:
| Instruction | Assember Code | waitirq x1
| ------------------| --------------------|
| waitirq x1 | custom0 1, 0, 0, 4 |
#### timer #### timer
@ -295,14 +289,12 @@ triggers the timer interrupt when transitioning from 1 to 0. Setting the
counter to zero disables the timer. The old value of the counter is written to counter to zero disables the timer. The old value of the counter is written to
`rd`. `rd`.
0000101 00000 XXXXX 000 XXXXX 0001011 0000101 ----- XXXXX --- XXXXX 0001011
f7 rs2 rs f3 rd opcode f7 rs2 rs f3 rd opcode
Example assembler code using the `custom0` mnemonic: Example:
| Instruction | Assember Code | timer x1, x2
| ------------------| --------------------|
| timer x1, x2 | custom0 1, 2, 0, 5 |
Building a pure RV32I Toolchain: Building a pure RV32I Toolchain:

36
firmware/custom_ops.S Normal file
View File

@ -0,0 +1,36 @@
// 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 q0 0
#define q1 1
#define q2 2
#define q3 3
.macro getq rd qs
custom0 \rd,\qs,0,0
.endm
.macro setq qd rs
custom0 \qd,\rs,0,1
.endm
.macro retirq
custom0 0,0,0,2
.endm
.macro maskirq rd rs
custom0 \rd,\rs,0,3
.endm
.macro waitirq rd
custom0 \rd,0,0,4
.endm
.macro timer rd rs
custom0 \rd,\rs,0,5
.endm

View File

@ -1,3 +1,10 @@
// 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.
#ifndef FIRMWARE_H #ifndef FIRMWARE_H
#define FIRMWARE_H #define FIRMWARE_H

View File

@ -1,3 +1,9 @@
// 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.
#include "firmware.h" #include "firmware.h"

View File

@ -1,4 +1,11 @@
#!/usr/bin/python3 #!/usr/bin/python3
#
# 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.
from sys import argv from sys import argv

View File

@ -1,3 +1,10 @@
// 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.
#include "firmware.h" #include "firmware.h"
uint32_t xorshift32() { uint32_t xorshift32() {

View File

@ -1,3 +1,9 @@
// 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.
#include "firmware.h" #include "firmware.h"

View File

@ -1,3 +1,12 @@
/*
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.
*/
SECTIONS { SECTIONS {
.memory : { .memory : {
. = 0x000000; . = 0x000000;

View File

@ -1,3 +1,10 @@
// 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.
// A simple Sieve of Eratosthenes // A simple Sieve of Eratosthenes
#include "firmware.h" #include "firmware.h"

View File

@ -1,8 +1,17 @@
// 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 ENABLE_RVTST #define ENABLE_RVTST
#define ENABLE_SIEVE #define ENABLE_SIEVE
#define ENABLE_MULTST #define ENABLE_MULTST
#define ENABLE_STATS #define ENABLE_STATS
#include "custom_ops.S"
.section .text .section .text
.global irq .global irq
.global sieve .global sieve
@ -13,43 +22,33 @@
.global hard_mulhu .global hard_mulhu
.global stats .global stats
#ifdef ENABLE_RVTST
# define TEST(n) \
.global n; \
addi x1, zero, 1000; \
custom0 0,1,0,5; /* timer zero, x1 */ \
jal zero,n; \
.global n ## _ret; \
n ## _ret:
#else
# define TEST(n) \
.global n ## _ret; \
n ## _ret:
#endif
reset_vec: reset_vec:
custom0 0,0,0,4 // waitirq zero // no more than 16 bytes here !
custom0 0,0,0,3 // maskirq zero, zero waitirq zero
maskirq zero, zero
j start j start
nop
nop
/* Interrupt handler
**********************************/
.balign 16
irq_vec: irq_vec:
/* save registers */ /* save registers */
custom0 2,1,0,1 // setq q2, x1 setq q2, x1
custom0 3,2,0,1 // setq q3, x2 setq q3, x2
lui x1, %hi(irq_regs) lui x1, %hi(irq_regs)
addi x1, x1, %lo(irq_regs) addi x1, x1, %lo(irq_regs)
custom0 2,0,0,0 // getq x2, q0 getq x2, q0
sw x2, 0*4(x1) sw x2, 0*4(x1)
custom0 2,2,0,0 // getq x2, q2 getq x2, q2
sw x2, 1*4(x1) sw x2, 1*4(x1)
custom0 2,3,0,0 // getq x2, q3 getq x2, q3
sw x2, 2*4(x1) sw x2, 2*4(x1)
sw x3, 3*4(x1) sw x3, 3*4(x1)
@ -82,19 +81,19 @@ irq_vec:
sw x30, 30*4(x1) sw x30, 30*4(x1)
sw x31, 31*4(x1) sw x31, 31*4(x1)
/* call interrupt handler */ /* call interrupt handler C function */
lui sp, %hi(irq_stack_top) lui sp, %hi(irq_stack)
addi sp, sp, %lo(irq_stack_top) addi sp, sp, %lo(irq_stack)
// arg0 = address of regs // arg0 = address of regs
lui a0, %hi(irq_regs) lui a0, %hi(irq_regs)
addi a0, a0, %lo(irq_regs) addi a0, a0, %lo(irq_regs)
// arg1 = interrupt type // arg1 = interrupt type
custom0 11,1,0,0 // getq x11, q1 getq x11, q1
// call to c function // call to C function
jal ra, irq jal ra, irq
/* restore registers */ /* restore registers */
@ -103,13 +102,13 @@ irq_vec:
addi x1, x1, %lo(irq_regs) addi x1, x1, %lo(irq_regs)
lw x2, 0*4(x1) lw x2, 0*4(x1)
custom0 0,2,0,1 // setq q0, x2 setq q0, x2
lw x2, 1*4(x1) lw x2, 1*4(x1)
custom0 1,2,0,1 // setq q1, x2 setq q1, x2
lw x2, 2*4(x1) lw x2, 2*4(x1)
custom0 2,2,0,1 // setq q2, x2 setq q2, x2
lw x3, 3*4(x1) lw x3, 3*4(x1)
lw x4, 4*4(x1) lw x4, 4*4(x1)
@ -141,21 +140,27 @@ irq_vec:
lw x30, 30*4(x1) lw x30, 30*4(x1)
lw x31, 31*4(x1) lw x31, 31*4(x1)
custom0 1,1,0,0 // getq x1, q1 getq x1, q1
custom0 2,2,0,0 // getq x2, q2 getq x2, q2
custom0 0,0,0,2 // retirq retirq
irq_regs: irq_regs:
// registers are saved to this memory region // registers are saved to this memory region during interrupt handling
// the program counter is saved as register 0 // the program counter is saved as register 0
.fill 32,4 .fill 32,4
irq_stack: // stack for the interrupt handler
.fill 128,4 .fill 128,4
irq_stack_top: irq_stack:
/* Main program
**********************************/
start: start:
/* zero-initialize all registers */
addi x1, zero, 0 addi x1, zero, 0
addi x2, zero, 0 addi x2, zero, 0
addi x3, zero, 0 addi x3, zero, 0
@ -188,6 +193,22 @@ start:
addi x30, zero, 0 addi x30, zero, 0
addi x31, zero, 0 addi x31, zero, 0
/* running tests from riscv-tests */
#ifdef ENABLE_RVTST
# define TEST(n) \
.global n; \
addi x1, zero, 1000; \
timer zero, x1; \
jal zero,n; \
.global n ## _ret; \
n ## _ret:
#else
# define TEST(n) \
.global n ## _ret; \
n ## _ret:
#endif
TEST(lui) TEST(lui)
TEST(auipc) TEST(auipc)
TEST(j) TEST(j)

View File

@ -1,3 +1,10 @@
// 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.
#include "firmware.h" #include "firmware.h"
static void stats_print_dec(int val, int digits, bool zero_pad) static void stats_print_dec(int val, int digits, bool zero_pad)