arm: working bootloader, example app
'make' will produce two outputs: - bootloader.elf to be loaded into the bitstream - app.bin to be loaded through the programmer Loading app.bin is as simple as: - reset the board - `python3 prog.py app.bin`
This commit is contained in:
parent
43d245bae2
commit
b8b0d94065
34
arm/app.ld
Normal file
34
arm/app.ld
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
MEMORY
|
||||||
|
{
|
||||||
|
ICTM (rwx) : ORIGIN = 0x00000800, LENGTH = 12228
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
KEEP(*(.app_init))
|
||||||
|
|
||||||
|
*(.text*)
|
||||||
|
*(.rodata*)
|
||||||
|
} > ICTM
|
||||||
|
|
||||||
|
.bss (NOLOAD) :
|
||||||
|
{
|
||||||
|
_bss_begin = .;
|
||||||
|
*(.bss*)
|
||||||
|
*(COMMON)
|
||||||
|
_bss_end = .;
|
||||||
|
} > ICTM
|
||||||
|
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.data*)
|
||||||
|
|
||||||
|
__exidx_start = .;
|
||||||
|
*(.exidx*)
|
||||||
|
__exidx_end = .;
|
||||||
|
} > ICTM
|
||||||
|
|
||||||
|
_initial_stack_pointer = 16384;
|
||||||
|
}
|
23
arm/app_init.cc
Normal file
23
arm/app_init.cc
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
extern "C" int main();
|
||||||
|
extern uint32_t _bss_begin, _bss_end, _initial_stack_pointer;
|
||||||
|
|
||||||
|
__attribute__((section(".app_init")))
|
||||||
|
void AppInit() {
|
||||||
|
*(uint32_t*)(0x40000000) = 0;
|
||||||
|
asm ("mov sp, %0"
|
||||||
|
:
|
||||||
|
: "r" (&_initial_stack_pointer)
|
||||||
|
:
|
||||||
|
);
|
||||||
|
|
||||||
|
// clear .bss
|
||||||
|
for (uint32_t* ptr = &_bss_begin; ptr < &_bss_end; ptr++) {
|
||||||
|
*ptr = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
|
||||||
|
while(true) {}
|
||||||
|
}
|
63
arm/bootloader.cc
Normal file
63
arm/bootloader.cc
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "gpio.h"
|
||||||
|
#include "uart.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t UartRead32() {
|
||||||
|
uint32_t val = 0;
|
||||||
|
|
||||||
|
// little endian
|
||||||
|
val |= (UartRead() << 0);
|
||||||
|
val |= (UartRead() << 8);
|
||||||
|
val |= (UartRead() << 16);
|
||||||
|
val |= (UartRead() << 24);
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
gpio0->data = 1;
|
||||||
|
|
||||||
|
InitUarts();
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
uint8_t c = UartRead();
|
||||||
|
if (c == 'c') {
|
||||||
|
uint32_t addr = UartRead32();
|
||||||
|
uint32_t bytes = UartRead32();
|
||||||
|
|
||||||
|
uint8_t* start = reinterpret_cast<uint8_t*>(addr);
|
||||||
|
uint8_t* end = reinterpret_cast<uint8_t*>(addr + bytes);
|
||||||
|
for (uint8_t* ptr = start; ptr < end; ptr++) {
|
||||||
|
*ptr = UartRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
UartWrite('a');
|
||||||
|
UartWrite(bytes);
|
||||||
|
gpio0->data = 0xf0;
|
||||||
|
} else if (c == 'j') {
|
||||||
|
uint32_t addr = UartRead32();
|
||||||
|
|
||||||
|
gpio0->data = 0x55;
|
||||||
|
|
||||||
|
addr |= 0x0001;
|
||||||
|
|
||||||
|
auto jump = reinterpret_cast<void(*)()>(addr);
|
||||||
|
jump();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
MEMORY
|
MEMORY
|
||||||
{
|
{
|
||||||
ICTM (rwx) : ORIGIN = 0x00000000, LENGTH = 16384
|
ICTM (rwx) : ORIGIN = 0x00000000, LENGTH = 2048
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
@ -30,5 +30,5 @@ SECTIONS
|
|||||||
__exidx_end = .;
|
__exidx_end = .;
|
||||||
} > ICTM
|
} > ICTM
|
||||||
|
|
||||||
_initial_stack_pointer = 16384;
|
_initial_stack_pointer = 2048;
|
||||||
}
|
}
|
||||||
|
9
arm/gpio.h
Normal file
9
arm/gpio.h
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
struct Gpio {
|
||||||
|
volatile uint32_t data;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define gpio0 ((Gpio*) 0x40000000)
|
51
arm/main.cc
51
arm/main.cc
@ -1,30 +1,12 @@
|
|||||||
#include <cstdint>
|
#include "gpio.h"
|
||||||
|
|
||||||
#include "xuartlite.h"
|
|
||||||
|
|
||||||
struct Gpio {
|
|
||||||
volatile uint32_t data;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define gpio0 ((Gpio*) 0x40000000)
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constexpr uintptr_t kUart0BaseAddress = 0x40001000;
|
|
||||||
XUartLite uart0;
|
|
||||||
XUartLite_Config uart0_config = {
|
|
||||||
.DeviceId = 0,
|
|
||||||
.RegBaseAddr = kUart0BaseAddress,
|
|
||||||
.BaudRate = 115200,
|
|
||||||
.UseParity = false,
|
|
||||||
.DataBits = 8,
|
|
||||||
};
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
void sleep(int ms) {
|
void sleep(int ms) {
|
||||||
for (int i = 0; i < ms; i++) {
|
for (int i = 0; i < ms; i++) {
|
||||||
// sleep for 1 ms
|
// sleep for 1 ms
|
||||||
for (int j = 0; j < 50000; j++) {
|
for (int j = 0; j < 22000; j++) {
|
||||||
asm("");
|
asm("");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -32,24 +14,19 @@ void sleep(int ms) {
|
|||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
int main() {
|
extern "C" int main() {
|
||||||
int recv = 0;
|
uint8_t cnt = 0;
|
||||||
gpio0->data = 37;
|
|
||||||
|
|
||||||
XUartLite_CfgInitialize(&uart0, &uart0_config, uart0_config.RegBaseAddr);
|
for (int i = 0; i < 256; i++) {
|
||||||
|
gpio0->data = cnt;
|
||||||
|
cnt++;
|
||||||
|
|
||||||
while (true) {
|
sleep(125);
|
||||||
uint8_t c;
|
|
||||||
int received_bytes = XUartLite_Recv(&uart0, &c, 1);
|
|
||||||
if (received_bytes < 1) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
recv++;
|
|
||||||
gpio0->data = recv & 0xff;
|
|
||||||
XUartLite_Send(&uart0, &c, 1);
|
|
||||||
if (c == '\r') {
|
|
||||||
c = '\n';
|
|
||||||
XUartLite_Send(&uart0, &c, 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto* airc = reinterpret_cast<volatile uint32_t*>(0xe000ed0c);
|
||||||
|
uint32_t a = *airc;
|
||||||
|
*airc = a | 0x04;
|
||||||
|
|
||||||
|
while (1) {}
|
||||||
}
|
}
|
16
arm/makefile
16
arm/makefile
@ -11,7 +11,7 @@ CFLAGS = -march=armv6-m -g -ffunction-sections -fdata-sections -O2 -Werror -Wall
|
|||||||
CXXFLAGS = $(CFLAGS) -std=c++20 -fno-exceptions
|
CXXFLAGS = $(CFLAGS) -std=c++20 -fno-exceptions
|
||||||
LDFLAGS = -march=armv6-m \
|
LDFLAGS = -march=armv6-m \
|
||||||
-g --specs=nano.specs --specs=nosys.specs \
|
-g --specs=nano.specs --specs=nosys.specs \
|
||||||
-Wl,--gc-sections -Wl,-T$(linker_script) -O2 \
|
-Wl,--gc-sections -O2 \
|
||||||
-Wl,--print-memory-usage
|
-Wl,--print-memory-usage
|
||||||
|
|
||||||
sources += hal/lib/common/xil_assert.c
|
sources += hal/lib/common/xil_assert.c
|
||||||
@ -20,21 +20,25 @@ includes += -Ihal/lib/common
|
|||||||
sources += hal/uart/xuartlite.c hal/uart/xuartlite_stats.c
|
sources += hal/uart/xuartlite.c hal/uart/xuartlite_stats.c
|
||||||
includes += -Ihal/uart
|
includes += -Ihal/uart
|
||||||
|
|
||||||
objects = main.o vector_table.o $(sources:.c=.o)
|
bootloader_objects = uart.o bootloader.o vector_table.o $(sources:.c=.o)
|
||||||
|
app_objects = app_init.o main.o
|
||||||
|
|
||||||
CFLAGS += $(includes)
|
CFLAGS += $(includes)
|
||||||
|
|
||||||
all: bootloader.elf
|
all: bootloader.elf app.bin
|
||||||
|
|
||||||
%.bin: %.elf
|
%.bin: %.elf
|
||||||
$(OBJCOPY) -O binary $< $@
|
$(OBJCOPY) -O binary $< $@
|
||||||
|
|
||||||
bootloader.elf: $(objects)
|
bootloader.elf: $(bootloader_objects)
|
||||||
|
$(LD) -Wl,-Tbootloader.ld $(LDFLAGS) -o $@ $^
|
||||||
|
|
||||||
|
app.elf: $(app_objects)
|
||||||
|
|
||||||
%.elf:
|
%.elf:
|
||||||
$(LD) $(LDFLAGS) -o $@ $^
|
$(LD) -Wl,-Tapp.ld $(LDFLAGS) -o $@ $^
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf *.elf *.bin $(objects)
|
rm -rf *.elf *.bin $(app_objects) $(bootloader_objects)
|
||||||
|
47
arm/prog.py
Normal file
47
arm/prog.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import serial
|
||||||
|
import struct
|
||||||
|
import sys
|
||||||
|
|
||||||
|
offset = 0x800
|
||||||
|
tty = 'tty'
|
||||||
|
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):
|
||||||
|
addr = struct.pack('<I', offset)
|
||||||
|
|
||||||
|
s.write(b'j')
|
||||||
|
s.write(addr)
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
21
arm/uart.cc
Normal file
21
arm/uart.cc
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
#include "uart.h"
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
constexpr uintptr_t kUart0BaseAddress = 0x40001000;
|
||||||
|
XUartLite uart0_inst;
|
||||||
|
XUartLite_Config uart0_config = {
|
||||||
|
.DeviceId = 0,
|
||||||
|
.RegBaseAddr = kUart0BaseAddress,
|
||||||
|
.BaudRate = 115200,
|
||||||
|
.UseParity = false,
|
||||||
|
.DataBits = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
XUartLite* uart0 = &uart0_inst;
|
||||||
|
|
||||||
|
void InitUarts() {
|
||||||
|
XUartLite_CfgInitialize(uart0, &uart0_config, uart0_config.RegBaseAddr);
|
||||||
|
}
|
7
arm/uart.h
Normal file
7
arm/uart.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "xuartlite.h"
|
||||||
|
|
||||||
|
extern XUartLite* uart0;
|
||||||
|
|
||||||
|
void InitUarts();
|
Loading…
Reference in New Issue
Block a user