Commits

Anonymous committed b2dd668

#185 mainlined directly

  • Participants
  • Parent commits b868134

Comments (0)

Files changed (1)

docs/src/HowToPortPyMite.txt

+.. Copyright 2009 Dean Hall
+   Permission is granted to copy, distribute and/or modify this document
+   under the terms of the GNU Free Documentation License, Version 1.2
+   or any later version published by the Free Software Foundation;
+   with no Invariant Sections, no Front-Cover Texts, and no Back-Cover
+   Texts.  A copy of the license is in the file docs/LICENSE.
+
+
+==================
+How To Port PyMite
+==================
+
+
+:Author:    Dean Hall
+:Id:        $Id$
+
+
+Purpose
+-------
+
+This document describes in a step-by-step manner how to port the PyMite
+interpreter to a new platform.  In doing so, it serves as a guide
+for the PyMite developer.
+
+
+Requirements
+------------
+
+The following is needed in order to port and compile PyMite to a new platform:
+
+- A C language toolchain (such as GCC) that includes the C compiler, assembler
+  and linker for the target platform.
+
+- A build system, preferably Make (preferably GNU Make) or Scons (www.scons.org).
+
+Starting from a sample project that configures the the communications
+peripheral serving as stdio (UART) and has a working build system (Makefile)
+is **highly recommended**.
+
+
+Porting
+-------
+
+Here is a step-by-step guide to porting PyMite to a new platform.
+
+- Copy an existing platform directory that most closely resembles the new target
+  platform.  For the rest of this document, the new directory is referred to as
+  ``<plat>``.  The core files needed for the port are ``main.c``, ``plat.c``
+  and ``Makefile``.  Other files that might be useful are `` main.py`` and
+  ``SConscript``.  Remove all the extraneous files.
+
+- Edit the build environment so that it builds the PyMite library,
+  ``../../vm/libpmvm_<plat>.a``, and links it to ``main.c``, ``plat.c``
+  and the native and image files that are generated by pmImgCreator.py
+  from your Python source code.  Below are example lines for a Makefile
+  that would be needed in addition to make a complete Makefile::
+
+      # PyMite: Configuration
+      PLATFORM := $(notdir $(CURDIR))
+      PM_LIB_ROOT = pmvm_$(PLATFORM)
+      PM_LIB_FN = lib$(PM_LIB_ROOT).a
+      PM_LIB_PATH = ../../vm/$(PM_LIB_FN)
+      PM_USR_SOURCES = main.py
+      PM_HEAP_SIZE = 0x3000
+      PMIMGCREATOR := ../../tools/pmImgCreator.py
+      PM_UART_BAUD = 19200
+      TARGET = main
+      SRC = $(TARGET).c plat.c $(TARGET)_nat.c $(TARGET)_img.c
+
+      # PyMite: CDEFS
+      CDEFS += -DHEAP_SIZE=$(PM_HEAP_SIZE) -DUART_BAUD=$(PM_UART_BAUD)
+      ifeq ($(DEBUG),true)
+          CDEFS += -g -gstabs -D__DEBUG__=1
+      endif
+
+      # Define the toolchain
+      CC = arm-elf-gcc
+      CPP = arm-elf-g++
+      OBJCOPY = arm-elf-objcopy
+      OBJDUMP = arm-elf-objdump
+      SIZE = arm-elf-size
+      AR = arm-elf-ar
+      NM = arm-elf-nm
+
+      # PyMite: Build the VM archive if it doesn't exist
+      pmvm : $(PM_LIB_PATH)
+
+      $(PM_LIB_PATH) :
+      	make -C ../../vm
+
+      # PyMite: Generate native code and module images from the python source
+      $(TARGET)_nat.c $(TARGET)_img.c : $(PM_USR_SOURCES)
+      	$(PMIMGCREATOR) -c -u -o $(TARGET)_img.c --native-file=$(TARGET)_nat.c $(PM_USR_SOURCES)
+
+      # PyMite: tell the compiler where to find pm.h and libpmvm_<plat>.a
+      CFLAGS += -I../../
+      LDFLAGS += -L../../vm -lpmvm_<plat>
+
+      # PyMite: Append pmvm to the list of .PHONY targets
+      .PHONY : pmvm
+
+      # PyMite: Export these env variables so the Makefile in ../../vm gets them
+      export CC OBJCOPY NM CFLAGS ALL_CFLAGS AR IPM PM_HEAP_SIZE PM_LIB_FN
+
+      # PyMite: Append these intermediate files to the list of things to clean
+      clean :
+          $(REMOVE) $(TARGET)_img.c
+          $(REMOVE) $(TARGET)_nat.c
+
+- Edit ``plat.c`` to replace ``#include`` statements with ones for the new
+  platform.  Edit the ``plat_init()`` function to enable the peripheral to be
+  used for PyMite's stdio (usually UART0).  If PyMite sys.time() or threading
+  is desired, also edit ``plat_init()`` to initialize a timer or other periodic
+  callback and the corresponding timer interrupt service routine (ISR) or
+  callback function.  The ISR or callback function simply needs to call
+  ``pm_vmPeriodic(<ms>);`` with an argument that is the number of milliseconds
+  that have passed since it was last called.
+
+- Edit the ``plat_memGetByte()`` function in ``plat.c`` to match the platform's
+  memory architecture.  A microcontroller that uses the von Neumann
+  architecture, such as ARM7TDMI, the RAM and program memory will use the same
+  kind of memory access. Here is an implementation for von Neumann
+  architectures::
+
+      uint8_t plat_memGetByte(PmMemSpace_t memspace, uint8_t const **paddr)
+      {
+          uint8_t b = 0;
+
+          switch (memspace)
+          {
+              case MEMSPACE_RAM:
+              case MEMSPACE_PROG:
+                  b = **paddr;
+                  *paddr += 1;
+                  return b;
+              /* Removed unused cases for brevity */
+          }
+      }
+
+  However, a microcontroller that uses the Harvard architecture, such as AVR,
+  might need an API call to read from the program memory.  Here is an
+  implementation for Harvard architecture with AVR-specific API::
+
+      uint8_t plat_memGetByte(PmMemSpace_t memspace, uint8_t const **paddr)
+      {
+          uint8_t b = 0;
+
+          switch (memspace)
+          {
+              case MEMSPACE_RAM:
+                  b = **paddr;
+                  *paddr += 1;
+                  return b;
+
+              case MEMSPACE_PROG:
+                  b = pgm_read_byte(*paddr);
+                  *paddr += 1;
+                  return b;
+              /* Unused cases removed for brevity */
+          }
+      }
+
+- Edit the ``plat_getByte()`` function in ``plat.c`` to read a byte from the
+  platform's designated stdio peripheral and return the byte by reference.
+  Follow the existing code to raise an exception if an I/O error occurs.
+
+- Edit the ``plat_putByte()`` function in ``plat.c`` to write a byte to the
+  platform's designated stdio peripheral.
+  Follow the existing code to raise an exception if an I/O error occurs.
+
+- Edit the ``plat_getMsTicks()`` function in ``plat.c`` to return, by reference,
+  the current number of milliseconds since system power-up (or reset if that is
+  preferred).  This function may either return ``pm_timerMsTicks`` which
+  requires that ``pm_vmPeriodic()`` be called faithfully, or it may fetch a
+  value from the platform's time-keeping system (such as a real time clock
+  peripheral).  The datatype holding the number of milliseconds is four bytes
+  (32 bits).  This means that it might be required to disable interrupts
+  while copying the value in order to avoid corruption; furthermore, PyMite
+  will experience system time "rollover" every 49 days (roughly).
+
+- Edit the ``plat_reportError()`` function in ``plat.c`` to report unhandled
+  exceptions and other incorrect return states.  A common method is to print
+  on stdout.  The ``desktop`` and ``avr`` platform implementations demonstrate
+  how to print the error status and a Python-like traceback on stdout.
+
+.. :mode=rest: