Portage de MicroPython

J'y ai soudainement pensé, alors j'ai essayé.

Préparation

Apportez ce que vous avez fourché sur GitHub et créez même une branche.

git clone [email protected]:ysat0/micropython.git
cd micropython
git checkout -b rx

Obtenez un aperçu approximatif. Tout d'abord, trouvez la partie dépendante du processeur car elle devrait fonctionner pour le moment.

$ ls
ACKNOWLEDGEMENTS    CONTRIBUTING.md  docs/      extmod/  mpy-cross/  tests/
CODECONVENTIONS.md  LICENSE          drivers/   lib/     ports/      tools/
CODEOFCONDUCT.md    README.md        examples/  logo/    py/

Une intuition sauvage m'a dit de regarder les ports, alors je vais y regarder.

$ ls ports
bare-arm/  esp8266/     nrf/       qemu-arm/  teensy/   zephyr/
cc3200/    javascript/  pic16bit/  samd/      unix/
esp32/     minimal/     powerpc/   stm32/     windows/          

Il semble bon d'utiliser minimal comme modèle, alors copiez-le.

$ mkdir ports/rx
$ cp -R ports/minimal/* ports/rx

J'ai donc pu le mettre sur une planche à découper.

Regardez

Maintenant que nous avons préparé un modèle, nous allons étudier sérieusement ce qui arrive aux parties dépendant du processeur.

$ ls ports/rx 
Makefile   frozentest.mpy  main.c          mphalport.h     stm32f405.ld
README.md  frozentest.py   mpconfigport.h  qstrdefsport.h  uart_core.c

Certains peuvent être devinés par le nom du fichier, mais je ne sais pas où le réparer, alors regardez à l'intérieur et vérifiez le but.

nom de fichier Utilisation Réparer
Makefil Créer un fichier Faire
README.md La description N'a pas d'importance
frozentest.mpy Résultat de la compilation d'octets de ↓ ne pas faire
frozentest.py Script de test ne pas faire
main.c Initialisation+main Faire
mpconfigport.h Divers réglages Faire
mphalport.h Définition des fonctions dépendant du matériel Tu n'as pas à
qstrdefsport.h Définition spéciale du type qstr ne pas faire
stm32f405.ld Script LD Faire
uart_core.c Entrée / sortie UART Faire

Vous n'êtes pas obligé de le réparer autant.

Préparation de l'environnement de développement

Donc, quand j'ai pensé à le réparer, j'ai remarqué un problème sérieux que je n'avais pas préparé d'environnement de développement (car ce n'est généralement pas pour baremetal), donc je vais le préparer en premier. Il utilise une chaîne d'outils rx-elf normale (binutils + gcc + newlib), alors construisez-la vous-même ou utilisez KPIT.

Considérant la cible

Je veux l'exécuter avec qemu pour le moment, donc je vais le faire correspondre avec le matériel qui émule qemu. Les spécifications de qemu sont

Cependant, cette fois, je n'utiliserai pas la mémoire externe, mais uniquement la mémoire intégrée du processeur.

je le réparerai

Fixez-le comme indiqué dans le tableau ci-dessus. main.c Le code d'origine est également inclus dans main.c comme le traitement de réinitialisation, mais comme il est plus facile de mettre la pièce écrite dans l'assembleur directement dans .s, il est décomposé en crt0.s et 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

C'est simplement le flux d'initialisation DATA / BSS → initialisation matérielle → main. Il y a beaucoup plus de tables vectorielles, mais comme elles ne devraient pas être appelées s'il n'y a rien, seule la partie réinitialisée est enregistrée.

main.c


(Abréviation)
#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;
}

Identique au main.c d'origine, sauf pour l'initialisation matérielle. C'est également l'initialisation minimale. Pour une raison quelconque, uart_core n'a pas d'initialisation, donc je l'initialise ici. D'ailleurs, écrire en C est la raison pour laquelle écrire dans un assembleur est gênant.

mpconfigport Approprié car je ne sais pas quel paramètre affecte où. C'est aussi la modification minimale nécessaire.

mpconfigport.h


(Abréviation)
#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

Il y a ~ THUMB sur le côté supérieur, mais il semble être invalide, donc je le laisse tel quel.

uart_core.c Responsable des entrées / sorties de bas niveau pour le dialogue. Comme je l'ai écrit ci-dessus, il n'y a pas de partie d'initialisation pour une raison quelconque, et il n'y a qu'un endroit pour entrer et sortir.

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
}

Cela dépend du matériel, donc je le réécris. Cependant, l'utilisation d'UART est presque la même, donc cela ne change pas beaucoup.

ldscript Comme prévu, stm32 ~ est déroutant, je vais donc changer le nom. Cela dépend également du matériel, je vais donc le réparer. Cela dit, ce n'est pas trop compliqué car il alloue simplement text / data / bss à la mémoire interne correctement. Si vous voulez l'exécuter avec R5F562N7, qui est largement disponible dans le monde, vous devez corriger FLASH et RAM de manière appropriée.

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
}

Au fait, le nom de section unique est la spécification rx-elf. Cependant, le fait que la réponse soit à mi-chemin est gênant.

Makefile Modifiez les options de construction ou ajoutez crt0. J'ai pensé que je le ferais, mais on m'a demandé setjmp / longjmp, donc j'ai lié libc facilement. S'il s'agissait de setjmp, j'aurais pu le préparer moi-même, mais il était difficile de chercher la définition de jmpbuf, alors c'est arrivé.

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

Après cela, j'ai pensé que le déploiement serait laissé, mais je n'en avais pas besoin séparément pour qemu, et je l'ai supprimé car il n'y avait pas de programme d'écriture approprié de make. Je m'en suis souvenu, mais il y a ceci, donc si vous voulez vraiment l'utiliser, veuillez l'utiliser (en faire la publicité) Garde le).

Construire

Docilement make cross=1 Vous pouvez le faire avec.

Essayez de bouger

Maintenant que c'est fait, déplaçons-le.

qemu-system-rx -bios build/mpyton.bin


 Commencez par et basculez l'écran sur le port série![Start.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316355/1e891cb0-37a4-f9e6 -639a-5dc4a33328b5.png)
 Quelque chose fonctionne, et si vous le saisissez correctement, vous pouvez le saisir![Print.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/316355/076e4079-0cd8-8495 -7206-9a2098799ad2.png)
 J'obtiendrai une réponse appropriée, alors peut-être que cela fonctionnera comme il se doit.

# fin
 Donc, si vous le déplacez pour le moment, c'est assez facile à faire.
 Peut-être qu'il est temps de corriger le code <temps de préparer l'environnement de développement.
 Je pense que je dois préparer plus de pilotes pour pouvoir l'utiliser correctement, mais j'étais satisfait de l'endroit où cela fonctionnait avec qemu, donc le calendrier futur est indécis.


Recommended Posts

Portage de MicroPython
Architecture ARM »Portage