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
This commit is contained in:
parent
a5c14f089b
commit
fa6ae7b667
@ -6,6 +6,10 @@ bootloader: ## Build the bootloader in docker
|
|||||||
helloworld: ## Build the helloworld app in docker
|
helloworld: ## Build the helloworld app in docker
|
||||||
docker build -o . --target export --build-arg TARGET=helloworld.bin .
|
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
|
.PHONY: dev-image
|
||||||
dev-image:
|
dev-image:
|
||||||
docker build -t mbv-dev --target dev .
|
docker build -t mbv-dev --target dev .
|
||||||
|
43
mbv/apps/fromddr.ld
Normal file
43
mbv/apps/fromddr.ld
Normal file
@ -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;
|
||||||
|
}
|
169
mbv/apps/wozmon/wozmon.cc
Normal file
169
mbv/apps/wozmon/wozmon.cc
Normal file
@ -0,0 +1,169 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#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<void (*)()>(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<uint8_t*>(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<uint32_t*>(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
11
mbv/configure
vendored
11
mbv/configure
vendored
@ -253,6 +253,7 @@ hal = source_set("hal", [
|
|||||||
|
|
||||||
bootloader = source_set("bootloader", glob.glob("./bootloader/**/*.cc", recursive=True))
|
bootloader = source_set("bootloader", glob.glob("./bootloader/**/*.cc", recursive=True))
|
||||||
helloworld = source_set("helloworld", glob.glob("./apps/helloworld/**/*.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_image = build_image(
|
||||||
bootloader,
|
bootloader,
|
||||||
@ -268,7 +269,15 @@ helloworld_image = build_image(
|
|||||||
bin_out="out/helloworld.bin",
|
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():
|
def parse_args():
|
||||||
|
57
mbv/prog.py
Normal file
57
mbv/prog.py
Normal file
@ -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('<cII', b'c', offset + i, len(chunk))
|
||||||
|
|
||||||
|
print(f'Sending {len(chunk)} bytes @0x{offset + i:04x}')
|
||||||
|
|
||||||
|
s.write(cmd)
|
||||||
|
s.write(chunk)
|
||||||
|
|
||||||
|
ack = s.read(2)
|
||||||
|
if len(ack) < 2:
|
||||||
|
raise RuntimeError(f'timeout waiting for full ack. got {ack}')
|
||||||
|
if ack[0] != b'a'[0]:
|
||||||
|
raise RuntimeError(f'expected ack, got this instead: {ack}')
|
||||||
|
print(f'Ack! len={ack[1]}')
|
||||||
|
|
||||||
|
|
||||||
|
def jump(s, offset):
|
||||||
|
cmd = struct.pack('<cI', b'j', offset)
|
||||||
|
s.write(cmd)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
binfile = sys.argv[1]
|
||||||
|
with open(binfile, 'rb') as f:
|
||||||
|
dat = f.read()
|
||||||
|
|
||||||
|
s = serial.Serial(tty, baud, timeout=1)
|
||||||
|
write(s, offset, dat)
|
||||||
|
jump(s, offset)
|
||||||
|
last_dat = time.time()
|
||||||
|
|
||||||
|
while True:
|
||||||
|
dat = s.read()
|
||||||
|
if not dat:
|
||||||
|
if time.time() - last_dat > 1.0:
|
||||||
|
print('Data timeout')
|
||||||
|
break
|
||||||
|
continue
|
||||||
|
last_dat = time.time()
|
||||||
|
sys.stdout.buffer.write(dat)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in New Issue
Block a user