software: shell from original BIOS
authorSebastien Bourdeauducq <sebastien@milkymist.org>
Tue, 7 Feb 2012 14:02:44 +0000 (15:02 +0100)
committerSebastien Bourdeauducq <sebastien@milkymist.org>
Tue, 7 Feb 2012 14:02:44 +0000 (15:02 +0100)
software/bios/Makefile
software/bios/main.c
software/include/base/console.h
software/include/base/stdio.h
software/libbase/console.c
software/libextra/Makefile [new file with mode: 0644]
software/libextra/crc16.c
software/libextra/crc32.c

index 5a5ac66d39dce8de4f891cf33dd67d52a4fb2369..f916aaab02ac3a23bad221f69b898e772b81a92f 100644 (file)
@@ -18,11 +18,12 @@ bios.elf: linker.ld $(OBJECTS) libs
 bios-rescue.elf: linker-rescue.ld $(OBJECTS) libs
 
 %.elf:
-       $(LD) $(LDFLAGS) -T $< -N -o $@ $(OBJECTS) -L$(M2DIR)/software/libbase -lbase
+       $(LD) $(LDFLAGS) -T $< -N -o $@ $(OBJECTS) -L$(M2DIR)/software/libbase -L$(M2DIR)/software/libextra -lbase -lextra
        chmod -x $@
 
 libs:
        make -C $(M2DIR)/software/libbase
+       make -C $(M2DIR)/software/libextra
 
 .PHONY: clean libs
 
index d90867b4261e87f30d502b0ca86a6b95fc463cff..c408b8e3fe75312b606b91d3db8bbdf39cee9775 100644 (file)
+/*
+ * Milkymist SoC (Software)
+ * Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Sebastien Bourdeauducq
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 3 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 #include <stdio.h>
-#include <irq.h>
+#include <console.h>
+#include <string.h>
 #include <uart.h>
+#include <system.h>
+#include <board.h>
+#include <irq.h>
+#include <version.h>
+#include <extra/crc.h>
+
+#include <hw/flash.h>
+
+enum {
+       CSR_IE = 1, CSR_IM, CSR_IP, CSR_ICC, CSR_DCC, CSR_CC, CSR_CFG, CSR_EBA,
+       CSR_DC, CSR_DEBA, CSR_JTX, CSR_JRX, CSR_BP0, CSR_BP1, CSR_BP2, CSR_BP3,
+       CSR_WP0, CSR_WP1, CSR_WP2, CSR_WP3,
+};
+
+/* General address space functions */
+
+#define NUMBER_OF_BYTES_ON_A_LINE 16
+static void dump_bytes(unsigned int *ptr, int count, unsigned 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<line_bytes;i++) {
+                       if((*(data+i) < 0x20) || (*(data+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");
+}
+
+static void mr(char *startaddr, char *len)
+{
+       char *c;
+       unsigned int *addr;
+       unsigned int length;
+
+       if(*startaddr == 0) {
+               printf("mr <address> [length]\n");
+               return;
+       }
+       addr = (unsigned *)strtoul(startaddr, &c, 0);
+       if(*c != 0) {
+               printf("incorrect address\n");
+               return;
+       }
+       if(*len == 0) {
+               length = 1;
+       } else {
+               length = strtoul(len, &c, 0);
+               if(*c != 0) {
+                       printf("incorrect length\n");
+                       return;
+               }
+       }
+
+       dump_bytes(addr, length, (unsigned)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 <address> <value> [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<count2;i++) *addr2++ = value2;
+}
+
+static void mc(char *dstaddr, char *srcaddr, char *count)
+{
+       char *c;
+       unsigned int *dstaddr2;
+       unsigned int *srcaddr2;
+       unsigned int count2;
+       unsigned int i;
+
+       if((*dstaddr == 0) || (*srcaddr == 0)) {
+               printf("mc <dst> <src> [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<count2;i++) *dstaddr2++ = *srcaddr2++;
+}
+
+static void crc(char *startaddr, char *len)
+{
+       char *c;
+       char *addr;
+       unsigned int length;
+
+       if((*startaddr == 0)||(*len == 0)) {
+               printf("crc <address> <length>\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));
+}
+
+/* processor registers */
+static int parse_csr(const char *csr)
+{
+       if(!strcmp(csr, "ie"))   return CSR_IE;
+       if(!strcmp(csr, "im"))   return CSR_IM;
+       if(!strcmp(csr, "ip"))   return CSR_IP;
+       if(!strcmp(csr, "icc"))  return CSR_ICC;
+       if(!strcmp(csr, "dcc"))  return CSR_DCC;
+       if(!strcmp(csr, "cc"))   return CSR_CC;
+       if(!strcmp(csr, "cfg"))  return CSR_CFG;
+       if(!strcmp(csr, "eba"))  return CSR_EBA;
+       if(!strcmp(csr, "dc"))   return CSR_DC;
+       if(!strcmp(csr, "deba")) return CSR_DEBA;
+       if(!strcmp(csr, "jtx"))  return CSR_JTX;
+       if(!strcmp(csr, "jrx"))  return CSR_JRX;
+       if(!strcmp(csr, "bp0"))  return CSR_BP0;
+       if(!strcmp(csr, "bp1"))  return CSR_BP1;
+       if(!strcmp(csr, "bp2"))  return CSR_BP2;
+       if(!strcmp(csr, "bp3"))  return CSR_BP3;
+       if(!strcmp(csr, "wp0"))  return CSR_WP0;
+       if(!strcmp(csr, "wp1"))  return CSR_WP1;
+       if(!strcmp(csr, "wp2"))  return CSR_WP2;
+       if(!strcmp(csr, "wp3"))  return CSR_WP3;
+
+       return 0;
+}
+
+static void rcsr(char *csr)
+{
+       unsigned int csr2;
+       register unsigned int value;
+
+       if(*csr == 0) {
+               printf("rcsr <csr>\n");
+               return;
+       }
+
+       csr2 = parse_csr(csr);
+       if(csr2 == 0) {
+               printf("incorrect csr\n");
+               return;
+       }
+
+       switch(csr2) {
+               case CSR_IE:   asm volatile ("rcsr %0,ie":"=r"(value)); break;
+               case CSR_IM:   asm volatile ("rcsr %0,im":"=r"(value)); break;
+               case CSR_IP:   asm volatile ("rcsr %0,ip":"=r"(value)); break;
+               case CSR_CC:   asm volatile ("rcsr %0,cc":"=r"(value)); break;
+               case CSR_CFG:  asm volatile ("rcsr %0,cfg":"=r"(value)); break;
+               case CSR_EBA:  asm volatile ("rcsr %0,eba":"=r"(value)); break;
+               case CSR_DEBA: asm volatile ("rcsr %0,deba":"=r"(value)); break;
+               case CSR_JTX:  asm volatile ("rcsr %0,jtx":"=r"(value)); break;
+               case CSR_JRX:  asm volatile ("rcsr %0,jrx":"=r"(value)); break;
+               default: printf("csr write only\n"); return;
+       }
+
+       printf("%08x\n", value);
+}
+
+static void wcsr(char *csr, char *value)
+{
+       char *c;
+       unsigned int csr2;
+       register unsigned int value2;
+
+       if((*csr == 0) || (*value == 0)) {
+               printf("wcsr <csr> <address>\n");
+               return;
+       }
+
+       csr2 = parse_csr(csr);
+       if(csr2 == 0) {
+               printf("incorrect csr\n");
+               return;
+       }
+       value2 = strtoul(value, &c, 0);
+       if(*c != 0) {
+               printf("incorrect value\n");
+               return;
+       }
+
+       switch(csr2) {
+               case CSR_IE:   asm volatile ("wcsr ie,%0"::"r"(value2)); break;
+               case CSR_IM:   asm volatile ("wcsr im,%0"::"r"(value2)); break;
+               case CSR_ICC:  asm volatile ("wcsr icc,%0"::"r"(value2)); break;
+               case CSR_DCC:  asm volatile ("wcsr dcc,%0"::"r"(value2)); break;
+               case CSR_EBA:  asm volatile ("wcsr eba,%0"::"r"(value2)); break;
+               case CSR_DC:   asm volatile ("wcsr dcc,%0"::"r"(value2)); break;
+               case CSR_DEBA: asm volatile ("wcsr deba,%0"::"r"(value2)); break;
+               case CSR_JTX:  asm volatile ("wcsr jtx,%0"::"r"(value2)); break;
+               case CSR_JRX:  asm volatile ("wcsr jrx,%0"::"r"(value2)); break;
+               case CSR_BP0:  asm volatile ("wcsr bp0,%0"::"r"(value2)); break;
+               case CSR_BP1:  asm volatile ("wcsr bp1,%0"::"r"(value2)); break;
+               case CSR_BP2:  asm volatile ("wcsr bp2,%0"::"r"(value2)); break;
+               case CSR_BP3:  asm volatile ("wcsr bp3,%0"::"r"(value2)); break;
+               case CSR_WP0:  asm volatile ("wcsr wp0,%0"::"r"(value2)); break;
+               case CSR_WP1:  asm volatile ("wcsr wp1,%0"::"r"(value2)); break;
+               case CSR_WP2:  asm volatile ("wcsr wp2,%0"::"r"(value2)); break;
+               case CSR_WP3:  asm volatile ("wcsr wp3,%0"::"r"(value2)); break;
+               default: printf("csr read only\n"); return;
+       }
+}
+
+/* Init + command line */
+
+static void help()
+{
+       puts("Milkymist(tm) BIOS");
+       puts("Don't know what to do? Try 'flashboot'.\n");
+       puts("Available commands:");
+       puts("mr         - read address space");
+       puts("mw         - write address space");
+       puts("mc         - copy address space");
+       puts("crc        - compute CRC32 of a part of the address space");
+       puts("rcsr       - read processor CSR");
+       puts("wcsr       - write processor CSR");
+       puts("version    - display version");
+       puts("reboot     - system reset");
+       puts("reconf     - reload FPGA configuration");
+}
+
+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 do_command(char *c)
+{
+       char *token;
 
-int main(void)
+       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));
+       else if(strcmp(token, "crc") == 0) crc(get_token(&c), get_token(&c));
+
+       else if(strcmp(token, "version") == 0) puts(VERSION);
+       else if(strcmp(token, "reboot") == 0) reboot();
+       else if(strcmp(token, "reconf") == 0) reconf();
+
+       else if(strcmp(token, "help") == 0) help();
+
+       else if(strcmp(token, "rcsr") == 0) rcsr(get_token(&c));
+       else if(strcmp(token, "wcsr") == 0) wcsr(get_token(&c), get_token(&c));
+
+       else if(strcmp(token, "") != 0)
+               printf("Command not found\n");
+}
+
+int rescue;
+extern unsigned int _edata;
+
+static void crcbios()
+{
+       unsigned int offset_bios;
+       unsigned int 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 = rescue ? FLASH_OFFSET_RESCUE_BIOS : FLASH_OFFSET_REGULAR_BIOS;
+       expected_crc = _edata;
+       length = (unsigned int)&_edata - offset_bios;
+       actual_crc = crc32((unsigned char *)offset_bios, length);
+       if(expected_crc == actual_crc)
+               printf("I: BIOS CRC passed (%08x)\n", actual_crc);
+       else {
+               printf("W: BIOS CRC failed (expected %08x, got %08x)\n", expected_crc, actual_crc);
+               printf("W: The system will continue, but expect problems.\n");
+       }
+}
+
+static void print_mac()
+{
+       unsigned char *macadr = (unsigned char *)FLASH_OFFSET_MAC_ADDRESS;
+
+       printf("I: MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n", macadr[0], macadr[1], macadr[2], macadr[3], macadr[4], macadr[5]);
+}
+
+static const char banner[] =
+       "\nMILKYMIST(tm) v"VERSION" BIOS   http://www.milkymist.org\n"
+       "(c) Copyright 2007-2012 Sebastien Bourdeauducq\n\n"
+       "This program is free software: you can redistribute it and/or modify\n"
+       "it under the terms of the GNU General Public License as published by\n"
+       "the Free Software Foundation, version 3 of the License.\n";
+
+static void readstr(char *s, int size)
+{
+       char c[2];
+       int ptr;
+
+       c[1] = 0;
+       ptr = 0;
+       while(1) {
+               c[0] = readchar();
+               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");
+                               return;
+                       default:
+                               putsnonl(c);
+                               s[ptr] = c[0];
+                               ptr++;
+                               break;
+               }
+       }
+}
+
+int main(int i, char **c)
 {
-       char c;
-       
+       char buffer[64];
+
+       rescue = !((unsigned int)main > FLASH_OFFSET_REGULAR_BIOS);
+
        irq_setmask(0);
        irq_setie(1);
        uart_init();
-       
-       printf("Hello World with IRQs\n");
-       
+       printf(banner);
+       crcbios();
+
+       if(rescue)
+               printf("I: Booting in rescue mode\n");
+
+       print_mac();
        while(1) {
-               c = uart_read();
-               printf("You typed: %c\n", c);
+               putsnonl("\e[1mBIOS>\e[0m ");
+               readstr(buffer, 64);
+               do_command(buffer);
        }
+       return 0;
 }
index d89f0a1537c9106947fd42d50ed1b31b6d620c5c..795176372f9df57078d64f58f5daea3bfef3909a 100644 (file)
@@ -28,7 +28,6 @@ void console_set_read_hook(console_read_hook r, console_read_nonblock_hook rn);
 char readchar(void);
 int readchar_nonblock(void);
 
-int puts(const char *s);
 void putsnonl(const char *s);
 
 #endif /* __CONSOLE_H */
index 5fb35a59c735466c60559b314e107afa39bbbebb..f80e3a6f19fd8dab9948f800481c7eb82275918d 100644 (file)
@@ -20,6 +20,9 @@
 
 #include <stdlib.h>
 
+int putchar(int c);
+int puts(const char *s);
+
 int snprintf(char *buf, size_t size, const char *fmt, ...);
 int scnprintf(char *buf, size_t size, const char *fmt, ...);
 int sprintf(char *buf, const char *fmt, ...);
index d27bff3d2d51a59edc4523ba862b488acf9d1c12..19d0a97b5b2b58dab3f4290143b339b1b7c25fb1 100644 (file)
@@ -19,8 +19,6 @@
 #include <console.h>
 #include <stdio.h>
 #include <stdarg.h>
-#include <irq.h>
-#include <hw/interrupts.h>
 
 static console_write_hook write_hook;
 static console_read_hook read_hook;
@@ -37,11 +35,12 @@ void console_set_read_hook(console_read_hook r, console_read_nonblock_hook rn)
        read_nonblock_hook = rn;
 }
 
-static void writechar(char c)
+int putchar(int c)
 {
        uart_write(c);
        if(write_hook != NULL)
                write_hook(c);
+       return c;
 }
 
 char readchar(void)
@@ -62,34 +61,20 @@ int readchar_nonblock(void)
 
 int puts(const char *s)
 {
-       unsigned int oldmask;
-
-       oldmask = irq_getmask();
-       irq_setmask(IRQ_UART); // HACK: prevent UART data loss
-
        while(*s) {
-               writechar(*s);
+               putchar(*s);
                s++;
        }
-       writechar('\n');
-       
-       irq_setmask(oldmask);
+       putchar('\n');
        return 1;
 }
 
 void putsnonl(const char *s)
 {
-       unsigned int oldmask;
-
-       oldmask = irq_getmask();
-       irq_setmask(IRQ_UART); // HACK: prevent UART data loss
-       
        while(*s) {
-               writechar(*s);
+               putchar(*s);
                s++;
        }
-       
-       irq_setmask(oldmask);
 }
 
 int printf(const char *fmt, ...)
diff --git a/software/libextra/Makefile b/software/libextra/Makefile
new file mode 100644 (file)
index 0000000..34747a6
--- /dev/null
@@ -0,0 +1,18 @@
+M2DIR=../..
+include $(M2DIR)/software/include.mak
+
+OBJECTS=crc16.o crc32.o
+
+all: libextra.a
+
+# pull in dependency info for *existing* .o files
+-include $(OBJECTS:.o=.d)
+
+libextra.a: $(OBJECTS)
+       $(AR) clr libextra.a $(OBJECTS)
+       $(RANLIB) libextra.a
+
+.PHONY: clean
+
+clean:
+       rm -f $(OBJECTS) $(OBJECTS:.o=.d) libextra.a .*~ *~
index a1222e861101602c4c281bf8cb765e16f26faf67..afd848c60876d00ee444c3217f8689f57e14e554 100644 (file)
@@ -1,4 +1,4 @@
-#include <crc.h>
+#include <extra/crc.h>
 
 static const unsigned int crc16_table[256] = {
        0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
index 29b9b99445c885ec6871dd5545b2da38c10fa380..f9438227d9ddca3551a5b3b28c893c43689cac77 100644 (file)
@@ -3,7 +3,7 @@
  * For conditions of distribution and use, see copyright notice in zlib.h
  */
 
-#include <crc.h>
+#include <extra/crc.h>
 
 static const unsigned int crc_table[256] = {
        0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L,