From 1edd5bb39e4cba40fa3e2cc91e8fb377e28bdc5a Mon Sep 17 00:00:00 2001 From: Jacob Pease Date: Fri, 2 Aug 2024 15:19:52 -0500 Subject: [PATCH] New bootloader now works. Added special print functions and print messages. sdclk is set to 3MHz after initialization currently. --- fpga/zsbl/boot.c | 92 +++++++++++++++++++++++++++++++++++------------- fpga/zsbl/boot.h | 2 ++ fpga/zsbl/gpt.c | 8 +++++ fpga/zsbl/sd.c | 63 ++++++++++++++++++++++++--------- fpga/zsbl/spi.c | 6 +++- fpga/zsbl/spi.h | 1 + fpga/zsbl/uart.c | 40 +++++++++++++++++++-- fpga/zsbl/uart.h | 11 ++++++ 8 files changed, 179 insertions(+), 44 deletions(-) diff --git a/fpga/zsbl/boot.c b/fpga/zsbl/boot.c index 7b2e9af7d..e47b34e2f 100644 --- a/fpga/zsbl/boot.c +++ b/fpga/zsbl/boot.c @@ -4,6 +4,9 @@ #include "uart.h" #include "spi.h" #include "sd.h" +#include "time.h" +#include "riscv.h" +#include "fail.h" /* int disk_read(BYTE * buf, LBA_t sector, UINT count, BYTE card_type) { */ @@ -34,11 +37,31 @@ /* return 0;; */ /* } */ -#define SYSTEMCLOCK 20000000 +// Need to convert this +/* void print_progress(size_t count, size_t max) { */ +/* const int bar_width = 50; */ + +/* float progress = (float) count / max; */ +/* int bar_length = progress * bar_width; */ + +/* printf("\r["); */ +/* for (int i = 0; i < bar_length; ++i) { */ +/* printf("#"); */ +/* } */ +/* for (int i = bar_length; i < bar_width; ++i) { */ +/* printf("-"); */ +/* } */ +/* printf("] %.2f%%", progress * 100); */ + +/* fflush(stdout); */ +/* } */ int disk_read(BYTE * buf, LBA_t sector, UINT count) { uint64_t r; UINT i; + volatile uint8_t *p = buf; + + UINT modulus = count/50; uint8_t crc = 0; crc = crc7(crc, 0x40 | SD_CMD_READ_BLOCK_MULTIPLE); @@ -52,48 +75,69 @@ int disk_read(BYTE * buf, LBA_t sector, UINT count) { print_uart("disk_read: CMD18 failed. r = 0x"); print_uart_byte(r); print_uart("\r\n"); - return -1; + fail(); + // return -1; } + print_uart("\r Blocks loaded: "); + print_uart("0"); + print_uart("/"); + print_uart_dec(count); // write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_HOLD); // Begin reading blocks for (i = 0; i < count; i++) { uint16_t crc, crc_exp; - - // Read the data token - r = spi_readbyte(); - /* if (r != SD_DATA_TOKEN) { */ - /* print_uart("Didn't receive data token first thing. Shoot: "); */ - /* print_uart_byte(r & 0xff); */ - /* print_uart("\r\n"); */ - /* return -1; */ - /* } */ + uint64_t n = 0; // Wait for data token - while((r & 0xff) != SD_DATA_TOKEN); + while((r = spi_dummy()) != SD_DATA_TOKEN); + // println_with_byte("Received data token: 0x", r & 0xff); + // println_with_dec("Block ", i); // Read block into memory. - for (int j = 0; j < 8; j++) { - *buf = sd_read64(&crc); - buf = buf + 64; - } - + /* for (int j = 0; j < 64; j++) { */ + /* *buf = sd_read64(&crc); */ + /* println_with_addr("0x", *buf); */ + /* buf = buf + 64; */ + /* } */ + crc = 0; + n = 512; + do { + uint8_t x = spi_dummy(); + *p++ = x; + crc = crc16(crc, x); + } while (--n > 0); + // Read CRC16 and check - crc_exp = ((uint16_t)spi_txrx(0xff) << 8); - crc_exp |= spi_txrx(0xff); + crc_exp = ((uint16_t)spi_dummy() << 8); + crc_exp |= spi_dummy(); if (crc != crc_exp) { print_uart("Stinking CRC16 didn't match on block read.\r\n"); print_uart_int(i); print_uart("\r\n"); - return -1; + //return -1; + fail(); } - + + if ( (i % modulus) == 0 ) { + print_uart("\r Blocks loaded: "); + print_uart_dec(i); + print_uart("/"); + print_uart_dec(count); + } + } sd_cmd(SD_CMD_STOP_TRANSMISSION, 0, 0x01); + + print_uart("\r Blocks loaded: "); + print_uart_dec(count); + print_uart("/"); + print_uart_dec(count); // write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_AUTO); //spi_txrx(0xff); + print_uart("\r\n"); return 0; } @@ -106,7 +150,7 @@ void copyFlash(QWORD address, QWORD * Dst, DWORD numBlocks) { // Initialize UART for messages init_uart(20000000, 115200); - + // Print the wally banner print_uart(BANNER); @@ -114,10 +158,8 @@ void copyFlash(QWORD address, QWORD * Dst, DWORD numBlocks) { /* print_uart_dec(SYSTEMCLOCK); */ /* print_uart("\r\n"); */ - println_with_dec("Hello, does this work? Here's the clock: ", SYSTEMCLOCK); - // Intialize the SD card - init_sd(SYSTEMCLOCK, SYSTEMCLOCK/2); + init_sd(SYSTEMCLOCK, 3000000); ret = gpt_load_partitions(); } diff --git a/fpga/zsbl/boot.h b/fpga/zsbl/boot.h index 087550326..25b8a5fcc 100644 --- a/fpga/zsbl/boot.h +++ b/fpga/zsbl/boot.h @@ -32,5 +32,7 @@ typedef QWORD LBA_t; // Export disk_read int disk_read(BYTE * buf, LBA_t sector, UINT count); +#define SYSTEMCLOCK 20000000 + #endif // WALLYBOOT diff --git a/fpga/zsbl/gpt.c b/fpga/zsbl/gpt.c index 9af396469..99f74ec3a 100644 --- a/fpga/zsbl/gpt.c +++ b/fpga/zsbl/gpt.c @@ -11,11 +11,13 @@ int gpt_load_partitions() { int ret = 0; //ret = disk_read(/* BYTE * buf, LBA_t sector, UINT count, BYTE card_type */); + print_time(); println("Getting GPT information."); ret = disk_read(lba1_buf, 1, 1); gpt_pth_t *lba1 = (gpt_pth_t *)lba1_buf; + print_time(); println("Getting partition entries."); BYTE lba2_buf[512]; ret = disk_read(lba2_buf, (LBA_t)lba1->partition_entries_lba, 1); @@ -26,6 +28,7 @@ int gpt_load_partitions() { partition_entries_t *kernel = (partition_entries_t *)(lba2_buf + 256); // Load device tree + print_time(); println_with_int("Loading device tree at: 0x", FDT_ADDRESS); ret = disk_read((BYTE *)FDT_ADDRESS, fdt->first_lba, fdt->last_lba - fdt->first_lba + 1); if (ret < 0) { @@ -34,6 +37,7 @@ int gpt_load_partitions() { } // Load OpenSBI + print_time(); println_with_int("Loading OpenSBI at: 0x", OPENSBI_ADDRESS); ret = disk_read((BYTE *)OPENSBI_ADDRESS, opensbi->first_lba, opensbi->last_lba - opensbi->first_lba + 1); if (ret < 0) { @@ -42,6 +46,7 @@ int gpt_load_partitions() { } // Load Linux + print_time(); println_with_int("Loading Linux Kernel at: 0x", KERNEL_ADDRESS); ret = disk_read((BYTE *)KERNEL_ADDRESS, kernel->first_lba,kernel->last_lba - kernel->first_lba + 1); if (ret < 0) { @@ -49,5 +54,8 @@ int gpt_load_partitions() { return -1; } + print_time(); + println("Done! Flashing LEDs and jumping to OpenSBI..."); + return 0; } diff --git a/fpga/zsbl/sd.c b/fpga/zsbl/sd.c index cacf40438..484fd65c0 100644 --- a/fpga/zsbl/sd.c +++ b/fpga/zsbl/sd.c @@ -1,6 +1,8 @@ #include "sd.h" #include "spi.h" #include "uart.h" +#include "fail.h" +#include "time.h" // Parallel byte update CRC7-CCITT algorithm. // The result is the CRC7 result, left shifted over by 1 @@ -36,9 +38,11 @@ uint16_t crc16(uint16_t crc, uint8_t data) { // watermark and interrupt features to determine when a // transfer is complete. This should save on cycles since // no arbitrary delays need to be added. + uint64_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc) { uint8_t response_len; uint8_t i; + uint8_t shiftAmnt; uint64_t r; uint8_t rbyte; @@ -53,6 +57,7 @@ uint64_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc) { break; case 12: response_len = R1B_RESPONSE; + break; default: response_len = R1_RESPONSE; break; @@ -70,6 +75,7 @@ uint64_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc) { // Write all 7 bytes into transfer fifo // spi_sendbyte(0xff); + spi_dummy(); spi_sendbyte(0x40 | cmd); spi_sendbyte(arg >> 24); spi_sendbyte(arg >> 16); @@ -89,30 +95,34 @@ uint64_t sd_cmd(uint8_t cmd, uint32_t arg, uint8_t crc) { // Send "dummy signals". Since SPI is duplex, // useless bytes must be transferred - for (i = 0; i < response_len; i++) { - spi_sendbyte(0xFF); - } + /* for (i = 0; i < response_len; i++) { */ + /* spi_sendbyte(0xFF); */ + /* } */ - // Wait for transfer fifo again - waittx(); + /* // Wait for transfer fifo again */ + /* waittx(); */ // Wait for actual response from SD card // All responses start with a 0. Output of SDCIn is high, unless // a message is being transferred. do { - rbyte = spi_txrx(0xff); + rbyte = spi_dummy(); } while ( (rbyte & 0x80) != 0 ); - r = r | (rbyte << ((response_len - 1)*8)); + // Note about the compiler. In order to compile as sll instead of + // sllw, the number to shift has to be a 64 bit number. + r = ((uint64_t)rbyte) << ((response_len - 1)*8); // Read rxfifo response for (i = 1; i < response_len; i++) { - rbyte = spi_readbyte(); - r = r | (rbyte << ((response_len - 1 - i)*8)); + rbyte = spi_dummy(); + r = r | (((uint64_t)rbyte) << ((response_len - 1 - i)*8)); } if (cmd != 18) { write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_AUTO); + } else { + spi_dummy(); } return r; } // sd_cmd @@ -122,16 +132,16 @@ uint64_t sd_read64(uint16_t * crc) { uint8_t rbyte; int i; - for (i = 0; i < 8; i++) { - spi_sendbyte(0xFF); - } + /* for (i = 0; i < 8; i++) { */ + /* spi_sendbyte(0xFF); */ + /* } */ - waittx(); + /* waittx(); */ for (i = 0; i < 8; i++) { - rbyte = spi_readbyte(); + rbyte = spi_dummy(); *crc = crc16(*crc, rbyte); - r = r | (rbyte << ((8 - 1 - i)*8)); + r = r | ((uint64_t)(rbyte) << ((8 - 1 - i)*8)); } return r; @@ -147,11 +157,15 @@ uint64_t sd_read64(uint16_t * crc) { // This first initializes the SPI peripheral then initializes the SD // card itself. We use the uart to display anything that goes wrong. int init_sd(uint32_t freq, uint32_t sdclk){ + print_time(); + println("Initializing SPI Controller."); spi_init(); uint64_t r; uint32_t newClockDiv; + int n; + print_time(); println("Initializing SD Card in SPI mode."); // This is necessary. This is the card's pre-init state initialization. write_reg(SPI_CSMODE, SIFIVE_SPI_CSMODE_MODE_OFF); @@ -165,31 +179,48 @@ int init_sd(uint32_t freq, uint32_t sdclk){ // Initializes SD card into SPI mode if CS is asserted '0' // We expect to get the R1 response 0x01 which means that the // card has been put into the idle state. + print_time(); print_uart("CMD0: "); + n = 0; do { r = CMD0(); + n++; + if (n == 1000) { + fail(); + } } while ( r != 0x01 ); println_with_r1("Success, r = 0x", r & 0xff); // CMD8 ------------------------------------------------------------- - // + // + print_time(); print_uart("CMD8: "); r = CMD8(); if ((r & 0x000000ff0000ffff) != 0x01000001aa) { println_with_r7("Failed, 0x", r); + fail(); } println_with_r7("Success, 0x", r); // ACMD41 ----------------------------------------------------------- + print_time(); print_uart("ACMD41: "); + n = 0; do { CMD55(); r = ACMD41(); + n++; + if (n == 1000) { + fail(); + } } while (r == 0x1); println_with_r1("Success, r = 0x", r & 0xff); + print_time(); println_with_dec("New clock frequency: ", (uint64_t)sdclk); spi_set_clock(freq, sdclk); + + print_time(); println("SD card is initialized."); } diff --git a/fpga/zsbl/spi.c b/fpga/zsbl/spi.c index b8829b12e..5b23c85b6 100644 --- a/fpga/zsbl/spi.c +++ b/fpga/zsbl/spi.c @@ -55,11 +55,15 @@ /* } */ uint8_t spi_txrx(uint8_t byte) { - spi_sendbyte(0xFF); + spi_sendbyte(byte); waittx(); return spi_readbyte(); } +uint8_t spi_dummy() { + return spi_txrx(0xff); +} + /* inline uint8_t spi_readbyte() { */ /* return read_reg(SPI_RXDATA); */ /* } */ diff --git a/fpga/zsbl/spi.h b/fpga/zsbl/spi.h index a662fce86..d2bf1191c 100644 --- a/fpga/zsbl/spi.h +++ b/fpga/zsbl/spi.h @@ -50,6 +50,7 @@ //inline void waittx(); //inline void waitrx(); uint8_t spi_txrx(uint8_t byte); +uint8_t spi_dummy(); //inline uint8_t spi_readbyte(); uint64_t spi_read64(); void spi_init(); diff --git a/fpga/zsbl/uart.c b/fpga/zsbl/uart.c index d7ac9b558..8c25f17ca 100644 --- a/fpga/zsbl/uart.c +++ b/fpga/zsbl/uart.c @@ -1,6 +1,5 @@ #include "uart.h" - void write_reg_u8(uintptr_t addr, uint8_t value) { volatile uint8_t *loc_addr = (volatile uint8_t *)addr; @@ -78,7 +77,7 @@ void print_uart_dec(uint64_t addr) { // floor(log(2^64)) = 19 char str[19] = {'\0'}; - uint8_t length = 0; + uint8_t length = 1; uint64_t cur = addr; while (cur != 0) { @@ -94,6 +93,43 @@ void print_uart_dec(uint64_t addr) { } } +// Print a floating point number on the UART +void print_uart_float(float num, int precision) { + char str[32] = {'\0'}; + char digit; + uint8_t length = precision + 1; + int i; + uint64_t cur; + + str[precision] = '.'; + + int pow = 1; + + // Calculate power for precision + for (i = 0; i < precision; i++) { + pow = pow * 10; + } + + cur = (uint64_t)(num * pow); + for (i = 0; i < precision; i++) { + digit = bin_to_hex_table[cur % 10]; + str[i] = digit; + cur = cur / 10; + } + + cur = (uint64_t)num; + do { + digit = bin_to_hex_table[cur % 10]; + str[length] = digit; + cur = cur/10; + length++; + } while (cur != 0); + + for (i = length; i > -1; i--) { + write_serial(str[i]); + } +} + /* void print_uart_int(uint32_t addr) */ /* { */ /* int i; */ diff --git a/fpga/zsbl/uart.h b/fpga/zsbl/uart.h index 515a9dccd..cbdcc5941 100644 --- a/fpga/zsbl/uart.h +++ b/fpga/zsbl/uart.h @@ -1,5 +1,7 @@ #pragma once #include +#include "riscv.h" +#include "time.h" // UART register addresses #define UART_BASE 0x10000000 @@ -28,6 +30,8 @@ void print_uart_dec(uint64_t addr); void print_uart_addr(uint64_t addr); void print_uart_hex(uint64_t addr, int n); void print_uart_byte(uint8_t byte); +void print_uart_float(float num, int precision); +// void print_time(); // Print numbers in hex with specified widths #define print_uart_int(addr) print_uart_hex(addr, 4) @@ -44,4 +48,11 @@ void print_uart_byte(uint8_t byte); #define println_with_addr(msg, num) print_uart(msg); print_uart_addr(num); print_uart("\r\n") #define println_with_r1(msg, num) print_uart(msg); print_r1(num); print_uart("\r\n") #define println_with_r7(msg, num) print_uart(msg); print_r7(num); print_uart("\r\n") +#define println_with_float(msg, num) print_uart(msg); set_status_fs(); print_uart_float(num,5); clear_status_fs(); print_uart("\r\n") + +/* #define print_time() print_uart("["); \ */ +/* set_status_fs(); \ */ +/* print_uart_float(getTime(),5); \ */ +/* clear_status_fs(); \ */ +/* print_uart("] ") */