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:
Franck Jullien 2020-04-28 23:03:18 +02:00
parent e764eabda1
commit bc5a1986e2
5 changed files with 500 additions and 49 deletions

View file

@ -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)

View file

@ -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");
#if !defined(TERM_MINI) && !defined(TERM_NO_HIST)
hist_init();
#endif
printf("\n%s", PROMPT);
while(1) {
putsnonl("\e[92;1mlitex\e[0m> ");
readstr(buffer, 64);
readline(buffer, CMD_LINE_BUFFER_SIZE);
if (buffer[0] != 0) {
printf("\n");
do_command(buffer);
}
printf("\n%s", PROMPT);
}
return 0;
}

View 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;
}

View 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_ */

View 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;
}