Compare commits
	
		
			4 Commits
		
	
	
		
			752cf011c3
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| cce7e96779 | |||
| 30339f0ece | |||
| b6e9c6f4db | |||
| d34ce4efd2 | 
							
								
								
									
										181
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,181 @@ | |||||||
|  | <h3>rivet - Register / Instruction Visualizer and Explainer Tool</h3> | ||||||
|  |  | ||||||
|  | --- | ||||||
|  | ## Table of contents | ||||||
|  | <!-- TOC --> | ||||||
|  |   * [Table of contents](#table-of-contents) | ||||||
|  |   * [Introduction](#introduction) | ||||||
|  |   * [Requirements](#requirements) | ||||||
|  |   * [Usage](#usage) | ||||||
|  |   * [Options](#options) | ||||||
|  |   * [Examples](#examples) | ||||||
|  |       * [config.json](#configjson) | ||||||
|  |       * [dark.json](#darkjson) | ||||||
|  |       * [blueprint.json](#blueprintjson) | ||||||
|  |       * [transparent.json](#transparentjson) | ||||||
|  |   * [Config](#config) | ||||||
|  | <!-- TOC --> | ||||||
|  |  | ||||||
|  | --- | ||||||
|  |  | ||||||
|  | ## Introduction | ||||||
|  |  | ||||||
|  | This tool lets you generate visual explanations of binary instructions, or describe the contents of a register. | ||||||
|  |  | ||||||
|  | The layout and style can be customized to fit your needs. | ||||||
|  |  | ||||||
|  | For a full description of the schema format, please check out [format.md](format.md) | ||||||
|  |  | ||||||
|  | ## Requirements | ||||||
|  |  | ||||||
|  | - [Python 3+](https://www.python.org/) | ||||||
|  | - [Pygame](https://pypi.org/project/pygame/) - used to render the images | ||||||
|  | - [Beautiful Soup 4](https://pypi.org/project/beautifulsoup4/) - used to parse XML files | ||||||
|  | - [PyYAML](https://pypi.org/project/PyYAML/) - used to parse YAML files | ||||||
|  |  | ||||||
|  | ## Usage | ||||||
|  |  | ||||||
|  | Basic usage: | ||||||
|  | ```bash | ||||||
|  | python3 main.py schema.xml | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Directory mode + config: | ||||||
|  | ```bash | ||||||
|  | python3 main.py -o out/ -c config.json -d schemas/ | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Options | ||||||
|  |  | ||||||
|  | Several command line options are available: | ||||||
|  | - `-o PATH` sets the output path. If not given, the output file will be located in the same directory as the input file, and given the same name (different extension) | ||||||
|  | - `-d` enables directory mode. If set, the input and output paths are directories and all files inside the input directory are processed | ||||||
|  | - `-c PATH` sets the config path. For more details on available config parameters, please read the [Config section](#config). | ||||||
|  |  | ||||||
|  | ## Examples | ||||||
|  |  | ||||||
|  | The following images were generated from this schema ([example1.yaml](example1.yaml)): | ||||||
|  |  | ||||||
|  | <details> | ||||||
|  | <summary>Show / hide</summary> | ||||||
|  |  | ||||||
|  | ```yaml | ||||||
|  | structures: | ||||||
|  |   main: | ||||||
|  |     bits: 32 | ||||||
|  |     ranges: | ||||||
|  |       31-28: | ||||||
|  |         name: cond | ||||||
|  |       27: | ||||||
|  |         name: 0 | ||||||
|  |       26: | ||||||
|  |         name: 1 | ||||||
|  |       25: | ||||||
|  |         name: I | ||||||
|  |       24: | ||||||
|  |         name: P | ||||||
|  |         description: pre / post indexing bit | ||||||
|  |         values: | ||||||
|  |           0: post, add offset after transfer | ||||||
|  |           1: pre, add offset before transfer | ||||||
|  |       23: | ||||||
|  |         name: U | ||||||
|  |         description: up / down bit | ||||||
|  |         values: | ||||||
|  |           0: down, subtract offset from base | ||||||
|  |           1: up, addition offset to base | ||||||
|  |       22: | ||||||
|  |         name: B | ||||||
|  |         description: byte / word bit | ||||||
|  |         values: | ||||||
|  |           0: transfer word quantity | ||||||
|  |           1: transfer byte quantity | ||||||
|  |       21: | ||||||
|  |         name: W | ||||||
|  |         description: write-back bit | ||||||
|  |         values: | ||||||
|  |           0: no write-back | ||||||
|  |           1: write address into base | ||||||
|  |       20: | ||||||
|  |         name: L | ||||||
|  |         description: load / store bit | ||||||
|  |         values: | ||||||
|  |           0: store to memory | ||||||
|  |           1: load from memory | ||||||
|  |       19-16: | ||||||
|  |         name: Rn | ||||||
|  |         description: base register | ||||||
|  |       15-12: | ||||||
|  |         name: Rd | ||||||
|  |         description: source / destination register | ||||||
|  |       11-0: | ||||||
|  |         name: offset | ||||||
|  |         depends-on: 25 | ||||||
|  |         values: | ||||||
|  |           0: | ||||||
|  |             description: offset is an immediate value | ||||||
|  |             structure: immediateOffset | ||||||
|  |           1: | ||||||
|  |             description: offset is a register | ||||||
|  |             structure: registerOffset | ||||||
|  |   immediateOffset: | ||||||
|  |     bits: 12 | ||||||
|  |     ranges: | ||||||
|  |       11-0: | ||||||
|  |         name: 12-bit immediate offset | ||||||
|  |         description: unsigned number | ||||||
|  |   registerOffset: | ||||||
|  |     bits: 12 | ||||||
|  |     ranges: | ||||||
|  |       11-4: | ||||||
|  |         name: shift | ||||||
|  |         description: shift applied to Rm | ||||||
|  |       3-0: | ||||||
|  |         name: Rm | ||||||
|  |         description: offset register | ||||||
|  | ``` | ||||||
|  | </details> | ||||||
|  |  | ||||||
|  | #### config.json | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #### dark.json | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #### blueprint.json | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #### transparent.json | ||||||
|  |  | ||||||
|  |  | ||||||
|  | ## Config | ||||||
|  |  | ||||||
|  | The config file may change the following values to customize the layout and style: | ||||||
|  | - `defaultFontFamily`: the default font family | ||||||
|  | - `defaultFontSize`: the default font size | ||||||
|  | - `italicFontFamily`: the italic font family (for value description) | ||||||
|  | - `italicFontSize`: the italic font size | ||||||
|  | - `backgroundColor`: the image background color (ex: [222, 250, 206]) | ||||||
|  | - `textColor`: the default text color | ||||||
|  | - `linkColor`: the color of linking lines and arrows | ||||||
|  | - `borderColor`: the color of register borders | ||||||
|  | - `bitWidth`: the width of 1 bit (in pixels) | ||||||
|  | - `bitHeight`: the height of 1 bit (in pixels) | ||||||
|  | - `descriptionMargin`: the space between descriptions (in pixels) | ||||||
|  | - `dashLength`: the length of one dash (for dashed lines) | ||||||
|  | - `dashSpace`: the space between dashes (for dashed lines) | ||||||
|  | - `arrowSize`: the arrow size (height in pixels, width for horizontal arrow) | ||||||
|  | - `margins`: the margins from the borders of the image (in pixels, [top, right, bottom, left]) | ||||||
|  | - `arrowMargin`: the margin between arrows and registers (in pixels) | ||||||
|  | - `valuesGap`: the gap between values (in pixels) | ||||||
|  | - `arrowLabelDistance`: the distance between arrows and their label (in pixels) | ||||||
|  | - `forceDescsOnSide`: if true, descriptions are placed on the side of the register, otherwise, they are placed as close as possible to the bit | ||||||
|  | - `leftLabels`: if true, descriptions are put on the left, otherwise, they default to the right hand side | ||||||
|  | - `width`: the image width (in pixels) | ||||||
|  | - `height`: the image height (in pixels) | ||||||
|  |  | ||||||
|  | Some config examples are already included: | ||||||
|  | - [config.json](config.json): Default configuration values (black on white) | ||||||
|  | - [dark.json](dark.json): Dark theme (white on black) | ||||||
|  | - [blueprint.json](blueprint.json): Blueprint theme (white on blue) | ||||||
|  | - [transparent.json](transparent.json): Transparent background, for easy integration in other documents (grey on transparent) | ||||||
| @@ -19,6 +19,7 @@ | |||||||
|     "valuesGap": 5, |     "valuesGap": 5, | ||||||
|     "arrowLabelDistance": 5, |     "arrowLabelDistance": 5, | ||||||
|     "forceDescsOnSide": false, |     "forceDescsOnSide": false, | ||||||
|  |     "leftLabels": false, | ||||||
|     "width": 1200, |     "width": 1200, | ||||||
|     "height": 800 |     "height": 800 | ||||||
| } | } | ||||||
| @@ -1,3 +1,5 @@ | |||||||
|  | from __future__ import annotations | ||||||
|  |  | ||||||
| import json | import json | ||||||
| import re | import re | ||||||
|  |  | ||||||
| @@ -30,7 +32,8 @@ class Config: | |||||||
|     def __init__(self, path: str = "config.json") -> None: |     def __init__(self, path: str = "config.json") -> None: | ||||||
|         self.load(path) |         self.load(path) | ||||||
|  |  | ||||||
|     def load(self, path: str) -> None: |     @staticmethod | ||||||
|  |     def load(path: str) -> None: | ||||||
|         with open(path, "r") as f: |         with open(path, "r") as f: | ||||||
|             config = json.load(f) |             config = json.load(f) | ||||||
|              |              | ||||||
| @@ -39,5 +42,6 @@ class Config: | |||||||
|                 if hasattr(Config, k): |                 if hasattr(Config, k): | ||||||
|                     setattr(Config, k, v) |                     setattr(Config, k, v) | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|     def formatKey(key: str) -> str: |     def formatKey(key: str) -> str: | ||||||
|         return re.sub(r"([a-z])([A-Z])", r"\1_\2", key).upper() |         return re.sub(r"([a-z])([A-Z])", r"\1_\2", key).upper() | ||||||
							
								
								
									
										
											BIN
										
									
								
								example_blueprint.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								example_blueprint.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 63 KiB | 
							
								
								
									
										
											BIN
										
									
								
								example_dark.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								example_dark.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 62 KiB | 
							
								
								
									
										
											BIN
										
									
								
								example_normal.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								example_normal.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 60 KiB | 
							
								
								
									
										
											BIN
										
									
								
								example_transparent.png
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								example_transparent.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 43 KiB | 
							
								
								
									
										125
									
								
								format.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								format.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,125 @@ | |||||||
|  | # Schema Format | ||||||
|  |  | ||||||
|  | _**Supported syntaxes: JSON, XML, YAML**_ | ||||||
|  |  | ||||||
|  | The following description uses the JSON syntax | ||||||
|  |  | ||||||
|  | For examples in different formats, see [example1.yaml](example1.yaml), [example2.yaml](example2.yaml), [example3.json](example3.json) and [example4.xml](example4.xml). | ||||||
|  |  | ||||||
|  | ## Main layout | ||||||
|  |  | ||||||
|  | A schema contains a dictionary of structures. There must be at least one defined structure named "main"  | ||||||
|  | ```json | ||||||
|  | { | ||||||
|  |   "structures": { | ||||||
|  |     "main": { | ||||||
|  |       ... | ||||||
|  |     }, | ||||||
|  |     "struct1": { | ||||||
|  |       ... | ||||||
|  |     }, | ||||||
|  |     "struct2": { | ||||||
|  |       ... | ||||||
|  |     }, | ||||||
|  |     ... | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Structure | ||||||
|  |  | ||||||
|  | A structure has a given number of bits and one or multiple ranges. Each range of bits can have a name, a description and / or values with special meaning (see [Range](#range)). A range's structure can also depend on another range's value (see [Dependencies](#dependencies)) | ||||||
|  |  | ||||||
|  | The range name (or key) defines the left- and rightmost bits (e.g. 7-4 goes from bit 7 to bit 4). Bits are displayed in big-endian, i.e. the leftmost bit has the highest value. | ||||||
|  | ```json | ||||||
|  | "main": { | ||||||
|  |   "bits": 8, | ||||||
|  |   "ranges": { | ||||||
|  |     "7-4": { | ||||||
|  |       ... | ||||||
|  |     }, | ||||||
|  |     "3-2": { | ||||||
|  |       ... | ||||||
|  |     }, | ||||||
|  |     "1": { | ||||||
|  |       ... | ||||||
|  |     }, | ||||||
|  |     "0": { | ||||||
|  |       ... | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Range | ||||||
|  |  | ||||||
|  | A range represents a group of consecutive bits. It can have a name (display in the bit cells), a description (displayed under the structure) and / or values. | ||||||
|  |  | ||||||
|  | For values depending on other ranges, see [Dependencies](#dependencies). | ||||||
|  |  | ||||||
|  | > **Note**<br> | ||||||
|  | > In YAML, make sure to wrap values in quotes because some values can be interpreted as octal notation (e.g. 010) | ||||||
|  |  | ||||||
|  | ```json | ||||||
|  | "3-2": { | ||||||
|  |   "name": "op", | ||||||
|  |   "description": "Logical operation", | ||||||
|  |   "values": { | ||||||
|  |     "00": "AND", | ||||||
|  |     "01": "OR", | ||||||
|  |     "10": "XOR", | ||||||
|  |     "11": "NAND" | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | ## Dependencies | ||||||
|  |  | ||||||
|  | The structure of one range may depend on the value of another. To represent this situation, first indicate on the child range the range on which it depends: | ||||||
|  |  | ||||||
|  | ```json | ||||||
|  | "7-4": { | ||||||
|  |   ... | ||||||
|  |   "depends-on": "0" | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Then, in its values, indicate which structure to use. A description can also be added (displayed above the horizontal dependency arrow) | ||||||
|  |  | ||||||
|  | ```json | ||||||
|  | "7-4": { | ||||||
|  |   ... | ||||||
|  |   "depends-on": "0", | ||||||
|  |   "values": { | ||||||
|  |     "0": { | ||||||
|  |       "description": "immediate value", | ||||||
|  |       "structure": "immediateValue" | ||||||
|  |     }, | ||||||
|  |     "1": { | ||||||
|  |       "description": "value in register", | ||||||
|  |       "structure": "registerValue" | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | ``` | ||||||
|  |  | ||||||
|  | Finally, add the sub-structures to the structure dictionary: | ||||||
|  |  | ||||||
|  | ```json | ||||||
|  | { | ||||||
|  |   "structures": { | ||||||
|  |     "main": { | ||||||
|  |       ... | ||||||
|  |     }, | ||||||
|  |     "immediateValue": { | ||||||
|  |       "bits": 4, | ||||||
|  |       ... | ||||||
|  |     }, | ||||||
|  |     "registerValue": { | ||||||
|  |       "bits": 4, | ||||||
|  |       ... | ||||||
|  |     }, | ||||||
|  |     ... | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | ``` | ||||||
							
								
								
									
										8
									
								
								main.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							
							
						
						
									
										8
									
								
								main.py
									
									
									
									
									
										
										
										Normal file → Executable file
									
								
							| @@ -1,9 +1,13 @@ | |||||||
|  | #!/usr/bin/env python3 | ||||||
|  | # -*- coding: utf-8 -*- | ||||||
|  |  | ||||||
|  | from __future__ import annotations | ||||||
|  |  | ||||||
| import argparse | import argparse | ||||||
| import os | import os | ||||||
|  |  | ||||||
| from schema import InstructionSetSchema | from schema import InstructionSetSchema | ||||||
|  |  | ||||||
|  |  | ||||||
| description = """Examples: | description = """Examples: | ||||||
|     - Default theme (black on white): |     - Default theme (black on white): | ||||||
|         python main.py schema.xml -o out.jpg |         python main.py schema.xml -o out.jpg | ||||||
| @@ -22,7 +26,7 @@ description = """Examples: | |||||||
| """ | """ | ||||||
|  |  | ||||||
|  |  | ||||||
| def processFile(inPath, outPath, confPath, display): | def processFile(inPath: str, outPath: str, confPath: str, display: bool) -> None: | ||||||
|     schema = InstructionSetSchema(inPath, confPath, display) |     schema = InstructionSetSchema(inPath, confPath, display) | ||||||
|     schema.save(outPath) |     schema.save(outPath) | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										27
									
								
								range.py
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								range.py
									
									
									
									
									
								
							| @@ -1,6 +1,6 @@ | |||||||
| from __future__ import annotations | from __future__ import annotations | ||||||
|  |  | ||||||
| from typing import Union | from typing import Union, Optional | ||||||
|  |  | ||||||
|  |  | ||||||
| class Range: | class Range: | ||||||
| @@ -9,22 +9,23 @@ class Range: | |||||||
|                  end: int, |                  end: int, | ||||||
|                  name: str, |                  name: str, | ||||||
|                  description: str = "", |                  description: str = "", | ||||||
|                  values: dict[str, Union[str, dict]] = None, |                  values: Optional[dict[str, Union[str, dict]]] = None, | ||||||
|                  dependsOn: str = None) -> None: |                  dependsOn: Optional[tuple[int, int]] = None) -> None: | ||||||
|          |          | ||||||
|         self.start = start |         self.start: int = start | ||||||
|         self.end = end |         self.end: int = end | ||||||
|         self.name = name |         self.name: str = name | ||||||
|         self.description = description |         self.description: str = description | ||||||
|         self.values = values |         self.values: Optional[dict[str, Union[str, dict]]] = values | ||||||
|         self.dependsOn = dependsOn |         self.dependsOn: Optional[tuple[int, int]] = dependsOn | ||||||
|         self.lastValueY = -1 |         self.lastValueY: int = -1 | ||||||
|      |      | ||||||
|     @property |     @property | ||||||
|     def bits(self) -> int: |     def bits(self) -> int: | ||||||
|         return self.end - self.start + 1 |         return self.end - self.start + 1 | ||||||
|  |  | ||||||
|     def load(start: int, end: int, data: dict): |     @staticmethod | ||||||
|  |     def load(start: int, end: int, data: dict) -> Range: | ||||||
|         values = None |         values = None | ||||||
|         bits = end - start + 1 |         bits = end - start + 1 | ||||||
|          |          | ||||||
| @@ -45,9 +46,11 @@ class Range: | |||||||
|                      values, |                      values, | ||||||
|                      dependsOn) |                      dependsOn) | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|     def parseSpan(span: str) -> tuple[int, int]: |     def parseSpan(span: str) -> tuple[int, int]: | ||||||
|         startEnd = span.split("-") |         startEnd = span.split("-") | ||||||
|         if len(startEnd) == 1: startEnd.append(startEnd[0]) |         if len(startEnd) == 1: | ||||||
|  |             startEnd.append(startEnd[0]) | ||||||
|         start = int(startEnd[1]) |         start = int(startEnd[1]) | ||||||
|         end = int(startEnd[0]) |         end = int(startEnd[0]) | ||||||
|         return (start, end) |         return (start, end) | ||||||
							
								
								
									
										25
									
								
								renderer.py
									
									
									
									
									
								
							
							
						
						
									
										25
									
								
								renderer.py
									
									
									
									
									
								
							| @@ -16,17 +16,23 @@ if TYPE_CHECKING: | |||||||
|  |  | ||||||
| class Renderer: | class Renderer: | ||||||
|     def __init__(self, config: Config, display: bool = False) -> None: |     def __init__(self, config: Config, display: bool = False) -> None: | ||||||
|         self.config = config |         self.config: Config = config | ||||||
|         self.display = display |         self.display: bool = display | ||||||
|         pygame.init() |         pygame.init() | ||||||
|         if self.display: |         if self.display: | ||||||
|             self.win = pygame.display.set_mode([self.config.WIDTH, self.config.HEIGHT]) |             self.win: pygame.Surface = pygame.display.set_mode([self.config.WIDTH, self.config.HEIGHT]) | ||||||
|          |          | ||||||
|         self.surf = pygame.Surface([self.config.WIDTH, self.config.HEIGHT], pygame.SRCALPHA) |         self.surf: pygame.Surface = pygame.Surface([self.config.WIDTH, self.config.HEIGHT], pygame.SRCALPHA) | ||||||
|         self.font = pygame.font.SysFont(self.config.DEFAULT_FONT_FAMILY, self.config.DEFAULT_FONT_SIZE) |  | ||||||
|         self.italicFont = pygame.font.SysFont(self.config.ITALIC_FONT_FAMILY, self.config.ITALIC_FONT_SIZE, italic=True) |  | ||||||
|  |  | ||||||
|         self.margins = self.config.MARGINS |         self.font: pygame.font.Font = pygame.font.SysFont( | ||||||
|  |             self.config.DEFAULT_FONT_FAMILY, | ||||||
|  |             self.config.DEFAULT_FONT_SIZE) | ||||||
|  |  | ||||||
|  |         self.italicFont: pygame.font.Font = pygame.font.SysFont( | ||||||
|  |             self.config.ITALIC_FONT_FAMILY, | ||||||
|  |             self.config.ITALIC_FONT_SIZE, italic=True) | ||||||
|  |          | ||||||
|  |         self.margins: list[int, int, int, int] = self.config.MARGINS | ||||||
|      |      | ||||||
|     def render(self, schema: InstructionSetSchema) -> None: |     def render(self, schema: InstructionSetSchema) -> None: | ||||||
|         self.surf.fill(self.config.BACKGROUND_COLOR) |         self.surf.fill(self.config.BACKGROUND_COLOR) | ||||||
| @@ -206,8 +212,7 @@ class Renderer: | |||||||
|  |  | ||||||
|     def drawDependency(self, |     def drawDependency(self, | ||||||
|                        struct: Structure, |                        struct: Structure, | ||||||
|                        structures: dict[str, |                        structures: dict[str, Structure], | ||||||
|                        Structure], |  | ||||||
|                        bitsX: float, |                        bitsX: float, | ||||||
|                        bitsY: float, |                        bitsY: float, | ||||||
|                        range_: Range, |                        range_: Range, | ||||||
| @@ -274,7 +279,7 @@ class Renderer: | |||||||
|                            descY + bitH - arrowMargin) |                            descY + bitH - arrowMargin) | ||||||
|  |  | ||||||
|             prevDependY = descY + bitH*2 + arrowMargin |             prevDependY = descY + bitH*2 + arrowMargin | ||||||
|             prevRangeY =prevDependY |             prevRangeY = prevDependY | ||||||
|             dependRange.lastValueY = prevDependY |             dependRange.lastValueY = prevDependY | ||||||
|             descY = self.drawStructure(structures[data["structure"]], structures, rStartX, descY) |             descY = self.drawStructure(structures[data["structure"]], structures, rStartX, descY) | ||||||
|          |          | ||||||
|   | |||||||
| @@ -17,9 +17,10 @@ class InstructionSetSchema: | |||||||
|     VALID_EXTENSIONS = ("yaml", "json", "xml") |     VALID_EXTENSIONS = ("yaml", "json", "xml") | ||||||
|      |      | ||||||
|     def __init__(self, path: str, configPath: str = "config.json", display: bool = False) -> None: |     def __init__(self, path: str, configPath: str = "config.json", display: bool = False) -> None: | ||||||
|         self.config = Config(configPath) |         self.config: Config = Config(configPath) | ||||||
|         self.display = display |         self.display: bool = display | ||||||
|         self.path = path |         self.path: str = path | ||||||
|  |         self.structures: dict[str, Structure] = {} | ||||||
|         self.load() |         self.load() | ||||||
|      |      | ||||||
|     def load(self) -> None: |     def load(self) -> None: | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								structure.py
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								structure.py
									
									
									
									
									
								
							| @@ -7,14 +7,15 @@ class Structure: | |||||||
|     def __init__(self, |     def __init__(self, | ||||||
|                  name: str, |                  name: str, | ||||||
|                  bits: int, |                  bits: int, | ||||||
|                  ranges: dict[str, Range], |                  ranges: dict[tuple[int, int], Range], | ||||||
|                  start: int = 0) -> None: |                  start: int = 0) -> None: | ||||||
|          |          | ||||||
|         self.name = name |         self.name: str = name | ||||||
|         self.bits = bits |         self.bits: int = bits | ||||||
|         self.ranges = ranges |         self.ranges: dict[tuple[int, int], Range] = ranges | ||||||
|         self.start = start |         self.start: int = start | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|     def load(id_: str, data: dict) -> Structure: |     def load(id_: str, data: dict) -> Structure: | ||||||
|         ranges = {} |         ranges = {} | ||||||
|         for rSpan, rData in data["ranges"].items(): |         for rSpan, rData in data["ranges"].items(): | ||||||
|   | |||||||
							
								
								
									
										9
									
								
								vec.py
									
									
									
									
									
								
							
							
						
						
									
										9
									
								
								vec.py
									
									
									
									
									
								
							| @@ -5,8 +5,8 @@ from math import sqrt | |||||||
|  |  | ||||||
| class Vec: | class Vec: | ||||||
|     def __init__(self, x: float = 0, y: float = 0) -> None: |     def __init__(self, x: float = 0, y: float = 0) -> None: | ||||||
|         self.x = x |         self.x: float = x | ||||||
|         self.y = y |         self.y: float = y | ||||||
|      |      | ||||||
|     def __add__(self, v: Vec) -> Vec: |     def __add__(self, v: Vec) -> Vec: | ||||||
|         return Vec(self.x+v.x, self.y+v.y) |         return Vec(self.x+v.x, self.y+v.y) | ||||||
| @@ -25,5 +25,6 @@ class Vec: | |||||||
|      |      | ||||||
|     def norm(self) -> Vec: |     def norm(self) -> Vec: | ||||||
|         mag = self.mag() |         mag = self.mag() | ||||||
|         if mag == 0: return Vec() |         if mag == 0: | ||||||
|         return self/mag |             return Vec() | ||||||
|  |         return self / mag | ||||||
|   | |||||||
| @@ -7,7 +7,9 @@ from bs4 import BeautifulSoup | |||||||
| if TYPE_CHECKING: | if TYPE_CHECKING: | ||||||
|     from io import TextIOWrapper |     from io import TextIOWrapper | ||||||
|  |  | ||||||
|  |  | ||||||
| class XMLLoader: | class XMLLoader: | ||||||
|  |     @staticmethod | ||||||
|     def load(file_: TextIOWrapper) -> dict: |     def load(file_: TextIOWrapper) -> dict: | ||||||
|         schema = {} |         schema = {} | ||||||
|         bs = BeautifulSoup(file_.read(), "xml") |         bs = BeautifulSoup(file_.read(), "xml") | ||||||
| @@ -20,9 +22,11 @@ class XMLLoader: | |||||||
|         schema["structures"] = structures |         schema["structures"] = structures | ||||||
|         return schema |         return schema | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|     def parseStructure(structElmt: any) -> dict: |     def parseStructure(structElmt: any) -> dict: | ||||||
|         struct = {} |         struct = { | ||||||
|         struct["bits"] = structElmt.get("bits") |             "bits": structElmt.get("bits") | ||||||
|  |         } | ||||||
|         ranges = {} |         ranges = {} | ||||||
|         rangeElmts = structElmt.findAll("range") |         rangeElmts = structElmt.findAll("range") | ||||||
|         for rangeElmt in rangeElmts: |         for rangeElmt in rangeElmts: | ||||||
| @@ -32,11 +36,14 @@ class XMLLoader: | |||||||
|         struct["ranges"] = ranges |         struct["ranges"] = ranges | ||||||
|         return struct |         return struct | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|     def parseRange(rangeElmt: any) -> dict: |     def parseRange(rangeElmt: any) -> dict: | ||||||
|         range_ = {} |         range_ = { | ||||||
|         range_["name"] = rangeElmt.get("name") |             "name": rangeElmt.get("name") | ||||||
|  |         } | ||||||
|         desc = rangeElmt.find("description") |         desc = rangeElmt.find("description") | ||||||
|         if desc is not None: range_["description"] = desc.getText() |         if desc is not None: | ||||||
|  |             range_["description"] = desc.getText() | ||||||
|          |          | ||||||
|         valuesElmt = rangeElmt.find("values") |         valuesElmt = rangeElmt.find("values") | ||||||
|         if valuesElmt is not None: |         if valuesElmt is not None: | ||||||
| @@ -47,6 +54,7 @@ class XMLLoader: | |||||||
|          |          | ||||||
|         return range_ |         return range_ | ||||||
|  |  | ||||||
|  |     @staticmethod | ||||||
|     def parseValues(valuesElmt: any) -> dict: |     def parseValues(valuesElmt: any) -> dict: | ||||||
|         values = {} |         values = {} | ||||||
|         caseElmts = valuesElmt.findAll("case") |         caseElmts = valuesElmt.findAll("case") | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user