diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 720ba0c6..31d9a9f1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -37,10 +37,14 @@ jobs: cp projects/cm_mcu/gcc/cm_mcu.axf cm_mcu_noecn001_rev1.axf make clean REV1=1 make -k REV1=1 - cp projects/cm_mcu/gcc/cm_mcu.bin cm_mcu_rev1.bin - cp projects/cm_mcu/gcc/cm_mcu.axf cm_mcu_rev1.axf - cp projects/boot_loader/gcc/bl_main.bin bl_main_rev1.bin - cp projects/boot_loader/gcc/bl_main.axf bl_main_rev1.axf + mkdir REV1 + cp projects/cm_mcu/gcc/cm_mcu.bin REV1/cm_mcu_rev1.bin + cp projects/cm_mcu/gcc/cm_mcu.axf REV1/cm_mcu_rev1.axf + cp projects/boot_loader/gcc/bl_main.bin REV1/bl_main_rev1.bin + cp projects/boot_loader/gcc/bl_main.axf REV1/bl_main_rev1.axf + make release + mv PL_MEM_CM_rev1.xml REV1 + tar zcvpf cm_mcu_rev1.tar.gz REV1 - name: make with GCC for Rev2 run: | export PATH=${PATH}:$HOME/work/_temp/arm-none-eabi/bin: @@ -50,10 +54,14 @@ jobs: cp projects/cm_mcu/gcc/cm_mcu.axf cm_mcu_noecn001_rev2.axf make clean REV2=1 make -k REV2=1 - cp projects/cm_mcu/gcc/cm_mcu.bin cm_mcu_rev2.bin - cp projects/cm_mcu/gcc/cm_mcu.axf cm_mcu_rev2.axf - cp projects/boot_loader/gcc/bl_main.bin bl_main_rev2.bin - cp projects/boot_loader/gcc/bl_main.axf bl_main_rev2.axf + mkdir REV2 + cp projects/cm_mcu/gcc/cm_mcu.bin REV2/cm_mcu_rev2.bin + cp projects/cm_mcu/gcc/cm_mcu.axf REV2/cm_mcu_rev2.axf + cp projects/boot_loader/gcc/bl_main.bin REV2/bl_main_rev2.bin + cp projects/boot_loader/gcc/bl_main.axf REV2/bl_main_rev2.axf + make release + mv PL_MEM_CM_rev2.xml REV2 + tar zcvpf cm_mcu_rev2.tar.gz REV2 - name: test run: pwd; ls -R ; find . -type f -name '*.axf' -print - uses: "marvinpinto/action-automatic-releases@latest" @@ -61,5 +69,6 @@ jobs: repo_token: "${{ secrets.GITHUB_TOKEN }}" prerelease: false files: | - ./cm_mcu*.* - ./bl_main*.* + ./REV1/* + ./REV2/* + *.tar.gz diff --git a/.gitignore b/.gitignore index 7db1c8bc..20c60e81 100644 --- a/.gitignore +++ b/.gitignore @@ -63,3 +63,5 @@ c_cpp_properties.json /.metadata/ projects/cm_mcu/ZynqMon_addresses.c projects/cm_mcu/ZynqMon_addresses.h +PL_MEM_CM_rev1.xml +PL_MEM_CM_rev2.xml diff --git a/Makefile b/Makefile index 5effcf45..9d534072 100644 --- a/Makefile +++ b/Makefile @@ -35,5 +35,7 @@ check-and-reinit-submodules: git submodule update --init; \ fi +release: + @$(MAKE) -C projects/cm_mcu release .PHONY: all clean $(DIRS) $(DIRSCLEAN) check-and-reinit-submodules diff --git a/projects/cm_mcu/Makefile b/projects/cm_mcu/Makefile index 5a68e192..660d5f3b 100644 --- a/projects/cm_mcu/Makefile +++ b/projects/cm_mcu/Makefile @@ -82,7 +82,7 @@ all: ${COMPILER}/cm_mcu.axf # The rule to clean out all the build products. # clean: - @rm -rf ${COMPILER} ${wildcard *~} ZynqMon_addresses.c ZynqMon_addresses.h + @rm -rf ${COMPILER} ${wildcard *~} ZynqMon_addresses.c ZynqMon_addresses.h ${ROOT}/PL_MEM*.xml # # The rule to create the target directory. @@ -90,11 +90,32 @@ clean: ${COMPILER}: @mkdir -p ${COMPILER} - ## Zynq address table -- MCU code YAML_FILES=$(wildcard ${ROOT}/sm_cm_config/data/*.yml) +# +# for building tar files in a release +# +release: ${YAML_FILES} + @for f in ${YAML_FILES}; do \ + if [ 'x${VERBOSE}' = x ]; then \ + echo " PY $(notdir $$f)"; \ + else \ + echo ${ROOT}/sm_cm_config/src/xml_generate.py -d ${ROOT} $$f; \ + fi; \ + python ${ROOT}/sm_cm_config/src/xml_generate.py -d ${ROOT} $$f; \ + done + +# +# Zynq address table -- MCU code +# ZynqMon_addresses.c ZynqMon_addresses.h &: ${YAML_FILES} - python ${ROOT}/sm_cm_config/src/mcu_generate.py -o $@ ${YAML_FILES} + @if [ 'x${VERBOSE}' = x ]; \ + then \ + echo " PY $(notdir $?)"; \ + else \ + echo ${ROOT}/sm_cm_config/src/mcu_generate.py -o $@ ${YAML_FILES}; \ + fi + @python ${ROOT}/sm_cm_config/src/mcu_generate.py -o $@ ${YAML_FILES} # these rules are required to force the generation of the ZynqMon_addresses.c # and .h file. The second one depends on the .h file only, but putting that @@ -183,4 +204,4 @@ ifneq (${MAKECMDGOALS},clean) -include ${wildcard ${COMPILER}/*.d} __dummy__ endif -.PHONY: ${COMPILER} +.PHONY: ${COMPILER} release diff --git a/sm_cm_config/.gitignore b/sm_cm_config/.gitignore index ff9a1cb6..beec200c 100644 --- a/sm_cm_config/.gitignore +++ b/sm_cm_config/.gitignore @@ -134,4 +134,6 @@ dmypy.json # testing xml output src/test.xml +src/test2.xml .DS_Store +**/*.xml diff --git a/sm_cm_config/.pylintrc b/sm_cm_config/.pylintrc index e9f9d455..f24c2101 100644 --- a/sm_cm_config/.pylintrc +++ b/sm_cm_config/.pylintrc @@ -501,7 +501,7 @@ ignore-imports=yes ignore-signatures=yes #Minimum lines number of a similarity. -min-similarity-lines=4 +min-similarity-lines=10 [SPELLING] diff --git a/sm_cm_config/README.md b/sm_cm_config/README.md index f2bc504a..cda02165 100644 --- a/sm_cm_config/README.md +++ b/sm_cm_config/README.md @@ -1,2 +1,11 @@ -#sm_cm_config -Configuration files for SM and CM firmware +# sm_cm_config +Configuration file and code to generate the memory mapping between the MCU and the Zynq. Here we generate the C code used on the MCU which sends the data and the XML files used on the Zynq to interpret the data. + +On the MCU side, we define which addresses the MCU will send with the data. (python code `mcu_generate.py`) + +On the Zynq side, the XML files allow us to decode the memory on the zynq according to the data as laid out in the MCU. (python code `xml_generate.py`) + +The input files are in the `data` directory and are given by `zynqmon_.yaml` where `i` refers to the CM revision number. +There are two outputs: +1. The `C` code consists of a `c` and a header file. It is compiled into the MCU binary in the `cm_mcu` repo +1. The xml files must be included in the Zynq in ... (add directory info here) diff --git a/sm_cm_config/data/zynqmon_1.yml b/sm_cm_config/data/PL_MEM_CM_rev1.yml similarity index 100% rename from sm_cm_config/data/zynqmon_1.yml rename to sm_cm_config/data/PL_MEM_CM_rev1.yml diff --git a/sm_cm_config/data/zynqmon_2.yml b/sm_cm_config/data/PL_MEM_CM_rev2.yml similarity index 100% rename from sm_cm_config/data/zynqmon_2.yml rename to sm_cm_config/data/PL_MEM_CM_rev2.yml diff --git a/sm_cm_config/src/mcu_generate.py b/sm_cm_config/src/mcu_generate.py index b1ee276c..209dec10 100644 --- a/sm_cm_config/src/mcu_generate.py +++ b/sm_cm_config/src/mcu_generate.py @@ -1,9 +1,9 @@ +#! /usr/bin/env python """ Generate the C code for the microcontroller using the yaml files in the data directory""" import os import sys import argparse import subprocess - import yaml parser = argparse.ArgumentParser(description='Process YAML for MCU.') @@ -17,7 +17,7 @@ args = parser.parse_args() -if args.output: +if args.output and args.verbose: print('Output file name:', args.output) # sort the input file names.Default appears to be random(or order in the filesystem) @@ -118,12 +118,16 @@ # reformat the c file using clang-format # -style=file:$HOME/src/apollo_cm_mcu/.clang-format -r = subprocess.run(["clang-format", "-i", args.output], check=False) -if r.returncode != 0: - print('clang-format failed') - sys.exit(1) -if args.verbose: - print('clang-format complete') +# if the clang-format fails, we just ignore it +try: + r = subprocess.run(["clang-format", "-i", args.output], check=False) + if r.returncode != 0 and args.verbose: + print('clang-format failed') + if args.verbose: + print('clang-format complete') +except FileNotFoundError as e: + if args.verbose: + print(f"clang-format not found: {e}") # open output header file for writing. # first chekc that ZM_VALID_ENTRIES has exactly two entries diff --git a/sm_cm_config/src/test2.xml b/sm_cm_config/src/test2.xml deleted file mode 100644 index 425baf9f..00000000 --- a/sm_cm_config/src/test2.xml +++ /dev/null @@ -1,296 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sm_cm_config/src/xml_generate.ipynb b/sm_cm_config/src/xml_generate.ipynb index 76c12381..6b76cc62 100644 --- a/sm_cm_config/src/xml_generate.ipynb +++ b/sm_cm_config/src/xml_generate.ipynb @@ -1,11 +1,11 @@ { - "cells" : [ + "cells": [ { - "cell_type" : "code", - "execution_count" : 31, - "metadata" : {}, - "outputs" : [], - "source" : [ + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ "import yaml\n", "from pprint import pprint\n", "import xml.etree.ElementTree as ET\n", @@ -14,18 +14,20 @@ ] }, { - "cell_type" : "code", - "execution_count" : 32, - "metadata" : {}, - "outputs" : [], - "source" : ["verbose=False"] + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "verbose=False\n" + ] }, { - "cell_type" : "code", - "execution_count" : 33, - "metadata" : {}, - "outputs" : [], - "source" : [ + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ "with open('../data/zynqmon_2.yml') as f:\n", " y = yaml.load(f, Loader=yaml.FullLoader)\n", " if (verbose) :\n", @@ -33,11 +35,11 @@ ] }, { - "cell_type" : "code", - "execution_count" : 34, - "metadata" : {}, - "outputs" : [], - "source" : [ + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [], + "source": [ "def makeNode(parent: ET.Element, id: str, c: dict, addr2: int, parent_id: str) -> ET.Element:\n", " node = ET.SubElement(parent, 'node')\n", " id = id.replace(' ', '_')\n", @@ -93,11 +95,11 @@ ] }, { - "cell_type" : "code", - "execution_count" : 35, - "metadata" : {}, - "outputs" : [], - "source" : [ + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ "# This is the parent (root) tag\n", "# onto which other tags would be\n", "# created\n", @@ -107,11 +109,11 @@ ] }, { - "cell_type" : "code", - "execution_count" : 36, - "metadata" : {}, - "outputs" : [], - "source" : [ + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ "config = y['config']\n", "\n", "for c in config: # loop over entries in configuration (sensor category)\n", @@ -141,13 +143,13 @@ " else:\n", " start = c['start']\n", " makeNode(cm, n, c, start+i, \"\")\n", - " i += 1" + " i += 1\n" ] }, { - "cell_type" : "markdown", - "metadata" : {}, - "source" : [ + "cell_type": "markdown", + "metadata": {}, + "source": [ "config = y['config']\n", "\n", "for c in config: # loop over entries in configuration (sensor category)\n", @@ -208,16 +210,16 @@ ] }, { - "cell_type" : "markdown", - "metadata" : {}, - "source" : [] + "cell_type": "markdown", + "metadata": {}, + "source": [] }, { - "cell_type" : "code", - "execution_count" : 37, - "metadata" : {}, - "outputs" : [], - "source" : [ + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ "s_xml = ET.tostring(cm).decode()\n", "\n", "tree = ET.ElementTree(cm)\n", @@ -226,14 +228,14 @@ ] }, { - "cell_type" : "code", - "execution_count" : 38, - "metadata" : {}, - "outputs" : [ + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ { - "name" : "stdout", - "output_type" : "stream", - "text" : [ + "name": "stdout", + "output_type": "stream", + "text": [ "\n", "\n", " \n", @@ -437,22 +439,22 @@ ] } ], - "source" : [ + "source": [ "from bs4 import BeautifulSoup\n", "\n", "bs = BeautifulSoup(s_xml, 'xml')\n", "pretty_xml = bs.prettify()\n", "with open(\"test.xml\", \"w\") as f:\n", " print(pretty_xml, file=f)\n", - "print(pretty_xml)" + "print(pretty_xml)\n" ] }, { - "cell_type" : "code", - "execution_count" : 39, - "metadata" : {}, - "outputs" : [], - "source" : [ + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [], + "source": [ "def calcSize(c: dict) -> int:\n", " if 'size' in c:\n", " size = c['size']*2 # extra factor of 2 for 16 to 32 bit\n", @@ -466,14 +468,14 @@ ] }, { - "cell_type" : "code", - "execution_count" : 40, - "metadata" : {}, - "outputs" : [ + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ { - "name" : "stdout", - "output_type" : "stream", - "text" : [ + "name": "stdout", + "output_type": "stream", + "text": [ "[name: firefly start: 0 end: 19 size: 20,\n", " name: psmon start: 32 end: 115 size: 84,\n", " name: adcmon start: 128 end: 148 size: 21,\n", @@ -485,7 +487,7 @@ ] } ], - "source" : [ + "source": [ "# check overlaps\n", "# create an object with a name, and a start end end register\n", "# do so for every entry\n", @@ -536,41 +538,40 @@ "for i in range(len(entries)):\n", " for j in range(i+1, len(entries)):\n", " if entries[i].overlaps(entries[j]):\n", - " print(f\"{entries[i].name} overlaps with {entries[j].name}\")\n", - "\n" + " print(f\"{entries[i].name} overlaps with {entries[j].name}\")\n" ] }, { - "cell_type" : "code", - "execution_count" : null, - "metadata" : {}, - "outputs" : [], - "source" : [] + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], - "metadata" : { - "interpreter" : { - "hash" : "d1bcf2015140efba1309a3b878c8a09b28a5da1fac13dcbb304588e5a25844fe" - }, - "kernelspec" : { - "display_name" : "Python 3.8.12 ('base')", - "language" : "python", - "name" : "python3" - }, - "language_info" : { - "codemirror_mode" : { - "name" : "ipython", - "version" : 3 - }, - "file_extension" : ".py", - "mimetype" : "text/x-python", - "name" : "python", - "nbconvert_exporter" : "python", - "pygments_lexer" : "ipython3", - "version" : "3.9.17" - }, - "orig_nbformat" : 4 - }, - "nbformat" : 4, - "nbformat_minor" : 2 + "metadata": { + "interpreter": { + "hash": "d1bcf2015140efba1309a3b878c8a09b28a5da1fac13dcbb304588e5a25844fe" + }, + "kernelspec": { + "display_name": "Python 3.8.12 ('base')", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.9.18" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 } diff --git a/sm_cm_config/src/xml_generate.py b/sm_cm_config/src/xml_generate.py index 2172dba6..92d7d983 100644 --- a/sm_cm_config/src/xml_generate.py +++ b/sm_cm_config/src/xml_generate.py @@ -1,34 +1,17 @@ +#! /usr/bin/env python """Generate XML file from YAML input""" import xml.etree.ElementTree as ET from pprint import pprint import argparse +import os import yaml -parser = argparse.ArgumentParser(description='Process YAML for XML.') -parser.add_argument('-v', '--verbose', action='store_true', - help='increase output verbosity') -parser.add_argument('-d', '--directory', type=str, help='output directory') -#this argument is required -parser.add_argument('input_files', metavar='file', type=str, - nargs='+', help='input file names') - -args = parser.parse_args() - -if args.verbose: - print('Verbose mode on') - -if args.directory: - print('Output directory:', args.directory) - -if args.verbose: - print('Input file names:', args.input_files) - #% % def make_node(parent: ET.Element, myid: str, thedict: dict, addr2: int, parent_id: str) -> ET.Element: """create the node to be inserted into the xml tree""" -#pylint : disable = too - many - branches -#I disable this check because as far as I can tell it's wrong +# pylint: disable=too-many-branches +# I disable this check because as far as I can tell it's wrong thenode = ET.SubElement(parent, 'node') myid = myid.replace(' ', '_') thenode.set('id', myid) @@ -134,8 +117,31 @@ def overloads(self): return False +# custom file type for yaml file, to be used with argparse +def yaml_file(filename): + """custom file type for yaml file, to be used with argparse""" + if not filename.endswith('.yml'): + raise argparse.ArgumentTypeError('File must have a .yml extension') + return filename -with open(args.input_files[1], encoding='ascii') as f: +parser = argparse.ArgumentParser(description='Process YAML for XML.') +parser.add_argument('-v', '--verbose', action='store_true', + help='increase output verbosity') +parser.add_argument('-d', '--directory', type=str, help='output directory') +# this argument is required, one input file ending with yaml extension +parser.add_argument('input_file', metavar='file', type=yaml_file, + help='input yaml file name') + +args = parser.parse_args() + +if args.verbose: + print('Verbose mode on') + print('Input file names:', args.input_file) + if args.directory: + print('Output directory:', args.directory) + + +with open(args.input_file, encoding='ascii') as f: y = yaml.load(f, Loader=yaml.FullLoader) if args.verbose: pprint(y) @@ -179,7 +185,12 @@ def overloads(self): i += 1 tree = ET.ElementTree(cm) ET.indent(tree, space='\t') -tree.write("test2.xml") +# create output file name based on input file, replacing 'yml' with 'xml' +out_name = os.path.basename(args.input_file)[:-len('.yml')] + '.xml' +out_name = args.directory + '/' + out_name +if args.verbose: + print("writing to file", out_name) +tree.write(out_name) #% % @@ -199,7 +210,9 @@ def overloads(self): size = calc_size(c) thislength = len(postfixes) * len(names)*size entries.append(reg(c['name'], start, start + thislength - 1, thislength)) -pprint(entries) +if args.verbose: + for e in entries: + print(e) #check for overlaps and overloads for i in range(len(entries)):