From e764eabda1aaeaa9d7ccb63ab276e23696d43339 Mon Sep 17 00:00:00 2001 From: Franck Jullien Date: Mon, 27 Apr 2020 21:52:36 +0200 Subject: [PATCH 1/5] builder: add a parameter to pass options to BIOS Makefile --- litex/soc/integration/builder.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/litex/soc/integration/builder.py b/litex/soc/integration/builder.py index 745eb75e9..4fd1b2330 100644 --- a/litex/soc/integration/builder.py +++ b/litex/soc/integration/builder.py @@ -49,7 +49,8 @@ class Builder: csr_json = None, csr_csv = None, csr_svd = None, - memory_x = None): + memory_x = None, + bios_options = None): self.soc = soc # From Python doc: makedirs() will become confused if the path @@ -66,6 +67,7 @@ class Builder: self.csr_json = csr_json self.csr_svd = csr_svd self.memory_x = memory_x + self.bios_options = bios_options self.software_packages = [] for name in soc_software_packages: @@ -110,6 +112,10 @@ class Builder: for name, src_dir in self.software_packages: define(name.upper() + "_DIRECTORY", src_dir) + if self.bios_options is not None: + for option in self.bios_options: + define(option, "1") + write_to_file( os.path.join(self.generated_dir, "variables.mak"), "".join(variables_contents)) From bc5a1986e237931554f7362e3bde44ba56fed5a7 Mon Sep 17 00:00:00 2001 From: Franck Jullien Date: Tue, 28 Apr 2020 23:03:18 +0200 Subject: [PATCH 2/5] 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. --- litex/soc/software/bios/Makefile | 15 +- litex/soc/software/bios/main.c | 61 +--- litex/soc/software/bios/readline.c | 331 ++++++++++++++++++++++ litex/soc/software/bios/readline.h | 83 ++++++ litex/soc/software/bios/readline_simple.c | 59 ++++ 5 files changed, 500 insertions(+), 49 deletions(-) create mode 100644 litex/soc/software/bios/readline.c create mode 100644 litex/soc/software/bios/readline.h create mode 100644 litex/soc/software/bios/readline_simple.c diff --git a/litex/soc/software/bios/Makefile b/litex/soc/software/bios/Makefile index cc3b973aa..5ede7cd71 100755 --- a/litex/soc/software/bios/Makefile +++ b/litex/soc/software/bios/Makefile @@ -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 diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index b6501edbb..368031f6a 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -10,6 +10,7 @@ // This file is Copyright (c) 2018 Jean-François Nguyen // This file is Copyright (c) 2018 Sergiusz Bazanski // This file is Copyright (c) 2016 Tim 'mithro' Ansell +// This file is Copyright (c) 2020 Franck Jullien // 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; } diff --git a/litex/soc/software/bios/readline.c b/litex/soc/software/bios/readline.c new file mode 100644 index 000000000..998ebc0ef --- /dev/null +++ b/litex/soc/software/bios/readline.c @@ -0,0 +1,331 @@ +// This file is Copyright (c) 2020 Franck Jullien +// +// Largely inspired/copied from U-boot and Barebox projects wich are: +// Wolfgang Denk, DENX Software Engineering, +// Sascha Hauer, Pengutronix, +// cmdline-editing related codes from vivi +// Author: Janghoon Lyu + +// SPDX-License-Identifier: BSD-Source-Code + +#include +#include +#include +#include + +#include +#include + +#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; +} diff --git a/litex/soc/software/bios/readline.h b/litex/soc/software/bios/readline.h new file mode 100644 index 000000000..f1284c5d1 --- /dev/null +++ b/litex/soc/software/bios/readline.h @@ -0,0 +1,83 @@ +#ifndef __READLINE_H__ +#define __READLINE_H__ + +#include +#include + +#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_ */ diff --git a/litex/soc/software/bios/readline_simple.c b/litex/soc/software/bios/readline_simple.c new file mode 100644 index 000000000..bcf062138 --- /dev/null +++ b/litex/soc/software/bios/readline_simple.c @@ -0,0 +1,59 @@ +// This file is Copyright (c) 2013-2014 Sebastien Bourdeauducq +// This file is Copyright (c) 2014-2019 Florent Kermarrec + +// SPDX-License-Identifier: BSD-Source-Code + +#include +#include +#include +#include + +#include +#include + +#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; +} + From 86cab3d3627636d71889be327f4f893207d64226 Mon Sep 17 00:00:00 2001 From: Franck Jullien Date: Tue, 28 Apr 2020 23:15:04 +0200 Subject: [PATCH 3/5] bios: move helper functions to their own file --- litex/soc/software/bios/Makefile | 8 +++- litex/soc/software/bios/helpers.c | 76 +++++++++++++++++++++++++++++++ litex/soc/software/bios/helpers.h | 7 +++ litex/soc/software/bios/main.c | 66 +-------------------------- 4 files changed, 91 insertions(+), 66 deletions(-) create mode 100644 litex/soc/software/bios/helpers.c create mode 100644 litex/soc/software/bios/helpers.h diff --git a/litex/soc/software/bios/Makefile b/litex/soc/software/bios/Makefile index 5ede7cd71..d48ab817d 100755 --- a/litex/soc/software/bios/Makefile +++ b/litex/soc/software/bios/Makefile @@ -10,7 +10,13 @@ ifdef TFTP_SERVER_PORT CFLAGS += -DTFTP_SERVER_PORT=$(TFTP_SERVER_PORT) endif -OBJECTS=isr.o sdram.o sdcard.o main.o boot-helper.o boot.o +OBJECTS = isr.o \ + sdram.o \ + sdcard.o \ + main.o \ + boot-helper.o \ + boot.o \ + helpers.o ifdef TERM_NO_HIST CFLAGS += -DTERM_NO_HIST diff --git a/litex/soc/software/bios/helpers.c b/litex/soc/software/bios/helpers.c new file mode 100644 index 000000000..21eb6e1fc --- /dev/null +++ b/litex/soc/software/bios/helpers.c @@ -0,0 +1,76 @@ +// This file is Copyright (c) 2017 Florent Kermarrec + +// SPDX-License-Identifier: BSD-Source-Code + +#include +#include +#include +#include + +#include "readline.h" +#include "helpers.h" + +extern unsigned int _ftext, _edata; + +#define NUMBER_OF_BYTES_ON_A_LINE 16 +void dump_bytes(unsigned int *ptr, int count, unsigned long addr) +{ + char *data = (char *)ptr; + int line_bytes = 0, i = 0; + + putsnonl("Memory dump:"); + while (count > 0) { + line_bytes = + (count > NUMBER_OF_BYTES_ON_A_LINE)? + NUMBER_OF_BYTES_ON_A_LINE : count; + + printf("\n0x%08x ", addr); + for (i = 0; i < line_bytes; i++) + printf("%02x ", *(unsigned char *)(data+i)); + + for (; i < NUMBER_OF_BYTES_ON_A_LINE; i++) + printf(" "); + + printf(" "); + + for (i = 0; i 0x7e)) + printf("."); + else + printf("%c", *(data+i)); + } + + for (; i < NUMBER_OF_BYTES_ON_A_LINE; i++) + printf(" "); + + data += (char)line_bytes; + count -= line_bytes; + addr += line_bytes; + } + printf("\n"); +} + +void crcbios(void) +{ + unsigned long offset_bios; + unsigned long length; + unsigned int expected_crc; + unsigned int actual_crc; + + /* + * _edata is located right after the end of the flat + * binary image. The CRC tool writes the 32-bit CRC here. + * We also use the address of _edata to know the length + * of our code. + */ + offset_bios = (unsigned long)&_ftext; + expected_crc = _edata; + length = (unsigned long)&_edata - offset_bios; + actual_crc = crc32((unsigned char *)offset_bios, length); + if (expected_crc == actual_crc) + printf(" BIOS CRC passed (%08x)\n", actual_crc); + else { + printf(" BIOS CRC failed (expected %08x, got %08x)\n", expected_crc, actual_crc); + printf(" The system will continue, but expect problems.\n"); + } +} diff --git a/litex/soc/software/bios/helpers.h b/litex/soc/software/bios/helpers.h new file mode 100644 index 000000000..227dcd174 --- /dev/null +++ b/litex/soc/software/bios/helpers.h @@ -0,0 +1,7 @@ +#ifndef __HELPERS_H__ +#define __HELPERS_H__ + +void dump_bytes(unsigned int *ptr, int count, unsigned long addr); +void crcbios(void); + +#endif diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 368031f6a..7f9187a31 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -44,47 +44,10 @@ #include "sdcard.h" #include "boot.h" #include "readline.h" +#include "helpers.h" /* General address space functions */ -#define NUMBER_OF_BYTES_ON_A_LINE 16 -static void dump_bytes(unsigned int *ptr, int count, unsigned long addr) -{ - char *data = (char *)ptr; - int line_bytes = 0, i = 0; - - putsnonl("Memory dump:"); - while(count > 0){ - line_bytes = - (count > NUMBER_OF_BYTES_ON_A_LINE)? - NUMBER_OF_BYTES_ON_A_LINE : count; - - printf("\n0x%08x ", addr); - for(i=0;i 0x7e)) - printf("."); - else - printf("%c", *(data+i)); - } - - for(;i Date: Wed, 29 Apr 2020 21:33:51 +0200 Subject: [PATCH 4/5] bios: switch command handler to a modular format Command are now described with a structure. A pointer to this structure is placed in a dedicated linker section. --- litex/soc/software/bios/Makefile | 13 +- litex/soc/software/bios/command.h | 47 ++ litex/soc/software/bios/commands/cmd_bios.c | 125 +++++ litex/soc/software/bios/commands/cmd_boot.c | 59 +++ litex/soc/software/bios/commands/cmd_dram.c | 222 +++++++++ litex/soc/software/bios/commands/cmd_mdio.c | 132 +++++ .../software/bios/commands/cmd_mem_access.c | 137 ++++++ litex/soc/software/bios/commands/cmd_sdcard.c | 85 ++++ .../software/bios/commands/cmd_spi_flash.c | 75 +++ .../soc/software/bios/commands/cmd_usddrphy.c | 128 +++++ litex/soc/software/bios/helpers.c | 52 ++ litex/soc/software/bios/helpers.h | 2 + litex/soc/software/bios/linker.ld | 7 + litex/soc/software/bios/main.c | 451 +----------------- litex/soc/software/bios/sdram.c | 71 +-- litex/soc/software/bios/sdram.h | 8 +- 16 files changed, 1104 insertions(+), 510 deletions(-) create mode 100644 litex/soc/software/bios/command.h create mode 100644 litex/soc/software/bios/commands/cmd_bios.c create mode 100644 litex/soc/software/bios/commands/cmd_boot.c create mode 100644 litex/soc/software/bios/commands/cmd_dram.c create mode 100644 litex/soc/software/bios/commands/cmd_mdio.c create mode 100644 litex/soc/software/bios/commands/cmd_mem_access.c create mode 100644 litex/soc/software/bios/commands/cmd_sdcard.c create mode 100644 litex/soc/software/bios/commands/cmd_spi_flash.c create mode 100644 litex/soc/software/bios/commands/cmd_usddrphy.c diff --git a/litex/soc/software/bios/Makefile b/litex/soc/software/bios/Makefile index d48ab817d..c80e0a130 100755 --- a/litex/soc/software/bios/Makefile +++ b/litex/soc/software/bios/Makefile @@ -16,7 +16,15 @@ OBJECTS = isr.o \ main.o \ boot-helper.o \ boot.o \ - helpers.o + helpers.o \ + cmd_bios.o \ + cmd_boot.o \ + cmd_dram.o \ + cmd_mdio.o \ + cmd_mem_access.o \ + cmd_sdcard.o \ + cmd_spi_flash.o \ + cmd_usddrphy.o ifdef TERM_NO_HIST CFLAGS += -DTERM_NO_HIST @@ -67,6 +75,9 @@ endif %.o: $(BIOS_DIRECTORY)/%.c $(compile) +%.o: $(BIOS_DIRECTORY)/commands/%.c + $(compile) + %.o: $(BIOS_DIRECTORY)/%.S $(assemble) diff --git a/litex/soc/software/bios/command.h b/litex/soc/software/bios/command.h new file mode 100644 index 000000000..247043895 --- /dev/null +++ b/litex/soc/software/bios/command.h @@ -0,0 +1,47 @@ +// This file is Copyright (c) 2020 Franck Jullien + +// SPDX-License-Identifier: BSD-Source-Code + +#ifndef __COMMAND_H__ +#define __COMMAND_H__ + +#define MAX_PARAM 8 + +#define MISC_CMDS 0 +#define SYSTEM_CMDS 1 +#define CACHE_CMDS 2 +#define BOOT_CMDS 3 +#define DRAM_CMDS 4 +#define MDIO_CMDS 5 +#define MEM_CMDS 6 +#define SD_CMDS 7 +#define SPIFLASH_CMDS 8 +#define DDR_CMDS 9 +#define NB_OF_GROUPS 10 + +typedef void (*cmd_handler)(int nb_params, char **params); + +struct command_struct { + void (*func)(int nb_params, char **params); + const char *name; + const char *help; + int group; +}; + +extern struct command_struct *const __bios_cmd_start[]; +extern struct command_struct *const __bios_cmd_end[]; + +#define define_command(cmd_name, handler, help_txt, group_id) \ + struct command_struct s_##cmd_name = { \ + .func = (cmd_handler)handler, \ + .name = #cmd_name, \ + .help = help_txt, \ + .group = group_id, \ + }; \ + const struct command_struct *__bios_cmd_##cmd_name __attribute__((__used__)) \ + __attribute__((__section__(".bios_cmd"))) = &s_##cmd_name + + +struct command_struct *command_dispatcher(char *command, int nb_params, char **params); + +#endif diff --git a/litex/soc/software/bios/commands/cmd_bios.c b/litex/soc/software/bios/commands/cmd_bios.c new file mode 100644 index 000000000..a5e704248 --- /dev/null +++ b/litex/soc/software/bios/commands/cmd_bios.c @@ -0,0 +1,125 @@ +// SPDX-License-Identifier: BSD-Source-Code + +#include +#include + +#include +#include +#include +#include + +#include "../command.h" +#include "../helpers.h" + +/** + * Command "help" + * + * Print a list of available commands with their help text + * + */ +static void help_handler(int nb_params, char **params) +{ + struct command_struct * const *cmd; + int i, not_empty; + + puts("\nLiteX BIOS, available commands:\n"); + + for (i = 0; i < NB_OF_GROUPS; i++) { + not_empty = 0; + for (cmd = __bios_cmd_start; cmd != __bios_cmd_end; cmd++) { + if ((*cmd)->group == i) { + printf("%-16s - %s\n", (*cmd)->name, (*cmd)->help ? (*cmd)->help : "-"); + not_empty = 1; + } + } + if (not_empty) + printf("\n"); + } +} + +define_command(help, help_handler, "Print this help", MISC_CMDS); + +/** + * Command "ident" + * + * Print SoC identyifier if available + * + */ +static void ident_helper(int nb_params, char **params) +{ + char buffer[IDENT_SIZE]; + + get_ident(buffer); + printf("Ident: %s", *buffer ? buffer : "-"); +} + +define_command(ident, ident_helper, "Display identifier", SYSTEM_CMDS); + +/** + * Command "reboot" + * + * Reboot the system + * + */ +#ifdef CSR_CTRL_BASE +static void reboot(int nb_params, char **params) +{ + ctrl_reset_write(1); +} + +define_command(reboot, reboot, "Reset processor", SYSTEM_CMDS); +#endif + +/** + * Command "crc" + * + * Compute CRC32 over an address range + * + */ +static void crc(int nb_params, char **params) +{ + char *c; + unsigned int addr; + unsigned int length; + + if (nb_params < 2) { + printf("crc
"); + return; + } + + addr = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect address"); + return; + } + + length = strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect length"); + return; + } + + printf("CRC32: %08x", crc32((unsigned char *)addr, length)); +} + +define_command(crc, crc, "Compute CRC32 of a part of the address space", MISC_CMDS); + +/** + * Command "flush_cpu_dcache" + * + * Flush CPU data cache + * + */ + +define_command(flush_cpu_dcache, flush_cpu_dcache, "Flush CPU data cache", CACHE_CMDS); + +/** + * Command "flush_l2_cache" + * + * Flush L2 cache + * + */ +#ifdef CONFIG_L2_SIZE +define_command(flush_l2_cache, flush_l2_cache, "Flush L2 cache", CACHE_CMDS); +#endif + diff --git a/litex/soc/software/bios/commands/cmd_boot.c b/litex/soc/software/bios/commands/cmd_boot.c new file mode 100644 index 000000000..c9cb8a11d --- /dev/null +++ b/litex/soc/software/bios/commands/cmd_boot.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: BSD-Source-Code + +#include +#include + +#include + +#include "../command.h" +#include "../helpers.h" +#include "../boot.h" + +/** + * Command "flashboot" + * + * Boot software from flash + * + */ +#ifdef FLASH_BOOT_ADDRESS +define_command(flashboot, flashboot, "Boot from flash", BOOT_CMDS); +#endif + +/** + * Command "romboot" + * + * Boot software from embedded rom + * + */ +#ifdef ROM_BOOT_ADDRESS +define_command(romboot, romboot, "Boot from embedded rom", BOOT_CMDS); +#endif + +/** + * Command "serialboot" + * + * Boot software from serial interface + * + */ +define_command(serialboot, serialboot, "Boot via SFL", BOOT_CMDS); + +/** + * Command "netboot" + * + * Boot software from TFTP server + * + */ +#ifdef CSR_ETHMAC_BASE +define_command(netboot, netboot, "Boot via TFTP", BOOT_CMDS); +#endif + +/** + * Command "spisdcardboot" + * + * Boot software from SDcard + * + */ +#ifdef CSR_SPISDCARD_BASE +define_command(spisdcardboot, spisdcardboot, "Boot from SDCard via SPI hardware bitbang", BOOT_CMDS); +#endif + diff --git a/litex/soc/software/bios/commands/cmd_dram.c b/litex/soc/software/bios/commands/cmd_dram.c new file mode 100644 index 000000000..0d6fa1d46 --- /dev/null +++ b/litex/soc/software/bios/commands/cmd_dram.c @@ -0,0 +1,222 @@ +// SPDX-License-Identifier: BSD-Source-Code + +#include +#include + +#include + +#include "../command.h" +#include "../helpers.h" +#include "../sdram.h" + +/** + * Command "sdrrow" + * + * Precharge/Activate row + * + */ +#ifdef CSR_SDRAM_BASE +static void sdrrow_handler(int nb_params, char **params) +{ + char *c; + unsigned int row; + + if (nb_params < 1) { + sdrrow(0); + printf("Precharged"); + } + + row = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect row"); + return; + } + + sdrrow(row); + printf("Activated row %d", row); +} +define_command(sdrrow, sdrrow_handler, "Precharge/Activate row", DRAM_CMDS); +#endif + +/** + * Command "sdrsw" + * + * Gives SDRAM control to SW + * + */ +#ifdef CSR_SDRAM_BASE +define_command(sdrsw, sdrsw, "Gives SDRAM control to SW", DRAM_CMDS); +#endif + +/** + * Command "sdrhw" + * + * Gives SDRAM control to HW + * + */ +#ifdef CSR_SDRAM_BASE +define_command(sdrhw, sdrhw, "Gives SDRAM control to HW", DRAM_CMDS); +#endif + +/** + * Command "sdrrdbuf" + * + * Dump SDRAM read buffer + * + */ +#ifdef CSR_SDRAM_BASE +static void sdrrdbuf_handler(int nb_params, char **params) +{ + sdrrdbuf(-1); +} + +define_command(sdrrdbuf, sdrrdbuf_handler, "Dump SDRAM read buffer", DRAM_CMDS); +#endif + +/** + * Command "sdrrd" + * + * Read SDRAM data + * + */ +#ifdef CSR_SDRAM_BASE +static void sdrrd_handler(int nb_params, char **params) +{ + unsigned int addr; + int dq; + char *c; + + if (nb_params < 1) { + printf("sdrrd
"); + return; + } + + addr = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect address"); + return; + } + + if (nb_params < 2) + dq = -1; + else { + dq = strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect DQ"); + return; + } + } + + sdrrd(addr, dq); +} + +define_command(sdrrd, sdrrd_handler, "Read SDRAM data", DRAM_CMDS); +#endif + +/** + * Command "sdrrderr" + * + * Print SDRAM read errors + * + */ +#ifdef CSR_SDRAM_BASE +static void sdrrderr_handler(int nb_params, char **params) +{ + int count; + char *c; + + if (nb_params < 1) { + printf("sdrrderr "); + return; + } + + count = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect count"); + return; + } + + sdrrderr(count); +} + +define_command(sdrrderr, sdrrderr_handler, "Print SDRAM read errors", DRAM_CMDS); +#endif + +/** + * Command "sdrwr" + * + * Write SDRAM test data + * + */ +#ifdef CSR_SDRAM_BASE +static void sdrwr_handler(int nb_params, char **params) +{ + unsigned int addr; + char *c; + + if (nb_params < 1) { + printf("sdrwr
"); + return; + } + + addr = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect address"); + return; + } + + sdrwr(addr); +} + +define_command(sdrwr, sdrwr_handler, "Write SDRAM test data", DRAM_CMDS); +#endif + +/** + * Command "sdrinit" + * + * Start SDRAM initialisation + * + */ +#if defined(CSR_SDRAM_BASE) && defined(CSR_DDRPHY_BASE) +define_command(sdrinit, sdrinit, "Start SDRAM initialisation", DRAM_CMDS); +#endif + +/** + * Command "sdrwlon" + * + * Write leveling ON + * + */ +#if defined(CSR_DDRPHY_BASE) && defined(SDRAM_PHY_WRITE_LEVELING_CAPABLE) && defined(CSR_SDRAM_BASE) +define_command(sdrwlon, sdrwlon, "Enable write leveling", DRAM_CMDS); +#endif + +/** + * Command "sdrwloff" + * + * Write leveling OFF + * + */ +#if defined(CSR_DDRPHY_BASE) && defined(SDRAM_PHY_WRITE_LEVELING_CAPABLE) && defined(CSR_SDRAM_BASE) +define_command(sdrwloff, sdrwloff, "Disable write leveling", DRAM_CMDS); +#endif + +/** + * Command "sdrlevel" + * + * Perform read/write leveling + * + */ +#if defined(CSR_DDRPHY_BASE) && defined(CSR_SDRAM_BASE) +define_command(sdrlevel, sdrlevel, "Perform read/write leveling", DRAM_CMDS); +#endif + +/** + * Command "memtest" + * + * Run a memory test + * + */ +#ifdef CSR_SDRAM_BASE +define_command(memtest, memtest, "Run a memory test", DRAM_CMDS); +#endif diff --git a/litex/soc/software/bios/commands/cmd_mdio.c b/litex/soc/software/bios/commands/cmd_mdio.c new file mode 100644 index 000000000..9d28c5347 --- /dev/null +++ b/litex/soc/software/bios/commands/cmd_mdio.c @@ -0,0 +1,132 @@ +// SPDX-License-Identifier: BSD-Source-Code + +#include +#include + +#include + +#include "../command.h" +#include "../helpers.h" + +/** + * Command "mdiow" + * + * Write MDIO register + * + */ +#ifdef CSR_ETHPHY_MDIO_W_ADDR +static void mdiow(int nb_params, char **params) +{ + char *c; + unsigned int phyadr2; + unsigned int reg2; + unsigned int val2; + + if (nb_params < 3) { + printf("mdiow "); + return; + } + + phyadr2 = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect phyadr"); + return; + } + + reg2 = strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect reg"); + return; + } + + val2 = strtoul(params[2], &c, 0); + if (*c != 0) { + printf("Incorrect val"); + return; + } + + mdio_write(phyadr2, reg2, val2); +} + +define_command(mdiow, mdiow, "Write MDIO register", MDIO_CMDS); +#endif + +/** + * Command "mdior" + * + * Read MDIO register + * + */ +#ifdef CSR_ETHPHY_MDIO_W_ADDR +static void mdior(int nb_params, char **params) +{ + char *c; + unsigned int phyadr2; + unsigned int reg2; + unsigned int val; + + if (nb_params < 2) { + printf("mdior "); + return; + } + + phyadr2 = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect phyadr"); + return; + } + + reg2 = strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect reg"); + return; + } + + val = mdio_read(phyadr2, reg2); + printf("Reg %d: 0x%04x", reg2, val); +} + +define_command(mdior, mdior, "Read MDIO register", MDIO_CMDS); +#endif + +/** + * Command "mdiod" + * + * Dump MDIO registers + * + */ +#ifdef CSR_ETHPHY_MDIO_W_ADDR +static void mdiod(int nb_params, char **params) +{ + char *c; + unsigned int phyadr; + unsigned int count; + unsigned int val; + int i; + + if (nb_params < 2) { + printf("mdiod "); + return; + } + + phyadr = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect phyadr"); + return; + } + + count = strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect count"); + return; + } + + printf("MDIO dump @0x%x:\n", phyadr); + for (i = 0; i < count; i++) { + val = mdio_read(phyadr, i); + printf("reg %d: 0x%04x", i, val); + } +} + +define_command(mdiod, mdiod, "Dump MDIO registers", MDIO_CMDS); +#endif diff --git a/litex/soc/software/bios/commands/cmd_mem_access.c b/litex/soc/software/bios/commands/cmd_mem_access.c new file mode 100644 index 000000000..8c63d4c44 --- /dev/null +++ b/litex/soc/software/bios/commands/cmd_mem_access.c @@ -0,0 +1,137 @@ +// SPDX-License-Identifier: BSD-Source-Code + +#include +#include + +#include "../command.h" +#include "../helpers.h" + +/** + * Command "mr" + * + * Memory read + * + */ +static void mr(int nb_params, char **params) +{ + char *c; + unsigned int *addr; + unsigned int length; + + if (nb_params < 1) { + printf("mr
[length]"); + return; + } + addr = (unsigned int *)strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect address"); + return; + } + if (nb_params == 1) { + length = 4; + } else { + length = strtoul(params[1], &c, 0); + if(*c != 0) { + printf("\nIncorrect length"); + return; + } + } + + dump_bytes(addr, length, (unsigned long)addr); +} + +define_command(mr, mr, "Read address space", MEM_CMDS); + +/** + * Command "mw" + * + * Memory write + * + */ +static void mw(int nb_params, char **params) +{ + char *c; + unsigned int *addr; + unsigned int value; + unsigned int count; + unsigned int i; + + if (nb_params < 2) { + printf("mw
[count]"); + return; + } + + addr = (unsigned int *)strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect address"); + return; + } + + value = strtoul(params[1], &c, 0); + if(*c != 0) { + printf("Incorrect value"); + return; + } + + if (nb_params == 2) { + count = 1; + } else { + count = strtoul(params[2], &c, 0); + if(*c != 0) { + printf("Incorrect count"); + return; + } + } + + for (i = 0; i < count; i++) + *addr++ = value; +} + +define_command(mw, mw, "Write address space", MEM_CMDS); + +/** + * Command "mc" + * + * Memory copy + * + */ +static void mc(int nb_params, char **params) +{ + char *c; + unsigned int *dstaddr; + unsigned int *srcaddr; + unsigned int count; + unsigned int i; + + if (nb_params < 2) { + printf("mc [count]"); + return; + } + + dstaddr = (unsigned int *)strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect destination address"); + return; + } + + srcaddr = (unsigned int *)strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect source address"); + return; + } + + if (nb_params == 2) { + count = 1; + } else { + count = strtoul(params[2], &c, 0); + if (*c != 0) { + printf("Incorrect count"); + return; + } + } + + for (i = 0; i < count; i++) + *dstaddr++ = *srcaddr++; +} + +define_command(mc, mc, "Copy address space", MEM_CMDS); diff --git a/litex/soc/software/bios/commands/cmd_sdcard.c b/litex/soc/software/bios/commands/cmd_sdcard.c new file mode 100644 index 000000000..96f9fe64c --- /dev/null +++ b/litex/soc/software/bios/commands/cmd_sdcard.c @@ -0,0 +1,85 @@ +// SPDX-License-Identifier: BSD-Source-Code + +#include +#include + +#include + +#include "../command.h" +#include "../helpers.h" +#include "../sdcard.h" + +/** + * Command "sdclk" + * + * Configure SDcard clock frequency + * + */ +#ifdef CSR_SDCORE_BASE +static void sdclk(int nb_params, char **params) +{ + unsigned int frequ; + char *c; + + if (nb_params < 1) { + printf("sdclk "); + return; + } + + frequ = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect frequency"); + return; + } + + sdclk_set_clk(frequ); +} + +struct command_struct cmd_sdclk = +{ + .func = sdclk, + .name = "sdclk", + .help = "SDCard set clk frequency (Mhz)", +}; + +define_command(sdclk, sdclk, "SDCard set clk frequency (Mhz)", SD_CMDS); +#endif + +/** + * Command "sdinit" + * + * Initialize SDcard + * + */ +#ifdef CSR_SDCORE_BASE +define_command(sdinit, sdinit, "SDCard initialization", SD_CMDS); +#endif + +/** + * Command "sdtest" + * + * Perform SDcard access tests + * + */ +#ifdef CSR_SDCORE_BASE +static void sdtest(int nb_params, char **params) +{ + unsigned int loops; + char *c; + + if (nb_params < 1) { + printf("sdtest "); + return; + } + + loops = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect number of loops"); + return; + } + + sdcard_test(loops); +} + +define_command(sdtest, sdtest, "SDCard test", SD_CMDS); +#endif diff --git a/litex/soc/software/bios/commands/cmd_spi_flash.c b/litex/soc/software/bios/commands/cmd_spi_flash.c new file mode 100644 index 000000000..e607a89df --- /dev/null +++ b/litex/soc/software/bios/commands/cmd_spi_flash.c @@ -0,0 +1,75 @@ +// SPDX-License-Identifier: BSD-Source-Code + +#include +#include + +#include + +#include "../command.h" +#include "../helpers.h" + +/** + * Command "fw" + * + * Write data from a memory buffer to SPI flash + * + */ +#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE) +static void fw(int nb_params, char **params) +{ + char *c; + unsigned int addr; + unsigned int value; + unsigned int count; + unsigned int i; + + if (nb_params < 2) { + printf("fw [count]"); + return; + } + + addr = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect offset"); + return; + } + + value = strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect value"); + return; + } + + if (nb_params == 2) { + count = 1; + } else { + count = strtoul(count, &c, 0); + if (*c != 0) { + printf("Incorrect count"); + return; + } + } + + for (i = 0; i < count; i++) + write_to_flash(addr + i * 4, (unsigned char *)&value, 4); +} + +define_command(fw, fw, "Write to flash", SPIFLASH_CMDS); +#endif + +/** + * Command "fe" + * + * Flash erase + * + */ +#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE) +static void fe(int nb_params, char **params) +{ + erase_flash(); + printf("Flash erased\n"); +} + +define_command(fe, fe, "Erase whole flash", SPIFLASH_CMDS); +#endif + diff --git a/litex/soc/software/bios/commands/cmd_usddrphy.c b/litex/soc/software/bios/commands/cmd_usddrphy.c new file mode 100644 index 000000000..69c62fad0 --- /dev/null +++ b/litex/soc/software/bios/commands/cmd_usddrphy.c @@ -0,0 +1,128 @@ +// SPDX-License-Identifier: BSD-Source-Code + +#include +#include + +#include + +#include "../command.h" +#include "../helpers.h" +#include "../sdram.h" + +/** + * Command "sdram_cdly" + * + * Set SDRAM clk/cmd delay + * + */ +#ifdef USDDRPHY_DEBUG +static void sdram_cdly(int nb_params, char **params) +{ + unsigned int delay; + char *c; + + if (nb_params < 1) { + printf("sdram_cdly "); + return; + } + + delay = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect delay"); + return; + } + + ddrphy_cdly(delay); +} + +define_command(sdram_cdly, sdram_cdly, "Set SDRAM clk/cmd delay", DDR_CMDS); +#endif + +/** + * Command "sdram_cdly" + * + * Run SDRAM calibration + * + */ +#ifdef USDDRPHY_DEBUG +define_command(sdram_cal, sdram_cal, "Run SDRAM calibration", DDR_CMDS); +#endif + +/** + * Command "sdram_mpr" + * + * Read SDRAM MPR + * + */ +#ifdef USDDRPHY_DEBUG +define_command(sdram_mpr, sdram_mpr, "Read SDRAM MPR", DDR_CMDS); +#endif + + +/** + * Command "sdram_mrwr" + * + * Write SDRAM mode registers + * + */ +#ifdef USDDRPHY_DEBUG +static void sdram_mrwr(int nb_params, char **params) +{ + unsigned int reg; + unsigned int value; + char *c; + + if (nb_params < 2) { + printf("sdram_mrwr "); + return; + } + + reg = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect register value"); + return; + } + + value = strtoul(params[1], &c, 0); + if (*c != 0) { + printf("Incorrect value"); + return; + } + + sdrsw(); + printf("Writing 0x%04x to SDRAM mode register %d\n", value, reg); + sdrmrwr(reg, value); + sdrhw(); +} + +define_command(sdram_mrwr, sdram_mrwr, "Write SDRAM mode registers", DDR_CMDS); +#endif + +/** + * Command "sdram_cdly_scan" + * + * Enable/disable cdly scan + * + */ +#ifdef USDDRPHY_DEBUG +static void sdram_cdly_scan(int nb_params, char **params) +{ + unsigned int value; + char *c; + + if (nb_params < 1) { + printf("sdram_cdly_scan "); + return; + } + + value = strtoul(params[0], &c, 0); + if (*c != 0) { + printf("Incorrect value"); + return; + } + + sdr_cdly_scan(value); +} + +define_command(sdram_cdly_scan, sdram_cdly_scan, "Enable/disable cdly scan", DDR_CMDS); +#endif diff --git a/litex/soc/software/bios/helpers.c b/litex/soc/software/bios/helpers.c index 21eb6e1fc..535dd61b2 100644 --- a/litex/soc/software/bios/helpers.c +++ b/litex/soc/software/bios/helpers.c @@ -9,6 +9,7 @@ #include "readline.h" #include "helpers.h" +#include "command.h" extern unsigned int _ftext, _edata; @@ -74,3 +75,54 @@ void crcbios(void) printf(" The system will continue, but expect problems.\n"); } } + +int get_param(char *buf, char **cmd, char **params) +{ + int nb_param = 0; + int i; + + for (i = 0; i < MAX_PARAM; i++) + params[i] = NULL; + + *cmd = buf; + + while ((*buf != ' ') && (*buf !=0)) + buf++; + + if (*buf == 0) + return nb_param; + + *buf++ = 0; + + while (1) { + while ((*buf == ' ') && (*buf !=0)) + buf++; + + + if (*buf == 0) + return nb_param; + + params[nb_param++] = buf; + + while ((*buf != ' ') && (*buf !=0)) + buf++; + + if (*buf == 0) + return nb_param; + *buf++ = 0; + } +} + +struct command_struct *command_dispatcher(char *command, int nb_params, char **params) +{ + struct command_struct * const *cmd; + + for (cmd = __bios_cmd_start; cmd != __bios_cmd_end; cmd++) { + if (!strcmp(command, (*cmd)->name)) { + (*cmd)->func(nb_params, params); + return (*cmd); + } + } + + return NULL; +} diff --git a/litex/soc/software/bios/helpers.h b/litex/soc/software/bios/helpers.h index 227dcd174..6f1f2deeb 100644 --- a/litex/soc/software/bios/helpers.h +++ b/litex/soc/software/bios/helpers.h @@ -3,5 +3,7 @@ void dump_bytes(unsigned int *ptr, int count, unsigned long addr); void crcbios(void); +int get_param(char *buf, char **cmd, char **params); +struct command_struct *command_dispatcher(char *command, int nb_params, char **params); #endif diff --git a/litex/soc/software/bios/linker.ld b/litex/soc/software/bios/linker.ld index 7760e551d..e0211a6b4 100644 --- a/litex/soc/software/bios/linker.ld +++ b/litex/soc/software/bios/linker.ld @@ -26,6 +26,13 @@ SECTIONS _erodata = .; } > rom + .commands : + { + PROVIDE_HIDDEN (__bios_cmd_start = .); + KEEP(*(.bios_cmd)) + PROVIDE_HIDDEN (__bios_cmd_end = .); + } > rom + .data : { . = ALIGN(8); diff --git a/litex/soc/software/bios/main.c b/litex/soc/software/bios/main.c index 7f9187a31..e985dd5a3 100644 --- a/litex/soc/software/bios/main.c +++ b/litex/soc/software/bios/main.c @@ -45,446 +45,7 @@ #include "boot.h" #include "readline.h" #include "helpers.h" - -/* General address space functions */ - -static void mr(char *startaddr, char *len) -{ - char *c; - unsigned int *addr; - unsigned int length; - - if(*startaddr == 0) { - printf("mr
[length]\n"); - return; - } - addr = (unsigned *)strtoul(startaddr, &c, 0); - if(*c != 0) { - printf("incorrect address\n"); - return; - } - if(*len == 0) { - length = 4; - } else { - length = strtoul(len, &c, 0); - if(*c != 0) { - printf("incorrect length\n"); - return; - } - } - - dump_bytes(addr, length, (unsigned long)addr); -} - -static void mw(char *addr, char *value, char *count) -{ - char *c; - unsigned int *addr2; - unsigned int value2; - unsigned int count2; - unsigned int i; - - if((*addr == 0) || (*value == 0)) { - printf("mw
[count]\n"); - return; - } - addr2 = (unsigned int *)strtoul(addr, &c, 0); - if(*c != 0) { - printf("incorrect address\n"); - return; - } - value2 = strtoul(value, &c, 0); - if(*c != 0) { - printf("incorrect value\n"); - return; - } - if(*count == 0) { - count2 = 1; - } else { - count2 = strtoul(count, &c, 0); - if(*c != 0) { - printf("incorrect count\n"); - return; - } - } - for (i=0;i [count]\n"); - return; - } - dstaddr2 = (unsigned int *)strtoul(dstaddr, &c, 0); - if(*c != 0) { - printf("incorrect destination address\n"); - return; - } - srcaddr2 = (unsigned int *)strtoul(srcaddr, &c, 0); - if(*c != 0) { - printf("incorrect source address\n"); - return; - } - if(*count == 0) { - count2 = 1; - } else { - count2 = strtoul(count, &c, 0); - if(*c != 0) { - printf("incorrect count\n"); - return; - } - } - for (i=0;i [count]\n"); - return; - } - addr2 = strtoul(addr, &c, 0); - if(*c != 0) { - printf("incorrect offset\n"); - return; - } - value2 = strtoul(value, &c, 0); - if(*c != 0) { - printf("incorrect value\n"); - return; - } - if(*count == 0) { - count2 = 1; - } else { - count2 = strtoul(count, &c, 0); - if(*c != 0) { - printf("incorrect count\n"); - return; - } - } - for (i=0;i \n"); - return; - } - phyadr2 = strtoul(phyadr, &c, 0); - if(*c != 0) { - printf("incorrect phyadr\n"); - return; - } - reg2 = strtoul(reg, &c, 0); - if(*c != 0) { - printf("incorrect reg\n"); - return; - } - val2 = strtoul(val, &c, 0); - if(*c != 0) { - printf("incorrect val\n"); - return; - } - mdio_write(phyadr2, reg2, val2); -} - -static void mdior(char *phyadr, char *reg) -{ - char *c; - unsigned int phyadr2; - unsigned int reg2; - unsigned int val; - - if((*phyadr == 0) || (*reg == 0)) { - printf("mdior \n"); - return; - } - phyadr2 = strtoul(phyadr, &c, 0); - if(*c != 0) { - printf("incorrect phyadr\n"); - return; - } - reg2 = strtoul(reg, &c, 0); - if(*c != 0) { - printf("incorrect reg\n"); - return; - } - val = mdio_read(phyadr2, reg2); - printf("reg %d: 0x%04x\n", reg2, val); -} - -static void mdiod(char *phyadr, char *count) -{ - char *c; - unsigned int phyadr2; - unsigned int count2; - unsigned int val; - int i; - - if((*phyadr == 0) || (*count == 0)) { - printf("mdiod \n"); - return; - } - phyadr2 = strtoul(phyadr, &c, 0); - if(*c != 0) { - printf("incorrect phyadr\n"); - return; - } - count2 = strtoul(count, &c, 0); - if(*c != 0) { - printf("incorrect count\n"); - return; - } - printf("MDIO dump @0x%x:\n", phyadr2); - for (i=0; i \n"); - return; - } - addr = (char *)strtoul(startaddr, &c, 0); - if(*c != 0) { - printf("incorrect address\n"); - return; - } - length = strtoul(len, &c, 0); - if(*c != 0) { - printf("incorrect length\n"); - return; - } - - printf("CRC32: %08x\n", crc32((unsigned char *)addr, length)); -} - -static void ident(void) -{ - char buffer[IDENT_SIZE]; - - get_ident(buffer); - printf("Ident: %s\n", buffer); -} - -/* Init + command line */ - -static void help(void) -{ - puts("LiteX BIOS, available commands:"); - puts("mr - read address space"); - puts("mw - write address space"); - puts("mc - copy address space"); -#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE) - puts("fe - erase whole flash"); - puts("fw - write to flash"); - -#endif -#ifdef CSR_ETHPHY_MDIO_W_ADDR - puts("mdiow - write MDIO register"); - puts("mdior - read MDIO register"); - puts("mdiod - dump MDIO registers"); -#endif - puts(""); - puts("crc - compute CRC32 of a part of the address space"); - puts("ident - display identifier"); - puts(""); - puts("flush_cpu_dcache - flush CPU data cache"); -#ifdef CONFIG_L2_SIZE - puts("flush_l2_cache - flush L2 cache"); -#endif - puts(""); -#ifdef CSR_CTRL_BASE - puts("reboot - reset processor"); -#endif -#ifdef CSR_ETHMAC_BASE - puts("netboot - boot via TFTP"); -#endif - puts("serialboot - boot via SFL"); -#ifdef FLASH_BOOT_ADDRESS - puts("flashboot - boot from flash"); -#endif -#ifdef ROM_BOOT_ADDRESS - puts("romboot - boot from embedded rom"); -#endif - puts(""); -#ifdef CSR_SDRAM_BASE - puts("memtest - run a memory test"); -#endif - puts(""); -#ifdef CSR_SDCORE_BASE - puts("sdclk - SDCard set clk frequency (Mhz)"); - puts("sdinit - SDCard initialization"); - puts("sdtest - SDCard test"); -#endif -#ifdef USDDRPHY_DEBUG - puts(""); - puts("sdram_cdly value - Set SDRAM clk/cmd delay"); - puts("sdram_cal - run SDRAM calibration"); - puts("sdram_mpr - read SDRAM MPR"); - puts("sdram_mrwr reg value - write SDRAM mode registers"); - puts("sdram_cdly_scan enabled - enable/disable cdly scan"); -#endif -#ifdef CSR_SPISDCARD_BASE - puts("spisdcardboot - boot from SDCard via SPI hardware bitbang"); -#endif -} - -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; -} - -#ifdef CSR_CTRL_BASE -static void reboot(void) -{ - ctrl_reset_write(1); -} -#endif - -static void do_command(char *c) -{ - char *token; - - token = get_token(&c); - - if(strcmp(token, "mr") == 0) mr(get_token(&c), get_token(&c)); - else if(strcmp(token, "mw") == 0) mw(get_token(&c), get_token(&c), get_token(&c)); - else if(strcmp(token, "mc") == 0) mc(get_token(&c), get_token(&c), get_token(&c)); -#if (defined CSR_SPIFLASH_BASE && defined SPIFLASH_PAGE_SIZE) - else if(strcmp(token, "fw") == 0) fw(get_token(&c), get_token(&c), get_token(&c)); - else if(strcmp(token, "fe") == 0) fe(); -#endif -#ifdef CSR_ETHPHY_MDIO_W_ADDR - else if(strcmp(token, "mdiow") == 0) mdiow(get_token(&c), get_token(&c), get_token(&c)); - else if(strcmp(token, "mdior") == 0) mdior(get_token(&c), get_token(&c)); - else if(strcmp(token, "mdiod") == 0) mdiod(get_token(&c), get_token(&c)); -#endif - else if(strcmp(token, "crc") == 0) crc(get_token(&c), get_token(&c)); - else if(strcmp(token, "ident") == 0) ident(); - - else if(strcmp(token, "flush_cpu_dcache") == 0) flush_cpu_dcache(); -#ifdef CONFIG_L2_SIZE - else if(strcmp(token, "flush_l2_cache") == 0) flush_l2_cache(); -#endif - -#ifdef CSR_CTRL_BASE - else if(strcmp(token, "reboot") == 0) reboot(); -#endif -#ifdef FLASH_BOOT_ADDRESS - else if(strcmp(token, "flashboot") == 0) flashboot(); -#endif -#ifdef ROM_BOOT_ADDRESS - else if(strcmp(token, "romboot") == 0) romboot(); -#endif - else if(strcmp(token, "serialboot") == 0) serialboot(); -#ifdef CSR_ETHMAC_BASE - else if(strcmp(token, "netboot") == 0) netboot(); -#endif - - else if(strcmp(token, "help") == 0) help(); - -#ifdef CSR_SDRAM_BASE - else if(strcmp(token, "sdrrow") == 0) sdrrow(get_token(&c)); - else if(strcmp(token, "sdrsw") == 0) sdrsw(); - else if(strcmp(token, "sdrhw") == 0) sdrhw(); - else if(strcmp(token, "sdrrdbuf") == 0) sdrrdbuf(-1); - else if(strcmp(token, "sdrrd") == 0) sdrrd(get_token(&c), get_token(&c)); - else if(strcmp(token, "sdrrderr") == 0) sdrrderr(get_token(&c)); - else if(strcmp(token, "sdrwr") == 0) sdrwr(get_token(&c)); -#ifdef CSR_DDRPHY_BASE - else if(strcmp(token, "sdrinit") == 0) sdrinit(); -#ifdef SDRAM_PHY_WRITE_LEVELING_CAPABLE - else if(strcmp(token, "sdrwlon") == 0) sdrwlon(); - else if(strcmp(token, "sdrwloff") == 0) sdrwloff(); -#endif - else if(strcmp(token, "sdrlevel") == 0) sdrlevel(); -#endif - else if(strcmp(token, "memtest") == 0) memtest(); -#endif - -#ifdef CSR_SDCORE_BASE - else if(strcmp(token, "sdclk") == 0) sdclk_set_clk(atoi(get_token(&c))); - else if(strcmp(token, "sdinit") == 0) sdcard_init(); - else if(strcmp(token, "sdtest") == 0) sdcard_test(atoi(get_token(&c))); -#endif -#ifdef USDDRPHY_DEBUG - else if(strcmp(token, "sdram_cdly") == 0) - ddrphy_cdly(atoi(get_token(&c))); - else if(strcmp(token, "sdram_cal") == 0) - sdrcal(); - else if(strcmp(token, "sdram_mpr") == 0) - sdrmpr(); - else if(strcmp(token, "sdram_mrwr") == 0) { - unsigned int reg; - unsigned int value; - reg = atoi(get_token(&c)); - value = atoi(get_token(&c)); - sdrsw(); - printf("Writing 0x%04x to SDRAM mode register %d\n", value, reg); - sdrmrwr(reg, value); - sdrhw(); - } - else if(strcmp(token, "sdram_cdly_scan") == 0) { - unsigned int enabled; - enabled = atoi(get_token(&c)); - sdr_cdly_scan(enabled); - } -#endif -#ifdef CSR_SPISDCARD_BASE - else if(strcmp(token, "spisdcardboot") == 0) spisdcardboot(); -#endif - - else if(strcmp(token, "") != 0) - printf("Command not found\n"); -} +#include "command.h" static void boot_sequence(void) { @@ -511,7 +72,12 @@ static void boot_sequence(void) int main(int i, char **c) { char buffer[CMD_LINE_BUFFER_SIZE]; + char *params[MAX_PARAM]; + char *command; + struct command_struct *cmd; + int nb_params; int sdr_ok; + #ifdef CONFIG_CPU_HAS_INTERRUPT irq_setmask(0); irq_setie(1); @@ -600,7 +166,10 @@ int main(int i, char **c) readline(buffer, CMD_LINE_BUFFER_SIZE); if (buffer[0] != 0) { printf("\n"); - do_command(buffer); + nb_params = get_param(buffer, &command, params); + cmd = command_dispatcher(command, nb_params, params); + if (!cmd) + printf("Command not found"); } printf("\n%s", PROMPT); } diff --git a/litex/soc/software/bios/sdram.c b/litex/soc/software/bios/sdram.c index 513a12665..1e139d5d2 100644 --- a/litex/soc/software/bios/sdram.c +++ b/litex/soc/software/bios/sdram.c @@ -78,28 +78,18 @@ void sdrhw(void) printf("SDRAM now under hardware control\n"); } -void sdrrow(char *_row) +void sdrrow(unsigned int row) { - char *c; - unsigned int row; - - if(*_row == 0) { + if(row == 0) { sdram_dfii_pi0_address_write(0x0000); sdram_dfii_pi0_baddress_write(0); command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS); cdelay(15); - printf("Precharged\n"); } else { - row = strtoul(_row, &c, 0); - if(*c != 0) { - printf("incorrect row\n"); - return; - } sdram_dfii_pi0_address_write(row); sdram_dfii_pi0_baddress_write(0); command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CS); cdelay(15); - printf("Activated row %d\n", row); } } @@ -126,58 +116,23 @@ void sdrrdbuf(int dq) printf("\n"); } -void sdrrd(char *startaddr, char *dq) +void sdrrd(unsigned int addr, int dq) { - char *c; - unsigned int addr; - int _dq; - - if(*startaddr == 0) { - printf("sdrrd
\n"); - return; - } - addr = strtoul(startaddr, &c, 0); - if(*c != 0) { - printf("incorrect address\n"); - return; - } - if(*dq == 0) - _dq = -1; - else { - _dq = strtoul(dq, &c, 0); - if(*c != 0) { - printf("incorrect DQ\n"); - return; - } - } - sdram_dfii_pird_address_write(addr); sdram_dfii_pird_baddress_write(0); command_prd(DFII_COMMAND_CAS|DFII_COMMAND_CS|DFII_COMMAND_RDDATA); cdelay(15); - sdrrdbuf(_dq); + sdrrdbuf(dq); } -void sdrrderr(char *count) +void sdrrderr(int count) { int addr; - char *c; - int _count; int i, j, p; unsigned char prev_data[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES]; unsigned char errs[SDRAM_PHY_PHASES][DFII_PIX_DATA_BYTES]; unsigned char new_data[DFII_PIX_DATA_BYTES]; - if(*count == 0) { - printf("sdrrderr \n"); - return; - } - _count = strtoul(count, &c, 0); - if(*c != 0) { - printf("incorrect count\n"); - return; - } - for(p=0;p\n"); - return; - } - addr = strtoul(startaddr, &c, 0); - if(*c != 0) { - printf("incorrect address\n"); - return; - } - for(p=0;p Date: Wed, 29 Apr 2020 21:57:13 +0200 Subject: [PATCH 5/5] bios: add auto completion for commands --- litex/soc/software/bios/Makefile | 6 + litex/soc/software/bios/command.h | 2 + litex/soc/software/bios/complete.c | 174 +++++++++++++++++++++++++++++ litex/soc/software/bios/complete.h | 6 + litex/soc/software/bios/readline.c | 28 +++++ 5 files changed, 216 insertions(+) create mode 100644 litex/soc/software/bios/complete.c create mode 100644 litex/soc/software/bios/complete.h diff --git a/litex/soc/software/bios/Makefile b/litex/soc/software/bios/Makefile index c80e0a130..4b8c6a51c 100755 --- a/litex/soc/software/bios/Makefile +++ b/litex/soc/software/bios/Makefile @@ -26,6 +26,12 @@ OBJECTS = isr.o \ cmd_spi_flash.o \ cmd_usddrphy.o +ifneq "$(or $(TERM_NO_COMPLETE),$(TERM_MINI))" "" +CFLAGS += -DTERM_NO_COMPLETE +else +OBJECTS += complete.o +endif + ifdef TERM_NO_HIST CFLAGS += -DTERM_NO_HIST endif diff --git a/litex/soc/software/bios/command.h b/litex/soc/software/bios/command.h index 247043895..693d79825 100644 --- a/litex/soc/software/bios/command.h +++ b/litex/soc/software/bios/command.h @@ -7,6 +7,8 @@ #define MAX_PARAM 8 +#define HIST_DEPTH 10 /* Used in string list, complete.c */ + #define MISC_CMDS 0 #define SYSTEM_CMDS 1 #define CACHE_CMDS 2 diff --git a/litex/soc/software/bios/complete.c b/litex/soc/software/bios/complete.c new file mode 100644 index 000000000..e4283297f --- /dev/null +++ b/litex/soc/software/bios/complete.c @@ -0,0 +1,174 @@ +// This file is Copyright (c) 2020 Franck Jullien +// +// Largely inspired/copied from U-boot and Barebox projects wich are: +// Sascha Hauer, Pengutronix, + +// License: BSD + +#include +#include +#include + +#include "readline.h" +#include "helpers.h" +#include "command.h" +#include "complete.h" + +static int tab_pressed = 0; + +char sl[HIST_DEPTH][CMD_LINE_BUFFER_SIZE]; +int sl_idx = 0; + +char out[CMD_LINE_BUFFER_SIZE]; + +static void string_list_init(void) +{ + int i; + for (i = 0; i < HIST_DEPTH; i++) + sl[i][0] = 0; +} + +static int string_list_add(const char *string) +{ + int i; + for (i = 0; i < HIST_DEPTH; i++) { + if (sl[i][0] == 0) { + strncpy(&sl[i][0], string, CMD_LINE_BUFFER_SIZE); + return 0; + } + } + return -1; +} + +static int string_list_empty(void) +{ + int i; + for (i = 0; i < HIST_DEPTH; i++) + if (sl[i][0] != 0) + return 0; + return 1; +} + +static int string_list_count(void) +{ + int i, count = 0; + for (i = 0; i < HIST_DEPTH; i++) + if (sl[i][0] != 0) + count++; + return count; +} + +static char *list_first_entry(void) +{ + int i; + for (i = 0; i < HIST_DEPTH; i++) + if (sl[i][0] != 0) + return &sl[i][0]; + return NULL; +} + +static void string_list_print_by_column(void) +{ + int len = 0, num, i, j; + + for (i = 0; i < HIST_DEPTH; i++) { + if (sl[i][0] != 0) { + int l = strlen(&sl[i][0]) + 4; + if (l > len) + len = l; + } + } + + if (!len) + return; + + num = 80 / (len + 1); + + for (j = 0; j < HIST_DEPTH; j++) { + if (sl[j][0] != 0) { + if (!(++i % num)) + printf("%s\n", &sl[j][0]); + else + printf("%-*s", len, &sl[j][0]); + } + } + if (i % num) + printf("\n"); +} + +static void command_complete(char *instr) +{ + struct command_struct * const *cmd; + + for (cmd = __bios_cmd_start; cmd != __bios_cmd_end; cmd++) + if (!strncmp(instr, (*cmd)->name, strlen(instr))) + string_list_add((*cmd)->name); +} + +int complete(char *instr, char **outstr) +{ + int pos; + char ch; + int changed; + int outpos = 0; + int reprint = 0; + char *first_entry; + char *entry; + int i; + + string_list_init(); + command_complete(instr); + + pos = strlen(instr); + + *outstr = ""; + if (string_list_empty()) + reprint = 0; + else + { + out[0] = 0; + + first_entry = list_first_entry(); + + while (1) { + entry = first_entry; + ch = entry[pos]; + if (!ch) + break; + + changed = 0; + for (i = 0; i < HIST_DEPTH; i++) { + if (sl[i][0] != 0) { + if (!sl[i][pos]) + break; + if (ch != sl[i][pos]) { + changed = 1; + break; + } + } + } + + if (changed) + break; + out[outpos++] = ch; + pos++; + } + + if ((string_list_count() != 1) && !outpos && tab_pressed) { + printf("\n"); + string_list_print_by_column(); + reprint = 1; + tab_pressed = 0; + } + + out[outpos++] = 0; + *outstr = out; + + if (*out == 0) + tab_pressed = 1; + else + tab_pressed = 0; + } + + return reprint; +} diff --git a/litex/soc/software/bios/complete.h b/litex/soc/software/bios/complete.h new file mode 100644 index 000000000..b615df76a --- /dev/null +++ b/litex/soc/software/bios/complete.h @@ -0,0 +1,6 @@ +#ifndef __COMPLETE_H__ +#define __COMPLETE_H__ + +int complete(char *instr, char **outstr); + +#endif diff --git a/litex/soc/software/bios/readline.c b/litex/soc/software/bios/readline.c index 998ebc0ef..48d8f1a6c 100644 --- a/litex/soc/software/bios/readline.c +++ b/litex/soc/software/bios/readline.c @@ -17,6 +17,7 @@ #include #include "readline.h" +#include "complete.h" #ifndef TERM_NO_HIST static int hist_max = 0; @@ -191,6 +192,12 @@ int readline(char *buf, int len) int insert = 1; char ichar; +#ifndef TERM_NO_COMPLETE + char tmp; + int reprint, i; + char *completestr; +#endif + while (1) { ichar = read_key(); @@ -200,6 +207,27 @@ int readline(char *buf, int len) switch (ichar) { case '\t': +#ifndef TERM_NO_COMPLETE + buf[eol_num] = 0; + tmp = buf[num]; + + buf[num] = 0; + reprint = complete(buf, &completestr); + buf[num] = tmp; + + if (reprint) { + printf("%s%s", PROMPT, buf); + + if (tmp) + for (i = 0; i < eol_num - num; i++) + getcmd_putch(CTL_BACKSPACE); + } + + i = 0; + while (completestr[i]) + cread_add_char(completestr[i++], insert, &num, + &eol_num, buf, len); +#endif break; case KEY_HOME: