mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
bios: add terminal history
Terminal history and characters parsing is done in readline.c. Passing TERM_NO_HIST disable terminal history. Passing TERM_MINI use a simple terminal implementation in order to save more space.
This commit is contained in:
parent
e764eabda1
commit
bc5a1986e2
5 changed files with 500 additions and 49 deletions
|
@ -2,7 +2,7 @@ include ../include/generated/variables.mak
|
|||
include $(SOC_DIRECTORY)/software/common.mak
|
||||
|
||||
ifeq ($(CPU),blackparrot)
|
||||
BP_LIBS = -L$(BP_EXTERNAL_DIR)/lib/gcc/riscv64-unknown-elf/8.3.0
|
||||
BP_LIBS = -L$(BP_EXTERNAL_DIR)/lib/gcc/riscv64-unknown-elf/8.3.0
|
||||
BP_FLAGS = -lgcc
|
||||
endif
|
||||
# Permit TFTP_SERVER_PORT override from shell environment / command line
|
||||
|
@ -12,6 +12,17 @@ endif
|
|||
|
||||
OBJECTS=isr.o sdram.o sdcard.o main.o boot-helper.o boot.o
|
||||
|
||||
ifdef TERM_NO_HIST
|
||||
CFLAGS += -DTERM_NO_HIST
|
||||
endif
|
||||
|
||||
ifdef TERM_MINI
|
||||
CFLAGS += -DTERM_MINI
|
||||
OBJECTS += readline_simple.o
|
||||
else
|
||||
OBJECTS += readline.o
|
||||
endif
|
||||
|
||||
all: bios.bin
|
||||
$(PYTHON) -m litex.soc.software.memusage bios.elf $(CURDIR)/../include/generated/regions.ld $(TRIPLE)
|
||||
|
||||
|
@ -39,7 +50,7 @@ bios.elf: $(BIOS_DIRECTORY)/linker.ld $(OBJECTS)
|
|||
$(BP_LIBS) \
|
||||
-lnet -lbase-nofloat -lcompiler_rt \
|
||||
$(BP_FLAGS)
|
||||
|
||||
|
||||
ifneq ($(OS),Windows_NT)
|
||||
chmod -x $@
|
||||
endif
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
// This file is Copyright (c) 2018 Jean-François Nguyen <jf@lambdaconcept.fr>
|
||||
// This file is Copyright (c) 2018 Sergiusz Bazanski <q3k@q3k.org>
|
||||
// This file is Copyright (c) 2016 Tim 'mithro' Ansell <mithro@mithis.com>
|
||||
// This file is Copyright (c) 2020 Franck Jullien <franck.jullien@gmail.com>
|
||||
|
||||
// License: BSD
|
||||
|
||||
|
@ -42,6 +43,7 @@
|
|||
#include "sdram.h"
|
||||
#include "sdcard.h"
|
||||
#include "boot.h"
|
||||
#include "readline.h"
|
||||
|
||||
/* General address space functions */
|
||||
|
||||
|
@ -548,48 +550,6 @@ static void crcbios(void)
|
|||
}
|
||||
}
|
||||
|
||||
static void readstr(char *s, int size)
|
||||
{
|
||||
static char skip = 0;
|
||||
char c[2];
|
||||
int ptr;
|
||||
|
||||
c[1] = 0;
|
||||
ptr = 0;
|
||||
while(1) {
|
||||
c[0] = readchar();
|
||||
if (c[0] == skip)
|
||||
continue;
|
||||
skip = 0;
|
||||
switch(c[0]) {
|
||||
case 0x7f:
|
||||
case 0x08:
|
||||
if(ptr > 0) {
|
||||
ptr--;
|
||||
putsnonl("\x08 \x08");
|
||||
}
|
||||
break;
|
||||
case 0x07:
|
||||
break;
|
||||
case '\r':
|
||||
skip = '\n';
|
||||
s[ptr] = 0x00;
|
||||
putsnonl("\n");
|
||||
return;
|
||||
case '\n':
|
||||
skip = '\r';
|
||||
s[ptr] = 0x00;
|
||||
putsnonl("\n");
|
||||
return;
|
||||
default:
|
||||
putsnonl(c);
|
||||
s[ptr] = c[0];
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void boot_sequence(void)
|
||||
{
|
||||
if(serialboot()) {
|
||||
|
@ -614,7 +574,7 @@ static void boot_sequence(void)
|
|||
|
||||
int main(int i, char **c)
|
||||
{
|
||||
char buffer[64];
|
||||
char buffer[CMD_LINE_BUFFER_SIZE];
|
||||
int sdr_ok;
|
||||
#ifdef CONFIG_CPU_HAS_INTERRUPT
|
||||
irq_setmask(0);
|
||||
|
@ -696,10 +656,17 @@ int main(int i, char **c)
|
|||
}
|
||||
|
||||
printf("--============= \e[1mConsole\e[0m ================--\n");
|
||||
while(1) {
|
||||
putsnonl("\e[92;1mlitex\e[0m> ");
|
||||
readstr(buffer, 64);
|
||||
do_command(buffer);
|
||||
#if !defined(TERM_MINI) && !defined(TERM_NO_HIST)
|
||||
hist_init();
|
||||
#endif
|
||||
printf("\n%s", PROMPT);
|
||||
while(1) {
|
||||
readline(buffer, CMD_LINE_BUFFER_SIZE);
|
||||
if (buffer[0] != 0) {
|
||||
printf("\n");
|
||||
do_command(buffer);
|
||||
}
|
||||
printf("\n%s", PROMPT);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
331
litex/soc/software/bios/readline.c
Normal file
331
litex/soc/software/bios/readline.c
Normal file
|
@ -0,0 +1,331 @@
|
|||
// This file is Copyright (c) 2020 Franck Jullien <franck.jullien@gmail.com>
|
||||
//
|
||||
// Largely inspired/copied from U-boot and Barebox projects wich are:
|
||||
// Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
|
||||
// Sascha Hauer, Pengutronix, <s.hauer@pengutronix.de>
|
||||
// cmdline-editing related codes from vivi
|
||||
// Author: Janghoon Lyu <nandy@mizi.com>
|
||||
|
||||
// SPDX-License-Identifier: BSD-Source-Code
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <console.h>
|
||||
#include <uart.h>
|
||||
|
||||
#include "readline.h"
|
||||
|
||||
#ifndef TERM_NO_HIST
|
||||
static int hist_max = 0;
|
||||
static int hist_add_idx = 0;
|
||||
static int hist_cur = 0;
|
||||
static int hist_num = 0;
|
||||
static char hist_lines[HIST_MAX][CMD_LINE_BUFFER_SIZE];
|
||||
#endif
|
||||
|
||||
#define ARRAY_SIZE(array) (sizeof(array) / sizeof(array[0]))
|
||||
|
||||
static const struct esc_cmds esccmds[] = {
|
||||
{"OA", KEY_UP}, // cursor key Up
|
||||
{"OB", KEY_DOWN}, // cursor key Down
|
||||
{"OC", KEY_RIGHT}, // Cursor Key Right
|
||||
{"OD", KEY_LEFT}, // cursor key Left
|
||||
{"OH", KEY_HOME}, // Cursor Key Home
|
||||
{"OF", KEY_END}, // Cursor Key End
|
||||
{"[A", KEY_UP}, // cursor key Up
|
||||
{"[B", KEY_DOWN}, // cursor key Down
|
||||
{"[C", KEY_RIGHT}, // Cursor Key Right
|
||||
{"[D", KEY_LEFT}, // cursor key Left
|
||||
{"[H", KEY_HOME}, // Cursor Key Home
|
||||
{"[F", KEY_END}, // Cursor Key End
|
||||
{"[1~", KEY_HOME}, // Cursor Key Home
|
||||
{"[2~", KEY_INSERT}, // Cursor Key Insert
|
||||
{"[3~", KEY_DEL}, // Cursor Key Delete
|
||||
{"[4~", KEY_END}, // Cursor Key End
|
||||
{"[5~", KEY_PAGEUP}, // Cursor Key Page Up
|
||||
{"[6~", KEY_PAGEDOWN},// Cursor Key Page Down
|
||||
};
|
||||
|
||||
static int read_key(void)
|
||||
{
|
||||
char c;
|
||||
char esc[5];
|
||||
c = readchar();
|
||||
|
||||
if (c == 27) {
|
||||
int i = 0;
|
||||
esc[i++] = readchar();
|
||||
esc[i++] = readchar();
|
||||
if (isdigit(esc[1])) {
|
||||
while(1) {
|
||||
esc[i] = readchar();
|
||||
if (esc[i++] == '~')
|
||||
break;
|
||||
if (i == ARRAY_SIZE(esc))
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
esc[i] = 0;
|
||||
for (i = 0; i < ARRAY_SIZE(esccmds); i++){
|
||||
if (!strcmp(esc, esccmds[i].seq))
|
||||
return esccmds[i].val;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
#ifndef TERM_NO_HIST
|
||||
static void cread_add_to_hist(char *line)
|
||||
{
|
||||
strcpy(&hist_lines[hist_add_idx][0], line);
|
||||
|
||||
if (++hist_add_idx >= HIST_MAX)
|
||||
hist_add_idx = 0;
|
||||
|
||||
if (hist_add_idx > hist_max)
|
||||
hist_max = hist_add_idx;
|
||||
|
||||
hist_num++;
|
||||
}
|
||||
|
||||
static char* hist_prev(void)
|
||||
{
|
||||
char *ret;
|
||||
int old_cur;
|
||||
|
||||
if (hist_cur < 0)
|
||||
return NULL;
|
||||
|
||||
old_cur = hist_cur;
|
||||
if (--hist_cur < 0)
|
||||
hist_cur = hist_max;
|
||||
|
||||
if (hist_cur == hist_add_idx) {
|
||||
hist_cur = old_cur;
|
||||
ret = NULL;
|
||||
} else {
|
||||
ret = &hist_lines[hist_cur][0];
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char* hist_next(void)
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if (hist_cur < 0)
|
||||
return NULL;
|
||||
|
||||
if (hist_cur == hist_add_idx)
|
||||
return NULL;
|
||||
|
||||
if (++hist_cur > hist_max)
|
||||
hist_cur = 0;
|
||||
|
||||
if (hist_cur == hist_add_idx)
|
||||
ret = "";
|
||||
else
|
||||
ret = &hist_lines[hist_cur][0];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hist_init(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
hist_max = 0;
|
||||
hist_add_idx = 0;
|
||||
hist_cur = -1;
|
||||
hist_num = 0;
|
||||
|
||||
for (i = 0; i < HIST_MAX; i++)
|
||||
hist_lines[i][0] = '\0';
|
||||
}
|
||||
#endif
|
||||
|
||||
static void cread_add_char(char ichar, int insert, unsigned long *num,
|
||||
unsigned long *eol_num, char *buf, unsigned long len)
|
||||
{
|
||||
unsigned long wlen;
|
||||
|
||||
if (insert || *num == *eol_num) {
|
||||
if (*eol_num > len - 1) {
|
||||
getcmd_cbeep();
|
||||
return;
|
||||
}
|
||||
(*eol_num)++;
|
||||
}
|
||||
|
||||
if (insert) {
|
||||
wlen = *eol_num - *num;
|
||||
if (wlen > 1) {
|
||||
memmove(&buf[*num+1], &buf[*num], wlen-1);
|
||||
}
|
||||
|
||||
buf[*num] = ichar;
|
||||
putnstr(buf + *num, wlen);
|
||||
(*num)++;
|
||||
while (--wlen) {
|
||||
getcmd_putch(CTL_BACKSPACE);
|
||||
}
|
||||
} else {
|
||||
/* echo the character */
|
||||
wlen = 1;
|
||||
buf[*num] = ichar;
|
||||
putnstr(buf + *num, wlen);
|
||||
(*num)++;
|
||||
}
|
||||
}
|
||||
|
||||
int readline(char *buf, int len)
|
||||
{
|
||||
unsigned long num = 0;
|
||||
unsigned long eol_num = 0;
|
||||
unsigned long wlen;
|
||||
int insert = 1;
|
||||
char ichar;
|
||||
|
||||
while (1) {
|
||||
|
||||
ichar = read_key();
|
||||
|
||||
if ((ichar == '\n') || (ichar == '\r'))
|
||||
break;
|
||||
|
||||
switch (ichar) {
|
||||
case '\t':
|
||||
break;
|
||||
|
||||
case KEY_HOME:
|
||||
BEGINNING_OF_LINE();
|
||||
break;
|
||||
case CTL_CH('c'): /* ^C - break */
|
||||
*buf = 0; /* discard input */
|
||||
return -1;
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
if (num < eol_num) {
|
||||
getcmd_putch(buf[num]);
|
||||
num++;
|
||||
}
|
||||
break;
|
||||
case KEY_LEFT:
|
||||
if (num) {
|
||||
getcmd_putch(CTL_BACKSPACE);
|
||||
num--;
|
||||
}
|
||||
break;
|
||||
case CTL_CH('d'):
|
||||
if (num < eol_num) {
|
||||
wlen = eol_num - num - 1;
|
||||
if (wlen) {
|
||||
memmove(&buf[num], &buf[num+1], wlen);
|
||||
putnstr(buf + num, (int)wlen);
|
||||
}
|
||||
|
||||
getcmd_putch(' ');
|
||||
do {
|
||||
getcmd_putch(CTL_BACKSPACE);
|
||||
} while (wlen--);
|
||||
eol_num--;
|
||||
}
|
||||
break;
|
||||
case KEY_ERASE_TO_EOL:
|
||||
ERASE_TO_EOL();
|
||||
break;
|
||||
case KEY_REFRESH_TO_EOL:
|
||||
case KEY_END:
|
||||
REFRESH_TO_EOL();
|
||||
break;
|
||||
case KEY_INSERT:
|
||||
insert = !insert;
|
||||
break;
|
||||
case KEY_ERASE_LINE:
|
||||
BEGINNING_OF_LINE();
|
||||
ERASE_TO_EOL();
|
||||
break;
|
||||
case DEL:
|
||||
case KEY_DEL7:
|
||||
case 8:
|
||||
if (num) {
|
||||
wlen = eol_num - num;
|
||||
num--;
|
||||
memmove(buf + num, buf + num + 1, wlen);
|
||||
getcmd_putch(CTL_BACKSPACE);
|
||||
putnstr(buf + num, (int)wlen);
|
||||
getcmd_putch(' ');
|
||||
do {
|
||||
getcmd_putch(CTL_BACKSPACE);
|
||||
} while (wlen--);
|
||||
eol_num--;
|
||||
}
|
||||
break;
|
||||
case KEY_DEL:
|
||||
if (num < eol_num) {
|
||||
wlen = eol_num - num;
|
||||
memmove(buf + num, buf + num + 1, wlen);
|
||||
putnstr(buf + num, (int)(wlen - 1));
|
||||
getcmd_putch(' ');
|
||||
do {
|
||||
getcmd_putch(CTL_BACKSPACE);
|
||||
} while (--wlen);
|
||||
eol_num--;
|
||||
}
|
||||
break;
|
||||
case KEY_UP:
|
||||
case KEY_DOWN:
|
||||
{
|
||||
#ifndef TERM_NO_HIST
|
||||
char * hline;
|
||||
if (ichar == KEY_UP)
|
||||
hline = hist_prev();
|
||||
else
|
||||
hline = hist_next();
|
||||
|
||||
if (!hline) {
|
||||
getcmd_cbeep();
|
||||
break;
|
||||
}
|
||||
|
||||
/* nuke the current line */
|
||||
/* first, go home */
|
||||
BEGINNING_OF_LINE();
|
||||
|
||||
/* erase to end of line */
|
||||
ERASE_TO_EOL();
|
||||
|
||||
/* copy new line into place and display */
|
||||
strcpy(buf, hline);
|
||||
eol_num = strlen(buf);
|
||||
REFRESH_TO_EOL();
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
if (isascii(ichar) && isprint(ichar))
|
||||
cread_add_char (ichar, insert, &num, &eol_num, buf, len);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
len = eol_num;
|
||||
buf[eol_num] = '\0';
|
||||
|
||||
#ifndef TERM_NO_HIST
|
||||
if (buf[0] && buf[0] != CREAD_HIST_CHAR)
|
||||
cread_add_to_hist(buf);
|
||||
hist_cur = hist_add_idx;
|
||||
#endif
|
||||
|
||||
num = 0;
|
||||
eol_num = 0;
|
||||
|
||||
return len;
|
||||
}
|
83
litex/soc/software/bios/readline.h
Normal file
83
litex/soc/software/bios/readline.h
Normal file
|
@ -0,0 +1,83 @@
|
|||
#ifndef __READLINE_H__
|
||||
#define __READLINE_H__
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define CMD_LINE_BUFFER_SIZE 64
|
||||
|
||||
#define PROMPT "\e[92;1mlitex\e[0m> "
|
||||
|
||||
#define ESC 27
|
||||
|
||||
struct esc_cmds {
|
||||
const char *seq;
|
||||
char val;
|
||||
};
|
||||
|
||||
#define CTL_CH(c) ((c) - 'a' + 1)
|
||||
|
||||
/* Misc. non-Ascii keys */
|
||||
#define KEY_UP CTL_CH('p') /* cursor key Up */
|
||||
#define KEY_DOWN CTL_CH('n') /* cursor key Down */
|
||||
#define KEY_RIGHT CTL_CH('f') /* Cursor Key Right */
|
||||
#define KEY_LEFT CTL_CH('b') /* cursor key Left */
|
||||
#define KEY_HOME CTL_CH('a') /* Cursor Key Home */
|
||||
#define KEY_ERASE_TO_EOL CTL_CH('k')
|
||||
#define KEY_REFRESH_TO_EOL CTL_CH('e')
|
||||
#define KEY_ERASE_LINE CTL_CH('x')
|
||||
#define KEY_INSERT CTL_CH('o')
|
||||
#define KEY_CLEAR_SCREEN CTL_CH('l')
|
||||
#define KEY_DEL7 127
|
||||
#define KEY_END 133 /* Cursor Key End */
|
||||
#define KEY_PAGEUP 135 /* Cursor Key Page Up */
|
||||
#define KEY_PAGEDOWN 136 /* Cursor Key Page Down */
|
||||
#define KEY_DEL 137 /* Cursor Key Del */
|
||||
|
||||
#define MAX_CMDBUF_SIZE 256
|
||||
|
||||
#define CTL_BACKSPACE ('\b')
|
||||
#define DEL 255
|
||||
#define DEL7 127
|
||||
#define CREAD_HIST_CHAR ('!')
|
||||
|
||||
#define HIST_MAX 10
|
||||
|
||||
#define putnstr(str,n) do { \
|
||||
printf ("%.*s", n, str); \
|
||||
} while (0)
|
||||
|
||||
#define getcmd_putch(ch) putchar(ch)
|
||||
#define getcmd_cbeep() getcmd_putch('\a')
|
||||
#define ANSI_CLEAR_SCREEN "\e[2J\e[;H"
|
||||
|
||||
#define BEGINNING_OF_LINE() { \
|
||||
while (num) { \
|
||||
getcmd_putch(CTL_BACKSPACE); \
|
||||
num--; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define ERASE_TO_EOL() { \
|
||||
if (num < eol_num) { \
|
||||
int t; \
|
||||
for (t = num; t < eol_num; t++) \
|
||||
getcmd_putch(' '); \
|
||||
while (t-- > num) \
|
||||
getcmd_putch(CTL_BACKSPACE); \
|
||||
eol_num = num; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define REFRESH_TO_EOL() { \
|
||||
if (num < eol_num) { \
|
||||
wlen = eol_num - num; \
|
||||
putnstr(buf + num, (int)wlen); \
|
||||
num = eol_num; \
|
||||
} \
|
||||
}
|
||||
|
||||
int readline(char *buf, int len);
|
||||
void hist_init(void);
|
||||
|
||||
#endif /* READLINE_H_ */
|
59
litex/soc/software/bios/readline_simple.c
Normal file
59
litex/soc/software/bios/readline_simple.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
// This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq <sb@m-labs.hk>
|
||||
// This file is Copyright (c) 2014-2019 Florent Kermarrec <florent@enjoy-digital.fr>
|
||||
|
||||
// SPDX-License-Identifier: BSD-Source-Code
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include <console.h>
|
||||
#include <uart.h>
|
||||
|
||||
#include "readline.h"
|
||||
|
||||
int readline(char *s, int size)
|
||||
{
|
||||
static char skip = 0;
|
||||
char c[2];
|
||||
int ptr;
|
||||
|
||||
c[1] = 0;
|
||||
ptr = 0;
|
||||
while(1) {
|
||||
c[0] = readchar();
|
||||
if (c[0] == skip)
|
||||
continue;
|
||||
skip = 0;
|
||||
switch(c[0]) {
|
||||
case 0x7f:
|
||||
case 0x08:
|
||||
if(ptr > 0) {
|
||||
ptr--;
|
||||
putsnonl("\x08 \x08");
|
||||
}
|
||||
break;
|
||||
case 0x07:
|
||||
break;
|
||||
case '\r':
|
||||
skip = '\n';
|
||||
s[ptr] = 0x00;
|
||||
putsnonl("\n");
|
||||
return 0;
|
||||
case '\n':
|
||||
skip = '\r';
|
||||
s[ptr] = 0x00;
|
||||
putsnonl("\n");
|
||||
return 0;
|
||||
default:
|
||||
putsnonl(c);
|
||||
s[ptr] = c[0];
|
||||
ptr++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in a new issue