mbv: now with functioning timer interrupts!
And a few other nice things. The bootloader now has an embedded wozmon! If you know its offset, you can jump to it from the app.
This commit is contained in:
parent
fa6ae7b667
commit
3db383d461
@ -10,6 +10,10 @@ helloworld: ## Build the helloworld app in docker
|
||||
wozmon: ## Build the wozmon app in docker
|
||||
docker build -o . --target export --build-arg TARGET=wozmon.bin .
|
||||
|
||||
.PHONY: timer
|
||||
timer: ## Build the timer app in docker
|
||||
docker build -o . --target export --build-arg TARGET=timer.bin .
|
||||
|
||||
.PHONY: dev-image
|
||||
dev-image:
|
||||
docker build -t mbv-dev --target dev .
|
||||
|
@ -1,6 +1,6 @@
|
||||
MEMORY
|
||||
{
|
||||
RAM (rwx) : ORIGIN = 0x00000800, LENGTH = 14336
|
||||
RAM (rwx) : ORIGIN = 0x80000000, LENGTH = 0x10000000
|
||||
}
|
||||
|
||||
_vector_table = 0x0;
|
||||
@ -37,6 +37,6 @@ SECTIONS
|
||||
|
||||
_heap_begin = .;
|
||||
|
||||
_initial_stack_pointer = 16384;
|
||||
_heap_end = _initial_stack_pointer - 1024;
|
||||
_initial_stack_pointer = 0x90000000;
|
||||
_heap_end = 0x8f000000; /* leave 1M for the stack */
|
||||
}
|
||||
|
@ -1,43 +0,0 @@
|
||||
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;
|
||||
}
|
@ -1,10 +1,12 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "pol0.h"
|
||||
|
||||
struct Gpio {
|
||||
volatile uint32_t data;
|
||||
};
|
||||
|
||||
#define gpio0 ((Gpio*)0x40000000)
|
||||
#define gpio0 ((Gpio*)GPIO0_BASE)
|
||||
|
||||
void sleep(int ms) {
|
||||
for (int m = 0; m < ms; m++) {
|
||||
|
47
mbv/apps/timer/timer.cc
Normal file
47
mbv/apps/timer/timer.cc
Normal file
@ -0,0 +1,47 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "intc.h"
|
||||
#include "interrupts.h"
|
||||
#include "pol0.h"
|
||||
#include "timer.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct Gpio {
|
||||
volatile uint32_t data;
|
||||
};
|
||||
|
||||
Gpio* leds = reinterpret_cast<Gpio*>(GPIO0_BASE);
|
||||
Timer* timer;
|
||||
|
||||
}
|
||||
|
||||
void Timer0Isr() {
|
||||
static int counter = 0;
|
||||
leds->data = counter++;
|
||||
|
||||
timer->Pet();
|
||||
timer->ClearInterrupt();
|
||||
}
|
||||
|
||||
void SetupTimer() {
|
||||
timer = Timer::Instance(TIMER0_BASE);
|
||||
timer->SetupAsWdt(100'000'000);
|
||||
timer->EnableT1();
|
||||
|
||||
SetIsr(TIMER0_IRQN, Timer0Isr);
|
||||
SetIrqEnabled(TIMER0_IRQN, true);
|
||||
EnableInterrupts();
|
||||
}
|
||||
|
||||
int main() {
|
||||
leds->data = 0xa0;
|
||||
|
||||
SetupTimer();
|
||||
SetExternalInterruptHandler(InterruptHandler);
|
||||
EnableExternalInterrupts();
|
||||
|
||||
leds->data = 0xa1;
|
||||
|
||||
BiosWozmon();
|
||||
}
|
@ -125,7 +125,6 @@ int main() {
|
||||
gpio0->data = 1;
|
||||
uint32_t cur_addr = 0;
|
||||
uint32_t cur_data = 0;
|
||||
bool writing = false;
|
||||
|
||||
char inbuf[64] = {};
|
||||
char* inptr = inbuf;
|
||||
|
@ -1,19 +1,23 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "pol0.h"
|
||||
#include "xuartlite.h"
|
||||
|
||||
uint8_t UartRead();
|
||||
void UartWrite(uint8_t);
|
||||
|
||||
struct Gpio {
|
||||
volatile uint32_t data;
|
||||
};
|
||||
|
||||
#define gpio0 ((Gpio*)0x40000000)
|
||||
#define gpio0 ((Gpio*)GPIO0_BASE)
|
||||
|
||||
namespace {
|
||||
constexpr uintptr_t kUart0BaseAddress = 0x40600000;
|
||||
|
||||
XUartLite uart0_inst;
|
||||
XUartLite_Config uart0_config = {
|
||||
.DeviceId = 0,
|
||||
.RegBaseAddr = kUart0BaseAddress,
|
||||
.RegBaseAddr = UART0_BASE,
|
||||
.BaudRate = 115200,
|
||||
.UseParity = false,
|
||||
.DataBits = 8,
|
||||
@ -25,15 +29,6 @@ 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); }
|
||||
|
||||
uint32_t UartRead32() {
|
||||
uint32_t val = 0;
|
||||
|
||||
@ -45,8 +40,21 @@ uint32_t UartRead32() {
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
} // 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);
|
||||
while (XUartLite_IsSending(uart0)) {}
|
||||
}
|
||||
|
||||
int main() {
|
||||
gpio0->data = 1;
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
MEMORY
|
||||
{
|
||||
BLRAM (rwx) : ORIGIN = 0x00000000, LENGTH = 2048
|
||||
BLRAM (rwx) : ORIGIN = 0x00000000, LENGTH = 0x1000
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@ -30,5 +30,5 @@ SECTIONS
|
||||
__exidx_end = .;
|
||||
} > BLRAM
|
||||
|
||||
_initial_stack_pointer = 2048;
|
||||
_initial_stack_pointer = 0x1000;
|
||||
}
|
||||
|
132
mbv/bootloader/wozmon.cc
Normal file
132
mbv/bootloader/wozmon.cc
Normal file
@ -0,0 +1,132 @@
|
||||
#include <cstdint>
|
||||
|
||||
uint8_t UartRead();
|
||||
void UartWrite(uint8_t);
|
||||
|
||||
namespace {
|
||||
|
||||
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
|
||||
|
||||
__attribute__((used))
|
||||
void wozmon() {
|
||||
uint32_t cur_addr = 0;
|
||||
uint32_t cur_data = 0;
|
||||
|
||||
char inbuf[64] = {};
|
||||
char* inptr = inbuf;
|
||||
|
||||
while (1) {
|
||||
uint8_t c = UartRead();
|
||||
UartWrite(c); // echo
|
||||
if (c == '\r') {
|
||||
*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;
|
||||
}
|
||||
}
|
||||
}
|
38
mbv/configure
vendored
38
mbv/configure
vendored
@ -18,6 +18,7 @@ hostcflags = "-g -std=c++20 -fprofile-instr-generate -fcoverage-mapping"
|
||||
hostlibs = "-lgtest -lgmock -lgtest_main"
|
||||
hostldflags = "-fprofile-instr-generate -fcoverage-mapping"
|
||||
include_dirs = [
|
||||
"hal",
|
||||
"hal/uart",
|
||||
"hal/lib/common",
|
||||
]
|
||||
@ -31,7 +32,7 @@ common_flags = [
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-flto",
|
||||
"-march=rv32i",
|
||||
"-march=rv32i_zicsr",
|
||||
"-ffunction-sections",
|
||||
"-Oz",
|
||||
]
|
||||
@ -44,7 +45,7 @@ ldflags = [
|
||||
"-Wl,--gc-sections",
|
||||
"-Wl,--print-memory-usage",
|
||||
"-flto",
|
||||
"-march=rv32i",
|
||||
"-march=rv32i_zicsr",
|
||||
]
|
||||
|
||||
|
||||
@ -244,6 +245,8 @@ def make_coverage(binaries):
|
||||
|
||||
|
||||
hal = source_set("hal", [
|
||||
"hal/intc.cc",
|
||||
"hal/interrupts.cc",
|
||||
"hal/start.cc",
|
||||
"hal/lib/common/xil_assert.c",
|
||||
"hal/uart/xuartlite.c",
|
||||
@ -252,9 +255,6 @@ 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,
|
||||
dependencies=[hal],
|
||||
@ -262,22 +262,22 @@ bootloader_image = build_image(
|
||||
linker_script="bootloader/bootloader.ld",
|
||||
)
|
||||
|
||||
helloworld_image = build_image(
|
||||
helloworld,
|
||||
dependencies=[hal],
|
||||
elf_out="out/helloworld.elf",
|
||||
bin_out="out/helloworld.bin",
|
||||
)
|
||||
def app_image(app):
|
||||
return build_image(
|
||||
source_set(app, glob.glob(f"./apps/{app}/**/*.cc", recursive=True)),
|
||||
dependencies=[hal],
|
||||
elf_out=f"out/{app}.elf",
|
||||
bin_out=f"out/{app}.bin",
|
||||
)
|
||||
|
||||
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,
|
||||
|
||||
all = [build_source_set(hal), bootloader_image, helloworld_image, wozmon_image]
|
||||
app_image("helloworld"),
|
||||
app_image("wozmon"),
|
||||
app_image("timer"),
|
||||
]
|
||||
|
||||
|
||||
def parse_args():
|
||||
|
62
mbv/hal/intc.cc
Normal file
62
mbv/hal/intc.cc
Normal file
@ -0,0 +1,62 @@
|
||||
#include "intc.h"
|
||||
|
||||
#include "pol0.h"
|
||||
|
||||
namespace {
|
||||
|
||||
struct IntC {
|
||||
volatile uint32_t ISR;
|
||||
volatile uint32_t IPR;
|
||||
volatile uint32_t IER;
|
||||
volatile uint32_t IAR;
|
||||
volatile uint32_t SIE;
|
||||
volatile uint32_t CIE;
|
||||
volatile uint32_t IVR;
|
||||
volatile uint32_t MER;
|
||||
volatile uint32_t IMR;
|
||||
volatile uint32_t ILR;
|
||||
|
||||
// the rest is not enabled
|
||||
};
|
||||
|
||||
IntC* intc = reinterpret_cast<IntC*>(INTC_BASE);
|
||||
Isr isrs[NIRQ] = {};
|
||||
|
||||
}
|
||||
|
||||
bool SetIrqEnabled(uint8_t irqn, bool enabled) {
|
||||
uint32_t mask = 1 << irqn;
|
||||
uint32_t ier = intc->IER;
|
||||
bool was_enabled = (ier & (~mask)) > 0;
|
||||
if (enabled) {
|
||||
intc->IER = ier | mask;
|
||||
} else {
|
||||
intc->IER = ier & (~mask);
|
||||
}
|
||||
|
||||
return was_enabled;
|
||||
}
|
||||
|
||||
void SetIsr(uint8_t irqn, Isr isr) {
|
||||
isrs[irqn] = isr;
|
||||
}
|
||||
|
||||
void EnableInterrupts() {
|
||||
intc->MER = 0x3;
|
||||
}
|
||||
|
||||
void InterruptHandler() {
|
||||
uint32_t ipr = intc->IPR;
|
||||
|
||||
for (int i = 0; i < NIRQ; i++) {
|
||||
uint32_t mask = 1 << i;
|
||||
|
||||
if ((ipr & mask) > 0) {
|
||||
// interrupt pending
|
||||
if (isrs[i] != nullptr) {
|
||||
isrs[i]();
|
||||
}
|
||||
intc->IAR = mask; // ack
|
||||
}
|
||||
}
|
||||
}
|
16
mbv/hal/intc.h
Normal file
16
mbv/hal/intc.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
using Isr = void(*)(void);
|
||||
|
||||
/// Returns: true if the IRQ was previously enabled
|
||||
bool SetIrqEnabled(uint8_t irqn, bool enabled);
|
||||
|
||||
void SetIsr(uint8_t irqn, Isr isr);
|
||||
|
||||
// Call this once to enable all HW interrupts
|
||||
void EnableInterrupts();
|
||||
|
||||
// Feed this to the CPU's interrupt handler
|
||||
void InterruptHandler();
|
52
mbv/hal/interrupts.cc
Normal file
52
mbv/hal/interrupts.cc
Normal file
@ -0,0 +1,52 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include "interrupts.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t kMstatusMieMask = 1 << 3;
|
||||
constexpr uint32_t kMieExternalInterruptMask = 1 << 11;
|
||||
constexpr uint32_t kExternalInterruptCause = 0x0b;
|
||||
constexpr uint32_t kInterruptCauseMask = 0xff;
|
||||
|
||||
Isr external_handler = nullptr;
|
||||
|
||||
__attribute__((interrupt))
|
||||
void TrapHandler() {
|
||||
uint32_t mcause;
|
||||
uint32_t mip;
|
||||
asm volatile("csrr %0, mcause" : "=r"(mcause));
|
||||
asm volatile("csrr %0, mip" : "=r"(mip));
|
||||
|
||||
// check for external interrupt
|
||||
if ((mcause & kInterruptCauseMask) == kExternalInterruptCause) {
|
||||
if (external_handler != nullptr) {
|
||||
external_handler();
|
||||
}
|
||||
|
||||
mip &= ~(kMieExternalInterruptMask);
|
||||
asm volatile("csrw mip, %0" :: "r"(mip));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void SetExternalInterruptHandler(Isr handler) {
|
||||
external_handler = handler;
|
||||
}
|
||||
|
||||
void EnableExternalInterrupts() {
|
||||
uint32_t mstatus;
|
||||
uint32_t mie;
|
||||
Isr trap = TrapHandler;
|
||||
|
||||
asm volatile("csrr %0, mstatus" : "=r"(mstatus));
|
||||
asm volatile("csrr %0, mie" : "=r"(mie));
|
||||
|
||||
asm volatile("csrw mtvec, %0" :: "r"(trap));
|
||||
|
||||
mie |= kMieExternalInterruptMask;
|
||||
asm volatile("csrw mie, %0" :: "r"(mie));
|
||||
mstatus |= kMstatusMieMask;
|
||||
asm volatile("csrw mstatus, %0" :: "r"(mstatus));
|
||||
}
|
6
mbv/hal/interrupts.h
Normal file
6
mbv/hal/interrupts.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
using Isr = void(*)();
|
||||
|
||||
void SetExternalInterruptHandler(Isr handler);
|
||||
void EnableExternalInterrupts();
|
18
mbv/hal/pol0.h
Normal file
18
mbv/hal/pol0.h
Normal file
@ -0,0 +1,18 @@
|
||||
// Platform definitions for pol0
|
||||
|
||||
// LED output
|
||||
#define GPIO0_BASE (0x40000000)
|
||||
|
||||
// /dev/ttyUSB1
|
||||
#define UART0_BASE (0x40600000)
|
||||
|
||||
// Interrupt controller
|
||||
#define INTC_BASE (0x41200000)
|
||||
|
||||
// It's uh.. a timer.
|
||||
#define TIMER0_BASE (0x41c00000)
|
||||
|
||||
// IRQs
|
||||
#define UART0_IRQN (0)
|
||||
#define TIMER0_IRQN (1)
|
||||
#define NIRQ (2)
|
69
mbv/hal/timer.h
Normal file
69
mbv/hal/timer.h
Normal file
@ -0,0 +1,69 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
struct TimerControl {
|
||||
union {
|
||||
struct {
|
||||
uint32_t MDT0 : 1;
|
||||
uint32_t UDT0 : 1;
|
||||
uint32_t GENT0 : 1;
|
||||
uint32_t CAPT0 : 1;
|
||||
uint32_t ARHT0 : 1;
|
||||
uint32_t LOAD0 : 1;
|
||||
uint32_t ENIT0 : 1;
|
||||
uint32_t ENT0 : 1;
|
||||
uint32_t T0INT : 1;
|
||||
uint32_t PWMA0 : 1;
|
||||
uint32_t ENALL : 1;
|
||||
uint32_t CASC : 1;
|
||||
|
||||
uint32_t reserved : 20;
|
||||
};
|
||||
uint32_t raw;
|
||||
};
|
||||
};
|
||||
|
||||
struct Timer {
|
||||
volatile TimerControl TCSR0;
|
||||
volatile uint32_t TLR0;
|
||||
volatile uint32_t TCR0;
|
||||
|
||||
uint32_t _reserved;
|
||||
|
||||
volatile TimerControl TCSR1;
|
||||
volatile uint32_t TLR1;
|
||||
volatile uint32_t TCR1;
|
||||
|
||||
void EnableT1() {
|
||||
TCSR1.ARHT0 = 1;
|
||||
TCSR1.ENT0 = 1;
|
||||
}
|
||||
|
||||
uint32_t GetT1Ticks() { return TCR1; }
|
||||
|
||||
void SetupAsWdt(uint32_t timeout_ticks) {
|
||||
TLR0 = timeout_ticks;
|
||||
TCSR0.LOAD0 = 1; // reset counter
|
||||
TCSR0.UDT0 = 1; // count backwards from the load value
|
||||
TCSR0.ENIT0 = 1; // enable interrupt
|
||||
|
||||
TCSR0.LOAD0 = 0; // allow counter to run
|
||||
TCSR0.ENT0 = 1; // enable timer
|
||||
}
|
||||
|
||||
void Pet() {
|
||||
TCSR0.ENT0 = 0;
|
||||
TCSR0.LOAD0 = 1;
|
||||
TCSR0.LOAD0 = 0;
|
||||
TCSR0.ENT0 = 1;
|
||||
}
|
||||
|
||||
void ClearInterrupt() {
|
||||
TCSR0.T0INT = 0;
|
||||
}
|
||||
|
||||
static Timer* Instance(uint32_t base) {
|
||||
return reinterpret_cast<Timer*>(base);
|
||||
}
|
||||
};
|
44
mbv/prog.py
44
mbv/prog.py
@ -1,6 +1,8 @@
|
||||
import argparse
|
||||
import serial
|
||||
import struct
|
||||
import sys
|
||||
import threading
|
||||
import time
|
||||
|
||||
offset = 0x80000000
|
||||
@ -29,28 +31,46 @@ def write(s, offset, dat):
|
||||
|
||||
def jump(s, offset):
|
||||
cmd = struct.pack('<cI', b'j', offset)
|
||||
print(f'Jumping to 0x{offset:04x}')
|
||||
s.write(cmd)
|
||||
|
||||
|
||||
def stream_logs(s):
|
||||
while True:
|
||||
dat = s.read()
|
||||
if not dat:
|
||||
continue
|
||||
sys.stdout.buffer.write(dat.replace(b'\r', b''))
|
||||
sys.stdout.buffer.flush()
|
||||
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("binary")
|
||||
parser.add_argument("--monitor", action="store_true",
|
||||
help="wait for and display program serial output")
|
||||
return parser.parse_args()
|
||||
|
||||
def main():
|
||||
binfile = sys.argv[1]
|
||||
with open(binfile, 'rb') as f:
|
||||
args = parse_args()
|
||||
|
||||
with open(args.binary, '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 args.monitor:
|
||||
t = threading.Thread(target=lambda: stream_logs(s), daemon=True)
|
||||
t.start()
|
||||
|
||||
try:
|
||||
while True:
|
||||
dat = input("") + '\r'
|
||||
s.write(dat.encode())
|
||||
except KeyboardInterrupt:
|
||||
print("Bye.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
Loading…
Reference in New Issue
Block a user