-
-
Save btashton/4aa7ed42bc81ff4716821636997d9df9 to your computer and use it in GitHub Desktop.
/* uartblink.S -- Brennan Ashton <bashton@brennanashton.com> | |
* | |
*************************************************************************** | |
* 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. | |
*************************************************************************** | |
* | |
* ABOUT: | |
* This is a test for handling interrupts and ecall for the SERV core | |
* it can be run like this: | |
* fusesoc run --target=verilator_tb servant --uart_baudrate=115200 | |
* --firmware=uartblink.hex --timeout=10000000 | |
* | |
* The expected result is a stream of 'a\n' with some 'b\n' on the console. | |
* the a is a busy loop, while the b indicates an interrupt is handled. | |
* right now the interrupts should be disabled until ecall is issued in | |
* which case machine interrupts are re-enabled via the mpie bit in mstatus. | |
* | |
* It appears that this bit does not actually work with this core. So you | |
* will see a single 'b\n' from the ecall, but no interrupts from the timer. | |
* The expected behavior can be seen when the mie bit is set before ecall | |
* This line is currently commented out. | |
*/ | |
#ifndef UART_BASE | |
#define UART_BASE 0x40000000 | |
#endif | |
#ifndef TIMER_BASE | |
#define TIMER_BASE 0x80000000 | |
#endif | |
#ifndef DELAY | |
#define DELAY 10 /* Loop 10 times before writing UART */ | |
#endif | |
#ifndef TICK_COUNT | |
#define TICK_COUNT 40000 /* 40000 cycles per tick */ | |
#endif | |
/* | |
* "RESERVED" registers: | |
* a0 = UART Base address | |
* a1 = Timer Base address | |
* a2 = One | |
* t1 = delay max value | |
* t2 = Current timer value | |
* t3 = timer tick | |
*/ | |
.globl _start | |
.globl __trap_vec | |
_start: | |
/* Load GPIO base address to a0 */ | |
li a0, UART_BASE | |
/* Load TIMER base address to a1 */ | |
li a1, TIMER_BASE | |
/* Set busy timer value to control blink speed */ | |
li t1, DELAY | |
/* Initialize UART (stop bit) */ | |
li a2, 1 | |
sb a2, 0(a0) | |
nop | |
nop | |
/* Initialize Timer */ | |
li t3, TICK_COUNT | |
lw t4, 0(a1) | |
add t4, t4, t3 | |
sw t4, 0(a1) | |
/* Disable Interrupts */ | |
csrw mstatus, zero | |
/* setup trap */ | |
lui t0, %hi(__trap_vec) | |
addi t0, t0, %lo(__trap_vec) | |
csrw mtvec, t0 | |
/* Initialize timer interrupt */ | |
li t6, 0x80 | |
csrs mie, t6 | |
/* We should be able to enable interrupts via the MPIE bit of mstatus | |
* in the exception handler logic. These two instructions will enable | |
* interrupts ahead of the exception handler being called. | |
*/ | |
//li t5, 0x8 | |
//csrs mstatus, t5 | |
ecall | |
blinky: | |
/* "blink 'a\n' on the UART */ | |
/* Reset timer */ | |
and t2, zero, zero | |
/* Enter critical */ | |
li t0, 0x8 | |
csrrc t4, mstatus, t0 | |
jal uart_a | |
jal uart_nl | |
/* Leave critical */ | |
csrw mstatus, t4 | |
/* Delay loop */ | |
time1: | |
addi t2, t2, 1 | |
bne t1, t2, time1 | |
j blinky | |
/* Trap Vector */ | |
__trap_vec: | |
/* Increment the PC (only for ecall?) */ | |
csrr t4, mepc | |
addi t4, t4, 4 | |
csrw mepc, t4 | |
/* add to the timer offset */ | |
li t3, TICK_COUNT | |
lw t4, 0(a1) | |
add t4, t4, t3 | |
sw t4, 0(a1) | |
/* "blink" 'b\n' on UART */ | |
jal uart_b | |
jal uart_nl | |
/* Let's see if the mstatus mpie works. | |
* Interrupts should be enabled after this returns | |
*/ | |
li t4, 0x80 | |
csrw mstatus, t4 | |
mret | |
/* uart utility functions */ | |
uart_a: | |
/* 'a' */ | |
sb zero, 0(a0) | |
nop | |
nop | |
sb a2, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb a2, 0(a0) | |
nop | |
nop | |
sb a2, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb a2, 0(a0) | |
nop | |
nop | |
ret | |
uart_b: | |
/* 'b' */ | |
sb zero, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb a2, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb a2, 0(a0) | |
nop | |
nop | |
sb a2, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb a2, 0(a0) | |
nop | |
nop | |
ret | |
uart_nl: | |
/* '\n' */ | |
sb zero, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb a2, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb a2, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb zero, 0(a0) | |
nop | |
nop | |
sb a2, 0(a0) | |
nop | |
nop | |
ret |
Just tried your mpie branch. Still not working for my case.
I'm new to risc-v, so I may be missing something. I've been wrapping SERV with a SoC to allow XIP (execute in place) directly from Flash on the icebreaker.
https://github.com/DaveBerkeley/fpga/tree/master/serv
This is all working fine, except I can't enable the timer interrupt.
Oh excellent work! I can take a look later today. Do you have a full code listing where you use these functions I could look at?
https://github.com/DaveBerkeley/fpga/blob/master/serv/firmware.c
But I'm using my own timer hardware
https://github.com/DaveBerkeley/fpga/blob/master/serv/timer.v
I was embarrassed to find that it adds 500 LUTs to the usage (including the irq code in SERV). My timer has 2 x 64-registers and a 32-bit temp register.
If you compile with -O1
optimisation gcc does a great job of producing minimal code.
I'm also using a hardware uart for tx which you might like. It delays ack until the next byte can be sent, which removes the need for bit-banging or polling the uart for busy.
@DaveBerkeley have you tried running the assembly in this gist? It was broken in the way mentioned in description, but was resolved by my PR olofk/serv#31. @olofk implemented a different approach that should also fix this issue, as well as another one I found and mentioned in the PR. I have not validating the change that he made in master, but you might try my PR and we can get to the bottom of all of this.