%\begin{content}
\chapter{添加 micropython 解释器}
从 \href{http://svn.zmd.com/svn/一部软件库/公共模块/micropython-c6x}{micropython-c6x} SVN 仓库获取项目最新的源码。

在将源代码下的 \texttt{ports/c6x/lib/upy.c6x.ae66} 添加到 AppRun 工程下的 lib 目录。
并修改 module.cmd，添加一行：
\begin{minted}[bgcolor=lightgray!30,fontsize=\small]{c}
-l ../lib/upy.c6x.ae66
\end{minted}
%修改后的 module.cmd 内容如下：
%\begin{minted}[bgcolor=lightgray!30,fontsize=\scriptsize]{ini}
%-l ../lib/DrvUtils.lib
%-l ../lib/upy.c6x.ae66
%
%--diag_suppress=10068,10247
%--retain="*(.shellCommand)"
%
%SECTIONS
%{
%	.module_section: fill=0x0 align=0x4{
%		module_ver_start=.;
%		*(.module_section)
%		module_ver_end=.;
%	}>DDR_RAM
%
%    .dsp_cmd_section: fill = 0x0 align = 0x10 {
%         __console_cmd_start = .;
%         *(.dsp_cmd_section)
%         __console_cmd_end = .;
%    } >       DDR_RAM
%
%    .shell_command_section: fill = 0x0{
%         _shell_command_start = .;
%         *(.shellCommand)
%         _shell_command_end = .;
%    } >       DDR_RAM
%}
%\end{minted}

\section{最小移植需求}
在 AppRun 工程中新建一个文件 mp\_port.c, 添加如下内容:
\begin{minted}[bgcolor=lightgray!30,fontsize=\scriptsize]{c}
#include <stdint.h>
/* {{{: console */
int mp_tic6x_console_readable()
{
    return serialTstc();
}

int mp_tic6x_console_getc()
{
    return serialGetc();
}

void mp_tic6x_console_putn(const char *str, size_t len)
{
    while (len > 0) {
        serialPutc(*str++);
        --len;
    }
}
/* }}} */
\end{minted}
也可以通过实现 uart 的接口(mp\_tic6x\_uart\_readable, mp\_tic6x\_uart\_putc, mp\_tic6x\_uart\_getc) 中的第一个参数(uart\_id) 为-1时的功能来作为 REPL 的console。

在 AppRun.c 中添加 micropython 解释器的代码:
\begin{minted}[bgcolor=lightgray!30,fontsize=\scriptsize]{c}
/* {{{: upy interpreter */
void mp_tic6x_repl(unsigned char *, int len);
#define GC_HEAP_SIZE 0x400000
static unsigned char gc_heap[GC_HEAP_SIZE];

void AppRun(void)
{
    ...
    if (DNUM == 0) {
        ...
        mp_tic6x_repl(gc_heap, GC_HEAP_SIZE);
        ...
    }
}
/* }}} */
\end{minted}
这里 upy 的堆大小 GC\_HEAP\_SIZE 可根据实际需求进行修改。示例的代码中 0x400000 只起演示作用，不是硬性的大小限制。

\section{Flash 文件系统支持}
upy 库默认添加了 FAT 和 LFS 支持，可以在 mp\_port.c 添加如下类似代码，实现文件系统的支持：
\begin{minted}[bgcolor=lightgray!30,fontsize=\scriptsize]{c}
/* {{{ tic6x.Flash */
#define BLOCK_SIZE_BYTES             (0x20000)
#define BPI_FLASH_REGBASE            (0x70000000)

#ifndef MICROPY_HW_FLASH_STORAGE_BYTES
#define MICROPY_HW_FLASH_STORAGE_BYTES (0x200000)
#endif
#ifndef MICROPY_HW_FLASH_STORAGE_BASE
#define MICROPY_HW_FLASH_STORAGE_BASE (0x600000)
#endif

#define FLASH_START_ADDRESS            (BPI_FLASH_REGBASE + MICROPY_HW_FLASH_STORAGE_BASE)

extern int norFlashFifoProgram(unsigned int nAddr, const unsigned char *pBuffer, unsigned int len);

int mp_tic6x_flash_get_part_size(int part_id, unsigned int *blocks, unsigned int *block_size)
{
    int r = 0;

    if (part_id == 0) {
        *blocks = (MICROPY_HW_FLASH_STORAGE_BYTES) / BLOCK_SIZE_BYTES;
        *block_size = BLOCK_SIZE_BYTES;
    } else {
        r = -1;
    }
    return (r);
}

int mp_tic6x_flash_read(int part_id, unsigned int sect_start, unsigned int sect_off, 
                        void *buf, size_t size)
{
    unsigned char *srcbuf = (unsigned char *)(FLASH_START_ADDRESS);

    if (part_id != 0) {
        return -1;
    }

    srcbuf  += sect_start * BLOCK_SIZE_BYTES + sect_off;
    memcpy(buf, srcbuf, size);

    return 0;
}

int mp_tic6x_flash_erase(int part_id, unsigned int block_start, unsigned int nblocks)
{
    if (part_id != 0) {
        return -1;
    }
    return 0;
}

int mp_tic6x_flash_program(int part_id, unsigned int sect_start, 
                           unsigned int offset_in_sect, const void *buf, unsigned int size)
{
    int r = 0;
    unsigned int lba;

    if (part_id != 0) {
        r = -1;
        goto end;
    }

    lba = MICROPY_HW_FLASH_STORAGE_BASE + sect_start * BLOCK_SIZE_BYTES + offset_in_sect;
    r =  norFlashFifoProgram(lba, buf, size);
end:
    return (r);
}
/* }}} */
\end{minted}
解释器在进入 REPL 之前，会先后自动运行文件系统上的名为 \textcolor{blue}{\texttt boot.py} 和 \textcolor{blue}{\texttt main.py} 的脚本文件。

\section{系统功能支持}
设置系统主频，复位和设备ID，可以在  mp\_port.c 中添加下列实现:
\begin{minted}[bgcolor=lightgray!30,fontsize=\scriptsize]{c}
/* {{{ machine.unique_id() */
int mp_tic6x_unique_id(uint8_t *buf, int len)
{
    const char *board = getEnv("BOARD_INDEX");

    if (board) {
        size_t slen = strlen(board);
        if (slen > len)
            slen = len;
        memcpy(buf, board, slen);
        return (slen);
    }
    return 0;
}

void sysReboot();
void mp_tic6x_hard_reset(void)
{
    sysReboot();
}

unsigned int mp_tic6x_get_cpu_freq()
{
    return 1250000000UL;
}
/* }}} */
\end{minted}

\section{符号表支持}
如果需要在 upy 支持直接调用程序的全局函数，可对 AppRun 工程做一点微小的修改来实现。

将 ports/c6x/include/symtbl.h 复制到 AppRun 的 h/user 目录下。
将 ports/c6x/lib/symgen目录下的 symgen.exe 和 symgen.lar 复制到 AppRun 的 bin 目录下，并在 该目录下新建一个空的名为 builtins.txt \label{sec:builtin} 的文件（该文件的用途后面再讲）。
将 ports/c6x/lib/symgen 下的 makefile.targets 文件复制到 AppRun 工程的最上面：
\begin{table}[H]
    \centering
    \begin{tabular}{lcl}
        \toprule
        {\bf upy 工程} & & {\bf AppRun 工程} \\
        \midrule
        ports/c6x/include/symtbl.h & -> & h/user/symtbl.h \\
        ports/c6x/lib/symgen/symgen.exe & -> & bin/symgen.exe \\
        ports/c6x/lib/symgen/symgen.lar & -> & bin/symgen.lar \\
        ports/c6x/lib/symgen/makefile.targets & -> & makefile.targets \\
        &  new & bin/builtins.txt \\
        \bottomrule
    \end{tabular}
    \caption{symbol 支持工程文件}
\end{table}
如果有需要从符号表中排除一些接口，可以在 AppRun 的bin目录，创建一个名为 symgen.excl 的文件，将不需要的符号添加到该文件，
每行一个符号名。

文件添加后，AppRun 工程的文件如下图所示：
\begin{figure}[H]
    \centering
    \includegraphics[width=0.5\textwidth]{symgen}
    \caption{symgen 文件位置}
\end{figure}
图中的 symgen.lar 是 symgen.lua 用 lz4.exe 压缩得到的:
\begin{minted}[bgcolor=lightgray!30,fontsize=\small]{bash}
lz4.exe -9 symgen.lua symgen.lar 
\end{minted}
直接用 symgen.lua 文件也是可以的。

在 AppRun 工程上点击右键，分别选择 “Properties” => “Build” => “Behaviour”，将按下图红框所示进行配置：
\begin{figure}[H]
    \centering
    \includegraphics[width=0.9\textwidth]{builder}
    \caption{编译 appsym 目标}
\end{figure}

将添加了 micropython 解释器的工程最编译并烧写后，进入调试串口，看到如下类似打印：
\begin{minted}[bgcolor=lightgray!30,fontsize=\scriptsize]{python}
 MicroPython ff67efa on 2022-07-20; C66xx with TIC6X
 Type "help()" for more information.
 >>> 
\end{minted}
则移植成功。可以输入 help() 查看帮助，输入 help('modules') 查看所支持的 Python 模块。

%生成的 bootloader 文件是: \texttt{image/A/bootloader.bin} 。


%在项目源码工程的 Tools 目录下有适合本项目的交叉编译器 gcc-linaro-6.1.1-2016.08-x86\_64\_aarch64-linux-gnu.tar.xz。
%先将其解压到 U-Boot 源码目录，然后编译：
%\begin{minted}[bgcolor=lightgray!30,fontsize=\small]{c}
%> cd /path/to/ASAACFT2000M-BS1_BOOT
%> tar xvf gcc-linaro-6.1.1-2016.08-x86_64_aarch64-linux-gnu.tar.xz
%> ./run build u-boot
%\end{minted}
%生成的 bootloader 文件是: \texttt{image/A/bootloader.bin} 。
