software: add minimal baremetal demo app.

Used to demonstrates how to easily create baremetal apps, boot to it with LiteX and
also ease litex_term testing.

To build it: export BUILD_DIR=xxyy/litex/litex/boards/targets/build/arty && make
To load it: lxterm /dev/ttyUSB1 --kernel=demo.bin

--============== Boot ==================--
Booting from serial...
Press Q or ESC to abort boot completely.
sL5DdSMmkekro
[LXTERM] Received firmware download request from the device.
[LXTERM] Uploading demo.bin to 0x40000000 (9264 bytes)...
[LXTERM] Upload complete (9.8KB/s).
[LXTERM] Booting the device.
[LXTERM] Done.
Executing booted program at 0x40000000

--============= Liftoff! ===============--

LiteX minimal demo app built Dec 10 2020 17:13:02

Available commands:
help               - Show this command
reboot             - Reboot CPU
led                - Led demo
donut              - Spinning Donut demo
litex-demo-app> led
Led demo...
Counter mode...
Shift mode...
Dance mode...
litex-demo-app> donut
Donut demo...

                                      $$$$$@@@@@
                                  $##########$$$$$$$$
                               ###*!!!!!!!!!***##$$$$$$
                             ***!!====;;;;===!!**###$$$$#
                            **!===;;;:::::;:===!!**####$##
                          !*!!==;;:~-,,.,-~::;;=!!**#######!
                          !!!!=;:~-,.......-~::==!!***#####*
                         !!!!==;~~-.........,-:;==!!***###**!
                         !**!!=;:~-...     ..-:;=!!!********!
                        ;!*#####*!!;.       ~:;==!!!******!!=
                        :!*###$$$$#*!      :;==!!!!!****!!!=;
                        ~=!*#$$$@@@$$##!!!!!!!!!!!!****!!!!=;
                         ;=!*#$$$@@@@$$#*******!*!!*!!!!!==;~
                         -;!*###$$$$$$$###******!!!!!!!===;~
                          -;!!*####$#####******!!!!!!==;;:-
                           ,:=!!!!**#**#***!!!!!!!====;:~,
                             -:==!!!*!!*!!!!!!!===;;;:~-
                               .~:;;========;=;;:::~-,
                                  .--~~::::~:~~--,.
litex-demo-app>
This commit is contained in:
Florent Kermarrec 2020-12-10 17:14:30 +01:00
parent ef6fd57613
commit 88bd754dd6
5 changed files with 370 additions and 0 deletions

View File

@ -0,0 +1,42 @@
BUILD_DIR?=../build/
include $(BUILD_DIR)/software/include/generated/variables.mak
include $(SOC_DIRECTORY)/software/common.mak
OBJECTS=isr.o donut.o main.o
all: demo.bin
# pull in dependency info for *existing* .o files
-include $(OBJECTS:.o=.d)
%.bin: %.elf
$(OBJCOPY) -O binary $< $@
chmod -x $@
demo.elf: $(OBJECTS)
$(LD) $(LDFLAGS) \
-T linker.ld \
-N -o $@ \
$(BUILD_DIR)/software/libbase/crt0.o \
$(OBJECTS) \
-L$(BUILD_DIR)/software/libbase \
-L$(BUILD_DIR)/software/libcompiler_rt \
-lbase-nofloat -lcompiler_rt
chmod -x $@
main.o: main.c
$(compile)
donut.o: CFLAGS += -w
%.o: %.c
$(compile)
%.o: %.S
$(assemble)
clean:
$(RM) $(OBJECTS) $(OBJECTS:.o=.d) demo.elf demo.bin .*~ *~
.PHONY: all main.o clean load

View File

@ -0,0 +1,67 @@
// The donut code with fixed-point arithmetic; no sines, cosines, square roots, or anything.
// a1k0n 2020
// Code from: https://gist.github.com/a1k0n/80f48aa8911fffd805316b8ba8f48e83
// For more info:
// - https://www.a1k0n.net/2011/07/20/donut-math.html
// - https://www.youtube.com/watch?v=DEqXNfs_HhY
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <console.h>
#define R(mul,shift,x,y) \
_=x; \
x -= mul*y>>shift; \
y += mul*_>>shift; \
_ = 3145728-x*x-y*y>>11; \
x = x*_>>10; \
y = y*_>>10;
signed char b[1760], z[1760];
void donut(void) {
int sA=1024,cA=0,sB=1024,cB=0,_;
for (;;) {
memset(b, 32, 1760); // text buffer
memset(z, 127, 1760); // z buffer
int sj=0, cj=1024;
for (int j = 0; j < 90; j++) {
int si = 0, ci = 1024; // sine and cosine of angle i
for (int i = 0; i < 324; i++) {
int R1 = 1, R2 = 2048, K2 = 5120*1024;
int x0 = R1*cj + R2,
x1 = ci*x0 >> 10,
x2 = cA*sj >> 10,
x3 = si*x0 >> 10,
x4 = R1*x2 - (sA*x3 >> 10),
x5 = sA*sj >> 10,
x6 = K2 + R1*1024*x5 + cA*x3,
x7 = cj*si >> 10,
x = 40 + 30*(cB*x1 - sB*x4)/x6,
y = 12 + 15*(cB*x4 + sB*x1)/x6,
N = (-cA*x7 - cB*((-sA*x7>>10) + x2) - ci*(cj*sB >> 10) >> 10) - x5 >> 7;
int o = x + 80 * y;
signed char zz = (x6-K2)>>15;
if (22 > y && y > 0 && x > 0 && 80 > x && zz < z[o]) {
z[o] = zz;
b[o] = ".,-~:;=!*#$@"[N > 0 ? N : 0];
}
R(5, 8, ci, si) // rotate i
}
R(9, 7, cj, sj) // rotate j
}
for (int k = 0; 1761 > k; k++)
putchar(k % 80 ? b[k] : 10);
R(5, 7, cA, sA);
R(5, 8, cB, sB);
if (readchar_nonblock()) {
readchar();
break;
}
putsnonl("\x1b[23A");
}
}

View File

@ -0,0 +1,29 @@
// This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
// License: BSD
#include <generated/csr.h>
#include <generated/soc.h>
#include <irq.h>
#include <uart.h>
void isr(void);
#ifdef CONFIG_CPU_HAS_INTERRUPT
void isr(void)
{
__attribute__((unused)) unsigned int irqs;
irqs = irq_pending() & irq_getmask();
#ifndef UART_POLLING
if(irqs & (1 << UART_INTERRUPT))
uart_isr();
#endif
}
#else
void isr(void){};
#endif

View File

@ -0,0 +1,56 @@
INCLUDE generated/output_format.ld
ENTRY(_start)
__DYNAMIC = 0;
INCLUDE generated/regions.ld
SECTIONS
{
.text :
{
_ftext = .;
*(.text .stub .text.* .gnu.linkonce.t.*)
_etext = .;
} > main_ram
.rodata :
{
. = ALIGN(4);
_frodata = .;
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.rodata1)
_erodata = .;
} > main_ram
.data :
{
. = ALIGN(4);
_fdata = .;
*(.data .data.* .gnu.linkonce.d.*)
*(.data1)
_gp = ALIGN(16);
*(.sdata .sdata.* .gnu.linkonce.s.*)
_edata = .;
} > main_ram
.bss :
{
. = ALIGN(4);
_fbss = .;
*(.dynsbss)
*(.sbss .sbss.* .gnu.linkonce.sb.*)
*(.scommon)
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
. = ALIGN(4);
_ebss = .;
_end = .;
} > sram
}
PROVIDE(_fstack = ORIGIN(sram) + LENGTH(sram) - 4);
PROVIDE(_fdata_rom = LOADADDR(.data));
PROVIDE(_edata_rom = LOADADDR(.data) + SIZEOF(.data));

View File

@ -0,0 +1,176 @@
// This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
// License: BSD
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <irq.h>
#include <uart.h>
#include <console.h>
#include <generated/csr.h>
/*-----------------------------------------------------------------------*/
/* Uart */
/*-----------------------------------------------------------------------*/
static char *readstr(void)
{
char c[2];
static char s[64];
static int ptr = 0;
if(readchar_nonblock()) {
c[0] = readchar();
c[1] = 0;
switch(c[0]) {
case 0x7f:
case 0x08:
if(ptr > 0) {
ptr--;
putsnonl("\x08 \x08");
}
break;
case 0x07:
break;
case '\r':
case '\n':
s[ptr] = 0x00;
putsnonl("\n");
ptr = 0;
return s;
default:
if(ptr >= (sizeof(s) - 1))
break;
putsnonl(c);
s[ptr] = c[0];
ptr++;
break;
}
}
return NULL;
}
static char *get_token(char **str)
{
char *c, *d;
c = (char *)strchr(*str, ' ');
if(c == NULL) {
d = *str;
*str = *str+strlen(*str);
return d;
}
*c = 0;
d = *str;
*str = c+1;
return d;
}
static void prompt(void)
{
printf("\e[92;1mlitex-demo-app\e[0m> ");
}
/*-----------------------------------------------------------------------*/
/* Help */
/*-----------------------------------------------------------------------*/
static void help(void)
{
puts("\nLiteX minimal demo app built "__DATE__" "__TIME__"\n");
puts("Available commands:");
puts("help - Show this command");
puts("reboot - Reboot CPU");
puts("led - Led demo");
puts("donut - Spinning Donut demo");
}
/*-----------------------------------------------------------------------*/
/* Commands */
/*-----------------------------------------------------------------------*/
static void reboot_cmd(void)
{
ctrl_reset_write(1);
}
static void led_cmd(void)
{
int i;
printf("Led demo...\n");
printf("Counter mode...\n");
for(i=0; i<32; i++) {
leds_out_write(i);
busy_wait(100);
}
printf("Shift mode...\n");
for(i=0; i<4; i++) {
leds_out_write(1<<i);
busy_wait(200);
}
for(i=0; i<4; i++) {
leds_out_write(1<<(3-i));
busy_wait(200);
}
printf("Dance mode...\n");
for(i=0; i<4; i++) {
leds_out_write(0x55);
busy_wait(200);
leds_out_write(0xaa);
busy_wait(200);
}
}
extern void donut(void);
static void donut_cmd(void)
{
printf("Donut demo...\n");
donut();
}
/*-----------------------------------------------------------------------*/
/* Console service / Main */
/*-----------------------------------------------------------------------*/
static void console_service(void)
{
char *str;
char *token;
str = readstr();
if(str == NULL) return;
token = get_token(&str);
if(strcmp(token, "help") == 0)
help();
else if(strcmp(token, "reboot") == 0)
reboot_cmd();
else if(strcmp(token, "led") == 0)
led_cmd();
else if(strcmp(token, "donut") == 0)
donut_cmd();
prompt();
}
int main(void)
{
#ifdef CONFIG_CPU_HAS_INTERRUPT
irq_setmask(0);
irq_setie(1);
#endif
uart_init();
help();
prompt();
while(1) {
console_service();
}
return 0;
}