I suddenly thought of it, so I tried it.
Bring the forked one on GitHub and make a branch.
git clone [email protected]:ysat0/micropython.git
cd micropython
git checkout -b rx
Get a rough overview. First of all, find the CPU-dependent part because it should work for the time being.
$ ls
ACKNOWLEDGEMENTS CONTRIBUTING.md docs/ extmod/ mpy-cross/ tests/
CODECONVENTIONS.md LICENSE drivers/ lib/ ports/ tools/
CODEOFCONDUCT.md README.md examples/ logo/ py/
Wild intuition told me to look at ports, so I will look there.
$ ls ports
bare-arm/ esp8266/ nrf/ qemu-arm/ teensy/ zephyr/
cc3200/ javascript/ pic16bit/ samd/ unix/
esp32/ minimal/ powerpc/ stm32/ windows/
It seems good to use minimal as a template, so copy it.
$ mkdir ports/rx
$ cp -R ports/minimal/* ports/rx
So I was able to put it on a cutting board.
Now that we have a template, we will seriously investigate what happens to the CPU-dependent parts.
$ ls ports/rx
Makefile frozentest.mpy main.c mphalport.h stm32f405.ld
README.md frozentest.py mpconfigport.h qstrdefsport.h uart_core.c
Some of them can be guessed by the file name, but I don't know where to fix it, so look inside and check the purpose.
file name | Use | Fix |
---|---|---|
Makefil | Makefile | To do |
README.md | Description | Does not matter |
frozentest.mpy | Result of byte compilation of ↓ | do not do |
frozentest.py | Test script | do not do |
main.c | Initialization+main | To do |
mpconfigport.h | Various settings | To do |
mphalport.h | Definition of hardware-dependent functions | You don't have to |
qstrdefsport.h | Special definition of qstr type | do not do |
stm32f405.ld | LD script | To do |
uart_core.c | UART input / output | To do |
You don't have to fix it so much.
So, when I thought about fixing it, I noticed a serious problem that I did not prepare a development environment (because it is not usually for baremetal), so I will prepare it first. It uses a normal rx-elf toolchain (binutils + gcc + newlib), so build it yourself or use KPIT's.
I want to run it with qemu for the time being, so I will match it with the hardware emulating qemu. The specifications of qemu are
However, this time I will not use the external memory, but only the CPU built-in memory.
Fix it as shown in the table above. main.c The original code is included in main.c, such as reset processing, but the part written in assembler is easier to put in .s, so it is decomposed into crt0.s and main.c.
crt0.s
.global _start
.section ".vector","ax"
.long _start
.text
_start:
mov #_estack, r0
mov #_sdata,r1
mov #_edata,r3
sub r1,r3
mov #_etext,r2
smovf
mov #_sbss,r1
mov #_ebss,r3
sub r1,r3
mov #0,r2
sstr
bsr _rx62n_init
sub r1,r1
sub r2,r2
bsr _main
bra .
.end
It is simply the flow of DATA / BSS initialization → hardware initialization → main. There are many more vector tables, but since they shouldn't be called if there is nothing, only the reset part is registered.
main.c
(Abbreviation)
#define SCKCR 0x00080020
#define MSTPCRB 0x00080014
#define SCR0 0x00088242
#define SMR0 0x00088240
#define BRR0 0x00088241
void rx62n_init(void) {
/* CPG Initialize */
/* XTAL:12MHz, ICLK:96MHz (x8), PCLK:48MHz (x4) */
*((volatile unsigned long *)SCKCR) = 0x00010100;
/* SCI0 enable */
*((volatile unsigned long *)MSTPCRB) &= ~0x80000000;
/* SCI0 Initialize */
*((volatile unsigned char *)SCR0) = 0x00;
*((volatile unsigned char *)SMR0) = 0x01;
*((volatile unsigned char *)BRR0) = 39; /* 9600 bps */
*((volatile unsigned char *)SCR0) = 0x30;
}
Same as the original main.c except for hardware initialization. This is also the minimum initialization. There is no initialization in uart_core for some reason, so I initialize it here. By the way, writing in C is the reason why writing in assembler is troublesome.
mpconfigport Appropriate because I'm not sure which setting affects where. This is also the minimum necessary modification.
mpconfigport.h
(Abbreviation)
#define MICROPY_HW_BOARD_NAME "minimal"
#define MICROPY_HW_MCU_NAME "Renesas RX"
#ifdef __linux__
#define MICROPY_MIN_USE_STDOUT (1)
#endif
#ifdef __RX__
#define MICROPY_MIN_USE_RX_CPU (1)
#endif
There is ~ THUMB on the upper side, but it seems to be invalid, so I leave it as it is.
uart_core.c Responsible for low-level I / O for dialogue. As I wrote above, for some reason there is no initialization part, only the actual input / output.
uart_core.c
#include <unistd.h>
#include "py/mpconfig.h"
/*
* Core UART functions to implement for a port
*/
#if MICROPY_MIN_USE_RX_CPU
#define TDR0 0x00088243
#define SSR0 0x00088244
#define RDR0 0x00088245
#define SSR_TDRE (1 << 7)
#define SSR_RDRF (1 << 6)
#endif
// Receive single character
int mp_hal_stdin_rx_chr(void) {
unsigned char c = 0;
#if MICROPY_MIN_USE_STDOUT
int r = read(0, &c, 1);
(void)r;
#elif MICROPY_MIN_USE_RX_CPU
// wait for RDRF
while ((*(volatile unsigned char *)SSR0 & SSR_RDRF) == 0) {
}
c = *(volatile unsigned char *)RDR0;
#endif
return c;
}
// Send string of given length
void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len) {
#if MICROPY_MIN_USE_STDOUT
int r = write(1, str, len);
(void)r;
#elif MICROPY_MIN_USE_RX_CPU
while (len--) {
// wait for TDRE
while ((*(volatile unsigned char *)SSR0 & SSR_TDRE) == 0) {
}
*(volatile unsigned char *)TDR0 = *str++;
}
#endif
}
This is hardware dependent, so I'm rewriting it. However, the usage of UART is almost the same, so it doesn't change so much.
ldscript As expected, stm32 ~ is confusing, so I will change the name. This is also hardware dependent, so I'll fix it. That said, it's not too much of a hassle as it just allocates text / data / bss to the internal memory properly. If you want to run it with R5F562N7, which is widely available in the world, you should fix FLASH and RAM appropriately.
rx62n.ld
/*
GNU linker script for RX62N
*/
/* Specify the memory areas */
MEMORY
{
FLASH (rx) : ORIGIN = 0xfff80000, LENGTH = 0x00080000 - 0x4 /* 512 KiB
*/
VECTOR (r) : ORIGIN = 0xfffffffc, LENGTH = 0x0000004
RAM (xrw) : ORIGIN = 0x00000000, LENGTH = 0x00018000 /* 96 KiB */
}
/* top end of the stack */
_estack = ORIGIN(RAM) + LENGTH(RAM);
/* define output sections */
SECTIONS
{
/* The program code and other data goes into FLASH */
.text :
{
. = ALIGN(4);
*(.text.startup)
*(P)
*(C)
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
_etext = .; /* define a global symbol at end of code */
_sidata = _etext; /* This is used by the startup in order to initialize the .data secion */
} >FLASH
.vector :
{
*(.vector)
} > VECTOR
/* This is the initialized data section
The program executes knowing that the data is in the RAM
but the loader puts the initial values in the FLASH (inidata).
It is one task of the startup to copy the initial values from FLASH to RAM.
*/
.data : AT ( _sidata )
{
. = ALIGN(4);
_sdata = .; /* create a global symbol at data start; used by startup code in order to initialise the .data section in RAM */
*(D*) /* .data* sections */
. = ALIGN(4);
_edata = .; /* define a global symbol at data end; used by startup code in order to initialise the .data section in RAM */
} >RAM
/* Uninitialized data section */
.bss :
{
. = ALIGN(4);
_sbss = .; /* define a global symbol at bss start; used by startup code */
*(B*)
*(COMMON)
. = ALIGN(4);
_ebss = .; /* define a global symbol at bss end; used by startup code */
} >RAM
}
By the way, the unique section name is the rx-elf specification. However, the fact that the response is halfway is troublesome.
Makefile Change build options or add crt0. I thought I'd do it, but I was asked for setjmp / longjmp, so I linked libc easily. If it was about setjmp, I could have prepared it myself, but it was troublesome to look up the definition of jmpbuf, so this happened.
include ../../py/mkenv.mk
CROSS = 0
TARGET = mpython
# qstr definitions (must come before including py.mk)
QSTR_DEFS = qstrdefsport.h
# include py core make definitions
include $(TOP)/py/py.mk
ifeq ($(CROSS), 1)
CROSS_COMPILE ?= rx-elf-
endif
INC += -I.
INC += -I$(TOP)
INC += -I$(BUILD)
ifeq ($(CROSS), 1)
CFLAGS_RX = -fsingle-precision-constant -Wdouble-promotion
CFLAGS = $(INC) -Wall -Werror -std=c99 -nostdlib $(CFLAGS_RX) $(COPT)
LIBC = $(shell $(CROSS_COMPILE)gcc -print-file-name=libc.a)
LDFLAGS = -T rx62n.ld [email protected] -L $(dir $(LIBC))
else
CFLAGS = -m32 $(INC) -Wall -Werror -std=c99 $(COPT)
LDFLAGS = -m32 -Wl,[email protected],--cref -Wl,--gc-sections
endif
CSUPEROPT = -Os # save some code space
# Tune for Debugging or Optimization
ifeq ($(DEBUG), 1)
CFLAGS += -O0 -ggdb
else
CFLAGS += -Os -DNDEBUG
endif
LIBS = -l c
SRC_C = \
main.c \
uart_core.c \
lib/utils/printf.c \
lib/utils/stdout_helpers.c \
lib/utils/pyexec.c \
lib/libc/string0.c \
lib/mp-readline/readline.c \
$(BUILD)/_frozen_mpy.c
SRC_S = crt0.s
OBJ = $(PY_CORE_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o)) $(addprefix $(BUILD)/, $(SRC_S:.s=.o))
ifeq ($(CROSS), 1)
all: $(BUILD)/$(TARGET).bin
else
all: $(BUILD)/$(TARGET).elf
endif
$(BUILD)/_frozen_mpy.c: frozentest.mpy $(BUILD)/genhdr/qstrdefs.generated.h
$(ECHO) "MISC freezing bytecode"
$(Q)$(TOP)/tools/mpy-tool.py -f -q $(BUILD)/genhdr/qstrdefs.preprocessed.h -mlongint-impl=none $< > $@
$(BUILD)/$(TARGET).elf: $(OBJ)
$(ECHO) "LINK $@"
$(Q)$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
$(Q)$(SIZE) $@
$(BUILD)/$(TARGET).bin: $(BUILD)/$(TARGET).elf
$(Q)$(OBJCOPY) -O binary -j .vector -j .text -j .data $^ $@
$(BUILD)/$(TARGET).srec: $(BUILD)/$(TARGET).elf
$(Q)$(OBJCOPY) -O srec -j .vector -j .text -j .data $^ $@
include $(TOP)/py/mkrules.mk
After that, I thought that deploy would be left, but I didn't need it separately for qemu, and I deleted it because there was no suitable writing program from make. I remembered that, but there is this, so if you really want to use it, please use it (promote it) Keep it).
Obediently
make cross=1
You can make it with.
Now that it's done, let's move it.
qemu-system-rx -bios build/mpyton.bin
Start with and switch the screen to the serial port![Start.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316355/1e891cb0-37a4-f9e6 -639a-5dc4a33328b5.png)
Something is working, and if you enter it properly,![Print.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316355/076e4079-0cd8-8495 -7206-9a2098799ad2.png)
I'll get a proper reply, so maybe it will work as it should.
# end
So, if you move it for the time being, it's pretty easy to do.
Maybe time to fix the code <time to prepare the development environment.
I think I have to prepare more drivers so that I can use it properly, but I was satisfied with the place where it worked with qemu, so the future schedule is undecided.