From fa6ae7b667fcee677d7b893889d187f04daef8f4 Mon Sep 17 00:00:00 2001 From: Paul Mathieu Date: Sun, 8 Jun 2025 23:11:04 -0700 Subject: [PATCH] mbv: now with DDR! and a wozmon We have access to 256 MiB of fresh DDR3. Isn't that great? prog.py is a bit opinionated for now: - tty is /dev/ttyUSB1 - writing programs to DDR --- mbv/Makefile | 4 + mbv/apps/fromddr.ld | 43 ++++++++++ mbv/apps/wozmon/wozmon.cc | 169 ++++++++++++++++++++++++++++++++++++++ mbv/configure | 11 ++- mbv/prog.py | 57 +++++++++++++ 5 files changed, 283 insertions(+), 1 deletion(-) create mode 100644 mbv/apps/fromddr.ld create mode 100644 mbv/apps/wozmon/wozmon.cc create mode 100644 mbv/prog.py diff --git a/mbv/Makefile b/mbv/Makefile index d8327da..c74145d 100644 --- a/mbv/Makefile +++ b/mbv/Makefile @@ -6,6 +6,10 @@ bootloader: ## Build the bootloader in docker helloworld: ## Build the helloworld app in docker docker build -o . --target export --build-arg TARGET=helloworld.bin . +.PHONY: wozmon +wozmon: ## Build the wozmon app in docker + docker build -o . --target export --build-arg TARGET=wozmon.bin . + .PHONY: dev-image dev-image: docker build -t mbv-dev --target dev . diff --git a/mbv/apps/fromddr.ld b/mbv/apps/fromddr.ld new file mode 100644 index 0000000..f62c61a --- /dev/null +++ b/mbv/apps/fromddr.ld @@ -0,0 +1,43 @@ +MEMORY +{ +/* RAM (rwx) : ORIGIN = 0x00000800, LENGTH = 14336 */ + RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 0x10000000 +} + +_vector_table = 0x0; + +SECTIONS +{ + .text : + { + _text_begin = .; + KEEP(*(.start)) + + *(.text*) + _text_end = .; + + *(.rodata*) + } > RAM + + .bss (NOLOAD) : + { + _bss_begin = .; + *(.bss*) + *(COMMON) + _bss_end = .; + } > RAM + + .data : + { + *(.data*) + + __exidx_start = .; + *(.exidx*) + __exidx_end = .; + } > RAM + + _heap_begin = .; + + _initial_stack_pointer = 16384; + _heap_end = _initial_stack_pointer - 1024; +} diff --git a/mbv/apps/wozmon/wozmon.cc b/mbv/apps/wozmon/wozmon.cc new file mode 100644 index 0000000..f37b3ad --- /dev/null +++ b/mbv/apps/wozmon/wozmon.cc @@ -0,0 +1,169 @@ +#include + +#include "xuartlite.h" + +struct Gpio { + volatile uint32_t data; +}; + +#define gpio0 ((Gpio*)0x40000000) + +namespace { +constexpr uintptr_t kUart0BaseAddress = 0x40600000; +XUartLite uart0_inst; +XUartLite_Config uart0_config = { + .DeviceId = 0, + .RegBaseAddr = kUart0BaseAddress, + .BaudRate = 115200, + .UseParity = false, + .DataBits = 8, +}; + +XUartLite* uart0 = &uart0_inst; + +void InitUarts() { + XUartLite_CfgInitialize(uart0, &uart0_config, uart0_config.RegBaseAddr); +} + +uint8_t UartRead() { + uint8_t c; + while (XUartLite_Recv(uart0, &c, 1) < 1) { + } + return c; +} + +void UartWrite(uint8_t c) { + XUartLite_Send(uart0, &c, 1); + while (XUartLite_IsSending(uart0)) {} +} + +void Jump(uint32_t addr) { + auto jump = reinterpret_cast(addr); + jump(); +} + +constexpr uint8_t kBackspace = 0x7f; +constexpr uint8_t kOtherBackspace = 0x08; + +uint8_t ReadHexNibble(uint8_t c) { + // lowercase only + if (c <= '9') { + return c - '0'; + } + return 10 + (c - 'a'); +} + +uint32_t ReadHex(const char* buf) { + uint32_t out = 0; + while (*buf == ' ') { + buf++; + } + for (int i = 0; i < 8; i++) { + uint8_t c = ReadHexNibble(*buf); + if (c > 0xf) { + break; + } + out = (out << 4) + c; + buf++; + } + + return out; +} + +void WriteHexNibble(uint8_t c) { + if (c > 9) { + UartWrite('a' + c - 10); + } else { + UartWrite('0' + c); + } +} + +void UartWriteUint32(uint32_t a) { + for (int i = 0; i < 8; i++) { + WriteHexNibble((a >> 28) & 0xf); + a <<= 4; + } +} + +void UartWriteUint8(uint8_t a) { + WriteHexNibble(a >> 4); + WriteHexNibble(a & 0xf); +} + +void UartDump(uint32_t addr, int count) { + for (int i = 0; i < count; i++) { + UartWrite(' '); + UartWriteUint8(*reinterpret_cast(addr + i)); + } +} + +void DumpHex(uint32_t addr) { + addr &= 0xfffffffc; + UartWriteUint32(addr); + UartWrite(':'); + UartDump(addr, 4); + UartWrite('\r'); + UartWrite('\n'); +} + +int FindChar(const char* buf, uint8_t c) { + int found = 0; + while (*buf) { + if (*buf == c) { + return found; + } + found++; + buf++; + } + return -1; +} + + +} // namespace + +int main() { + gpio0->data = 1; + uint32_t cur_addr = 0; + uint32_t cur_data = 0; + bool writing = false; + + char inbuf[64] = {}; + char* inptr = inbuf; + + InitUarts(); + + while (1) { + uint8_t c = UartRead(); + UartWrite(c); // echo + if (c == '\r') { + gpio0->data = 0x55; + *inptr = 0; + if (inptr == inbuf) { + cur_addr += 4; + } else if (FindChar(inbuf, 'r') >= 0) { + Jump(cur_addr); + } else { + cur_addr = ReadHex(inbuf); + UartWrite('\n'); + } + DumpHex(cur_addr); + int assigned = FindChar(inbuf, ':'); + if (assigned >= 0) { + cur_data = ReadHex(inbuf + assigned + 1); + *(reinterpret_cast(cur_addr)) = cur_data; + } + inptr = inbuf; + } else if (c == kBackspace) { + inptr--; + if (inptr < inbuf) { + inptr = inbuf; + continue; + } + UartWrite(kOtherBackspace); + UartWrite(' '); + UartWrite(kOtherBackspace); + } else { + *inptr++ = c; + } + } +} diff --git a/mbv/configure b/mbv/configure index 2016731..ad8c65c 100755 --- a/mbv/configure +++ b/mbv/configure @@ -253,6 +253,7 @@ hal = source_set("hal", [ bootloader = source_set("bootloader", glob.glob("./bootloader/**/*.cc", recursive=True)) helloworld = source_set("helloworld", glob.glob("./apps/helloworld/**/*.cc", recursive=True)) +wozmon = source_set("wozmon", glob.glob("./apps/wozmon/**/*.cc", recursive=True)) bootloader_image = build_image( bootloader, @@ -268,7 +269,15 @@ helloworld_image = build_image( bin_out="out/helloworld.bin", ) -all = [build_source_set(hal), bootloader_image, helloworld_image] +wozmon_image = build_image( + wozmon, + dependencies=[hal], + elf_out="out/wozmon.elf", + bin_out="out/wozmon.bin", + linker_script = "apps/fromddr.ld", +) + +all = [build_source_set(hal), bootloader_image, helloworld_image, wozmon_image] def parse_args(): diff --git a/mbv/prog.py b/mbv/prog.py new file mode 100644 index 0000000..3e14b00 --- /dev/null +++ b/mbv/prog.py @@ -0,0 +1,57 @@ +import serial +import struct +import sys +import time + +offset = 0x80000000 +tty = '/dev/ttyUSB1' +baud = 115200 +chunksize = 128 + + +def write(s, offset, dat): + for i in range(0, len(dat), chunksize): + chunk = dat[i: i + chunksize] + cmd = struct.pack(' 1.0: + print('Data timeout') + break + continue + last_dat = time.time() + sys.stdout.buffer.write(dat) + + +if __name__ == "__main__": + main()