initial commit
This commit is contained in:
		
							
								
								
									
										23
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								.vscode/launch.json
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | { | ||||||
|  |     // Use IntelliSense to learn about possible attributes. | ||||||
|  |     // Hover to view descriptions of existing attributes. | ||||||
|  |     // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 | ||||||
|  |     "version": "0.2.0", | ||||||
|  |     "configurations": [ | ||||||
|  |         { | ||||||
|  |             "name": "Python: Current File", | ||||||
|  |             "type": "python", | ||||||
|  |             "request": "launch", | ||||||
|  |             "program": "${file}", | ||||||
|  |             "console": "integratedTerminal", | ||||||
|  |             "justMyCode": true | ||||||
|  |         }, | ||||||
|  |         { | ||||||
|  |             "name": "main.py", | ||||||
|  |             "type": "python", | ||||||
|  |             "request": "launch", | ||||||
|  |             "program": "${workspaceFolder}/main.py", | ||||||
|  |             "console": "integratedTerminal" | ||||||
|  |         } | ||||||
|  |     ] | ||||||
|  | } | ||||||
							
								
								
									
										0
									
								
								__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										21
									
								
								config.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								config.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | { | ||||||
|  |     "defaultFontFamily": "Ubuntu Mono", | ||||||
|  |     "defaultFontSize": 16, | ||||||
|  |     "italicFontFamily": "Ubuntu Mono", | ||||||
|  |     "italicFontSize": 14, | ||||||
|  |     "backgroundColor": [255, 255, 255], | ||||||
|  |     "textColor": [0, 0, 0], | ||||||
|  |     "linkColor": [0, 0, 0], | ||||||
|  |     "bitIColor": [0, 0, 0], | ||||||
|  |     "borderColor": [0, 0, 0], | ||||||
|  |     "bitWidth": 30, | ||||||
|  |     "bitHeight": 30, | ||||||
|  |     "descriptionMargin": 10, | ||||||
|  |     "dashLength": 6, | ||||||
|  |     "dashSpace": 4, | ||||||
|  |     "arrowSize": 10, | ||||||
|  |     "margins": [20, 20, 20, 20], | ||||||
|  |     "arrowMargin": 4, | ||||||
|  |     "valuesGap": 5, | ||||||
|  |     "arrowLabelDistance": 5 | ||||||
|  | } | ||||||
							
								
								
									
										10
									
								
								config.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								config.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | |||||||
|  | import json | ||||||
|  | from typing import Any | ||||||
|  |  | ||||||
|  | class Config: | ||||||
|  |     def __init__(self) -> None: | ||||||
|  |         with open("config.json", "r") as f: | ||||||
|  |             self.params = json.load(f) | ||||||
|  |      | ||||||
|  |     def get(self, param: str) -> Any: | ||||||
|  |         return self.params[param] | ||||||
							
								
								
									
										73
									
								
								example1.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										73
									
								
								example1.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,73 @@ | |||||||
|  | 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 | ||||||
							
								
								
									
										64
									
								
								example2.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								example2.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | |||||||
|  | structures: | ||||||
|  |   main: | ||||||
|  |     bits: 32 | ||||||
|  |     ranges: | ||||||
|  |       31-8: | ||||||
|  |         name: '-' | ||||||
|  |       7-6: | ||||||
|  |         name: code | ||||||
|  |       5-4: | ||||||
|  |         name: params | ||||||
|  |         description: parameter | ||||||
|  |         values: | ||||||
|  |           00: unsigned integer | ||||||
|  |           01: signed integer | ||||||
|  |           10: unsigned float | ||||||
|  |           11: signed float | ||||||
|  |       3-0: | ||||||
|  |         name: values | ||||||
|  |         depends-on: 7-6 | ||||||
|  |         values: | ||||||
|  |           00: | ||||||
|  |             description: increment register | ||||||
|  |             structure: valuesIncrReg | ||||||
|  |           01: | ||||||
|  |             description: add registers | ||||||
|  |             structure: valuesAddReg | ||||||
|  |           10: | ||||||
|  |             description: add immediate value and register | ||||||
|  |             structure: valuesAddImmReg | ||||||
|  |           11: | ||||||
|  |             description: right shift register by value | ||||||
|  |             structure: valuesShiftReg | ||||||
|  |   valuesIncrReg: | ||||||
|  |     bits: 4 | ||||||
|  |     ranges: | ||||||
|  |       3-0: | ||||||
|  |         name: register address | ||||||
|  |   valuesAddReg: | ||||||
|  |     bits: 4 | ||||||
|  |     ranges: | ||||||
|  |       3-2: | ||||||
|  |         name: r1 | ||||||
|  |         description: first register address | ||||||
|  |       1-0: | ||||||
|  |         name: r2 | ||||||
|  |         description: second register address | ||||||
|  |   valuesAddImmReg: | ||||||
|  |     bits: 4 | ||||||
|  |     ranges: | ||||||
|  |       3-2: | ||||||
|  |         name: val | ||||||
|  |         description: immediate value | ||||||
|  |       1-0: | ||||||
|  |         name: r1 | ||||||
|  |         description: register address | ||||||
|  |   valuesShiftReg: | ||||||
|  |     bits: 4 | ||||||
|  |     ranges: | ||||||
|  |       3-2: | ||||||
|  |         name: shift | ||||||
|  |         description: shift amount | ||||||
|  |       1-0: | ||||||
|  |         name: r1 | ||||||
|  |         description: register address | ||||||
							
								
								
									
										6
									
								
								main.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								main.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | |||||||
|  | from schema import InstructionSetSchema | ||||||
|  |  | ||||||
|  | if __name__ == "__main__": | ||||||
|  |     schema = InstructionSetSchema("example1.yaml") | ||||||
|  |     schema.save("example1_v2.jpg") | ||||||
|  |     input() | ||||||
							
								
								
									
										50
									
								
								range.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								range.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | |||||||
|  | from __future__ import annotations | ||||||
|  | from typing import Union | ||||||
|  |  | ||||||
|  | class Range: | ||||||
|  |     def __init__(self, | ||||||
|  |                  start: int, | ||||||
|  |                  end: int, | ||||||
|  |                  name: str, | ||||||
|  |                  description: str = "", | ||||||
|  |                  values: dict[str, Union[str, dict]] = None, | ||||||
|  |                  dependsOn: str = None) -> None: | ||||||
|  |          | ||||||
|  |         self.start = start | ||||||
|  |         self.end = end | ||||||
|  |         self.name = name | ||||||
|  |         self.description = description | ||||||
|  |         self.values = values | ||||||
|  |         self.dependsOn = dependsOn | ||||||
|  |      | ||||||
|  |     @property | ||||||
|  |     def bits(self) -> int: | ||||||
|  |         return self.end - self.start + 1 | ||||||
|  |      | ||||||
|  |     def load(start: int, end: int, data: dict): | ||||||
|  |         values = None | ||||||
|  |         bits = end - start + 1 | ||||||
|  |          | ||||||
|  |         if "values" in data: | ||||||
|  |             values = {} | ||||||
|  |             for val, desc in data["values"].items(): | ||||||
|  |                 val = str(val).zfill(bits) | ||||||
|  |                 values[val] = desc | ||||||
|  |          | ||||||
|  |         dependsOn = data.get("depends-on", None) | ||||||
|  |         if dependsOn is not None: | ||||||
|  |             dependsOn = Range.parseSpan(str(dependsOn)) | ||||||
|  |          | ||||||
|  |         return Range(start, | ||||||
|  |                      end, | ||||||
|  |                      str(data["name"]), | ||||||
|  |                      data.get("description", ""), | ||||||
|  |                      values, | ||||||
|  |                      dependsOn) | ||||||
|  |  | ||||||
|  |     def parseSpan(span: str) -> tuple[int, int]: | ||||||
|  |         startEnd = span.split("-") | ||||||
|  |         if len(startEnd) == 1: startEnd.append(startEnd[0]) | ||||||
|  |         start = int(startEnd[1]) | ||||||
|  |         end = int(startEnd[0]) | ||||||
|  |         return (start, end) | ||||||
							
								
								
									
										263
									
								
								renderer.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										263
									
								
								renderer.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,263 @@ | |||||||
|  | from __future__ import annotations | ||||||
|  | from typing import TYPE_CHECKING | ||||||
|  | if TYPE_CHECKING: | ||||||
|  |     from config import Config | ||||||
|  |     from range import Range | ||||||
|  |     from schema import InstructionSetSchema | ||||||
|  |  | ||||||
|  | import pygame | ||||||
|  |  | ||||||
|  | from structure import Structure | ||||||
|  | from vec import Vec | ||||||
|  |  | ||||||
|  | class Renderer: | ||||||
|  |     WIDTH = 1200 | ||||||
|  |     HEIGHT = 800 | ||||||
|  |      | ||||||
|  |     def __init__(self, config: Config) -> None: | ||||||
|  |         self.config = config | ||||||
|  |         pygame.init() | ||||||
|  |         self.win = pygame.display.set_mode([Renderer.WIDTH, Renderer.HEIGHT]) | ||||||
|  |         self.font = pygame.font.SysFont(self.config.get("defaultFontFamily"), self.config.get("defaultFontSize")) | ||||||
|  |         self.italicFont = pygame.font.SysFont(self.config.get("italicFontFamily"), self.config.get("italicFontSize"), italic=True) | ||||||
|  |          | ||||||
|  |         self.margins = self.config.get("margins") | ||||||
|  |      | ||||||
|  |     def render(self, schema: InstructionSetSchema) -> None: | ||||||
|  |          | ||||||
|  |         self.win.fill(self.config.get("backgroundColor")) | ||||||
|  |          | ||||||
|  |         self.drawStructure(schema.structures["main"], schema.structures, self.margins[3], self.margins[0]) | ||||||
|  |          | ||||||
|  |         pygame.display.flip() | ||||||
|  |      | ||||||
|  |     def save(self, path: str) -> None: | ||||||
|  |         pygame.image.save(self.win, path) | ||||||
|  |      | ||||||
|  |     def drawStructure(self, | ||||||
|  |                       struct: Structure, | ||||||
|  |                       structures: dict[str, | ||||||
|  |                       Structure], | ||||||
|  |                       ox: float = 0, | ||||||
|  |                       oy: float = 0) -> float: | ||||||
|  |          | ||||||
|  |         bgCol = self.config.get("backgroundColor") | ||||||
|  |         txtCol = self.config.get("textColor") | ||||||
|  |         borderCol = self.config.get("borderColor") | ||||||
|  |         bitW = self.config.get("bitWidth") | ||||||
|  |         bitH = self.config.get("bitHeight") | ||||||
|  |          | ||||||
|  |         bitsX, bitsY = ox, oy + bitH | ||||||
|  |         bitsWidth = struct.bits * bitW | ||||||
|  |         startBit = struct.start | ||||||
|  |          | ||||||
|  |         # Draw rectangle around structure | ||||||
|  |         pygame.draw.rect(self.win, borderCol, [bitsX, bitsY, bitsWidth, bitH], 2) | ||||||
|  |          | ||||||
|  |         for i in range(struct.bits): | ||||||
|  |             bitX = ox + i * bitW | ||||||
|  |              | ||||||
|  |             bitITxt = self.font.render(str(struct.bits - i - 1 + startBit), True, txtCol) | ||||||
|  |             self.win.blit(bitITxt, [ | ||||||
|  |                 bitX + (bitW - bitITxt.get_width())/2, | ||||||
|  |                 oy + (bitH - bitITxt.get_height())/2 | ||||||
|  |             ]) | ||||||
|  |              | ||||||
|  |             # Draw separator | ||||||
|  |             if i != 0: | ||||||
|  |                 pygame.draw.line(self.win, borderCol, [bitX, bitsY], [bitX, bitsY + bitH]) | ||||||
|  |          | ||||||
|  |         ranges = struct.getSortedRanges() | ||||||
|  |         descX = ox + max(0, (struct.bits-12) * bitW) | ||||||
|  |         descY = bitsY + bitH * 2 | ||||||
|  |          | ||||||
|  |         # Names + simple descriptions | ||||||
|  |         for range_ in ranges: | ||||||
|  |             rStartI = struct.bits - range_.end + startBit - 1 | ||||||
|  |              | ||||||
|  |             rStartX = bitsX + rStartI * bitW | ||||||
|  |             rWidth = range_.bits * bitW | ||||||
|  |              | ||||||
|  |             nameTxt = self.font.render(range_.name, True, txtCol) | ||||||
|  |             nameX = rStartX + (rWidth - nameTxt.get_width())/2 | ||||||
|  |             nameY = bitsY + (bitH - nameTxt.get_height())/2 | ||||||
|  |             pygame.draw.rect(self.win, bgCol, [rStartX + bitW/2, nameY, rWidth - bitW, nameTxt.get_height()], 0) | ||||||
|  |             self.win.blit(nameTxt, [nameX, nameY]) | ||||||
|  |  | ||||||
|  |             if range_.description: | ||||||
|  |                 descX, descY = self.drawDescription(range_, rStartX, bitsY, rWidth, descX, descY) | ||||||
|  |          | ||||||
|  |         # Dependencies | ||||||
|  |         for range_ in ranges: | ||||||
|  |             if range_.values is not None and range_.dependsOn is not None: | ||||||
|  |                 descX, descY = self.drawDependency(struct, structures, bitsX, bitsY, range_, descX, descY) | ||||||
|  |          | ||||||
|  |         return descY | ||||||
|  |      | ||||||
|  |     def drawUnderbracket(self, start: float, end: float, bitsY: float) -> None: | ||||||
|  |         bitW = self.config.get("bitWidth") | ||||||
|  |         bitH = self.config.get("bitHeight") | ||||||
|  |          | ||||||
|  |         x0 = start + bitW/2 | ||||||
|  |         x1 = end - bitW/2 | ||||||
|  |         y0 = bitsY + bitH * 1.25 | ||||||
|  |         y1 = bitsY + bitH * 1.5 | ||||||
|  |          | ||||||
|  |         pygame.draw.lines(self.win, self.config.get("linkColor"), False, [ | ||||||
|  |             [x0, y0], | ||||||
|  |             [x0, y1], | ||||||
|  |             [x1, y1], | ||||||
|  |             [x1, y0] | ||||||
|  |         ]) | ||||||
|  |      | ||||||
|  |     def drawLink(self, startX: float, startY: float, endX: float, endY: float) -> None: | ||||||
|  |         bitH = self.config.get("bitHeight") | ||||||
|  |         arrowMargin = self.config.get("arrowMargin") | ||||||
|  |          | ||||||
|  |         pygame.draw.lines(self.win, self.config.get("linkColor"), False, [ | ||||||
|  |             [startX, startY + bitH*1.5], | ||||||
|  |             [startX, endY + bitH/2], | ||||||
|  |             [endX - arrowMargin, endY + bitH/2] | ||||||
|  |         ]) | ||||||
|  |      | ||||||
|  |     def drawDescription(self, | ||||||
|  |                         range_: Range, | ||||||
|  |                         rStartX: float, | ||||||
|  |                         rStartY: float, | ||||||
|  |                         rWidth: float, | ||||||
|  |                         descX: float, | ||||||
|  |                         descY: float) -> tuple[float, float]: | ||||||
|  |  | ||||||
|  |         bitW = self.config.get("bitWidth") | ||||||
|  |         bitH = self.config.get("bitHeight") | ||||||
|  |          | ||||||
|  |         descX = max(descX, rStartX + rWidth/2 + bitW) | ||||||
|  |          | ||||||
|  |         self.drawUnderbracket(rStartX, rStartX + rWidth, rStartY) | ||||||
|  |          | ||||||
|  |         midX = rStartX + rWidth/2 | ||||||
|  |         self.drawLink(midX, rStartY, descX, descY) | ||||||
|  |          | ||||||
|  |         descTxt = self.font.render(range_.description, True, self.config.get("textColor")) | ||||||
|  |         self.win.blit(descTxt, [descX, descY + (bitH - descTxt.get_height())/2]) | ||||||
|  |          | ||||||
|  |         descY += descTxt.get_height() | ||||||
|  |          | ||||||
|  |         if range_.values is not None and range_.dependsOn is None: | ||||||
|  |             descX, descY = self.drawValues(range_.values, descX, descY) | ||||||
|  |          | ||||||
|  |         descY += self.config.get("descriptionMargin") | ||||||
|  |          | ||||||
|  |         return (descX, descY) | ||||||
|  |  | ||||||
|  |     def drawValues(self, values: dict[str, str], descX: float, descY: float) -> tuple[float, float]: | ||||||
|  |         textCol = self.config.get("textColor") | ||||||
|  |         bitW = self.config.get("bitWidth") | ||||||
|  |         gap = self.config.get("valuesGap") | ||||||
|  |          | ||||||
|  |         for val, desc in sorted(values.items(), key=lambda vd: vd[0]): | ||||||
|  |             descY += gap | ||||||
|  |             valTxt = self.italicFont.render(f"{val} = {desc}", True, textCol) | ||||||
|  |             self.win.blit(valTxt, [descX + bitW/2, descY]) | ||||||
|  |             descY += valTxt.get_height() | ||||||
|  |          | ||||||
|  |         return (descX, descY) | ||||||
|  |  | ||||||
|  |     def drawDependency(self, | ||||||
|  |                        struct: Structure, | ||||||
|  |                        structures: dict[str, | ||||||
|  |                        Structure], | ||||||
|  |                        bitsX: float, | ||||||
|  |                        bitsY: float, | ||||||
|  |                        range_: Range, | ||||||
|  |                        descX: float, | ||||||
|  |                        descY: float) -> tuple[float, float]: | ||||||
|  |          | ||||||
|  |         bitW = self.config.get("bitWidth") | ||||||
|  |         bitH = self.config.get("bitHeight") | ||||||
|  |         arrowMargin = self.config.get("arrowMargin") | ||||||
|  |          | ||||||
|  |         rStartI = struct.bits - range_.end - 1 | ||||||
|  |         rStartX = bitsX + rStartI * bitW | ||||||
|  |         rWidth = range_.bits * bitW | ||||||
|  |          | ||||||
|  |         self.drawUnderbracket(rStartX, rStartX + rWidth, bitsY) | ||||||
|  |         prevY = bitsY + bitH * 1.5 | ||||||
|  |         dependRange = struct.ranges[range_.dependsOn] | ||||||
|  |         dependStartI = struct.bits - dependRange.end - 1 | ||||||
|  |         dependStartX = bitsX + dependStartI * bitW | ||||||
|  |         dependWidth = dependRange.bits * bitW | ||||||
|  |         dependMid = dependStartX + dependWidth/2 | ||||||
|  |         self.drawUnderbracket(dependStartX, dependStartX + dependWidth, bitsY) | ||||||
|  |          | ||||||
|  |         for val, data in sorted(range_.values.items(), key=lambda vd: vd[0]): | ||||||
|  |             self.drawArrow(dependMid, prevY, dependMid, descY - arrowMargin) | ||||||
|  |              | ||||||
|  |             valRanges = {} | ||||||
|  |             for i in range(dependRange.bits): | ||||||
|  |                 valRanges[dependRange.end - i] = { | ||||||
|  |                     "name": val[i] | ||||||
|  |                 } | ||||||
|  |              | ||||||
|  |             valStruct = { | ||||||
|  |                 "bits": dependRange.bits, | ||||||
|  |                 "start": dependRange.start, | ||||||
|  |                 "ranges": valRanges | ||||||
|  |             } | ||||||
|  |             valStruct = Structure.load("", valStruct) | ||||||
|  |              | ||||||
|  |             self.drawStructure(valStruct, structures, dependStartX, descY) | ||||||
|  |              | ||||||
|  |             valueRight = dependStartX + dependWidth | ||||||
|  |             self.drawArrow(valueRight + arrowMargin, | ||||||
|  |                            descY + bitH*1.5, | ||||||
|  |                            rStartX - arrowMargin, | ||||||
|  |                            descY + bitH*1.5, | ||||||
|  |                            data["description"]) | ||||||
|  |              | ||||||
|  |             self.drawArrow(rStartX + rWidth - bitW, | ||||||
|  |                            prevY, | ||||||
|  |                            rStartX + rWidth - bitW, | ||||||
|  |                            descY + bitH - arrowMargin) | ||||||
|  |  | ||||||
|  |             prevY = descY + bitH*2 + arrowMargin | ||||||
|  |             descY = self.drawStructure(structures[data["structure"]], structures, rStartX, descY) | ||||||
|  |          | ||||||
|  |         return (descX, descY) | ||||||
|  |  | ||||||
|  |     def drawArrow(self, sx: float, sy: float, ex: float, ey: float, label: str = "") -> None: | ||||||
|  |         dashLen = self.config.get("dashLength") | ||||||
|  |         dashSpace = self.config.get("dashSpace") | ||||||
|  |         arrowSize = self.config.get("arrowSize") | ||||||
|  |         linkCol = self.config.get("linkColor") | ||||||
|  |         textCol = self.config.get("textColor") | ||||||
|  |         arrowLabelDist = self.config.get("arrowLabelDistance") | ||||||
|  |          | ||||||
|  |         start = Vec(sx, sy) | ||||||
|  |         end = Vec(ex, ey) | ||||||
|  |         startEnd = end - start | ||||||
|  |         d = startEnd.norm() | ||||||
|  |          | ||||||
|  |         dashes = int(startEnd.mag() / (dashLen + dashSpace)) | ||||||
|  |          | ||||||
|  |         for i in range(dashes): | ||||||
|  |             a = start + d * i * (dashLen + dashSpace) | ||||||
|  |             b = a + d*dashLen | ||||||
|  |             pygame.draw.line(self.win, linkCol, [a.x, a.y], [b.x, b.y]) | ||||||
|  |          | ||||||
|  |         n = Vec(d.y, -d.x) | ||||||
|  |          | ||||||
|  |         width = arrowSize / 1.5 | ||||||
|  |         p1 = end - d * arrowSize + n * width | ||||||
|  |         p2 = end - d * arrowSize - n * width | ||||||
|  |         pygame.draw.polygon(self.win, linkCol, [ | ||||||
|  |             [end.x, end.y], | ||||||
|  |             [p1.x, p1.y], | ||||||
|  |             [p2.x, p2.y]], 0) | ||||||
|  |          | ||||||
|  |         if label: | ||||||
|  |             txt = self.italicFont.render(label, True, textCol) | ||||||
|  |             self.win.blit(txt, [ | ||||||
|  |                 (start.x + end.x - txt.get_width())/2, | ||||||
|  |                 (start.y + end.y)/2 + arrowLabelDist | ||||||
|  |             ]) | ||||||
							
								
								
									
										26
									
								
								schema.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								schema.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,26 @@ | |||||||
|  | import yaml | ||||||
|  |  | ||||||
|  | from config import Config | ||||||
|  | from renderer import Renderer | ||||||
|  | from structure import Structure | ||||||
|  |  | ||||||
|  | class InstructionSetSchema: | ||||||
|  |     def __init__(self, path: str) -> None: | ||||||
|  |         self.config = Config() | ||||||
|  |         self.path = path | ||||||
|  |         self.load() | ||||||
|  |      | ||||||
|  |     def load(self) -> None: | ||||||
|  |         with open(self.path, "r") as f: | ||||||
|  |             schema = yaml.safe_load(f) | ||||||
|  |  | ||||||
|  |         self.structures = {} | ||||||
|  |          | ||||||
|  |         for id_, data in schema["structures"].items(): | ||||||
|  |             id_ = str(id_) | ||||||
|  |             self.structures[id_] = Structure.load(id_, data) | ||||||
|  |      | ||||||
|  |     def save(self, path: str) -> None: | ||||||
|  |         renderer = Renderer(self.config) | ||||||
|  |         renderer.render(self) | ||||||
|  |         renderer.save(path) | ||||||
							
								
								
									
										35
									
								
								structure.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								structure.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | from __future__ import annotations | ||||||
|  | from range import Range | ||||||
|  |  | ||||||
|  | class Structure: | ||||||
|  |     def __init__(self, | ||||||
|  |                  name: str, | ||||||
|  |                  bits: int, | ||||||
|  |                  ranges: dict[str, Range], | ||||||
|  |                  start: int = 0) -> None: | ||||||
|  |          | ||||||
|  |         self.name = name | ||||||
|  |         self.bits = bits | ||||||
|  |         self.ranges = ranges | ||||||
|  |         self.start = start | ||||||
|  |      | ||||||
|  |     def load(id_: str, data: dict) -> Structure: | ||||||
|  |         ranges = {} | ||||||
|  |         for rSpan, rData in data["ranges"].items(): | ||||||
|  |             rStart, rEnd = Range.parseSpan(str(rSpan)) | ||||||
|  |             ranges[(rStart, rEnd)] = Range.load(rStart, rEnd, rData) | ||||||
|  |          | ||||||
|  |         for range_ in ranges.values(): | ||||||
|  |             if range_.values is not None and range_.dependsOn is not None: | ||||||
|  |                 bits = ranges[range_.dependsOn].bits | ||||||
|  |                 values = {} | ||||||
|  |                 for v, d in range_.values.items(): | ||||||
|  |                     v = str(int(v)).zfill(bits) | ||||||
|  |                     values[v] = d | ||||||
|  |                 range_.values = values | ||||||
|  |          | ||||||
|  |         return Structure(id_, data["bits"], ranges, data.get("start", 0)) | ||||||
|  |  | ||||||
|  |     def getSortedRanges(self) -> list[Range]: | ||||||
|  |         ranges = self.ranges.values() | ||||||
|  |         return list(sorted(ranges, key=lambda r: r.end)) | ||||||
							
								
								
									
										27
									
								
								vec.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vec.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | from __future__ import annotations | ||||||
|  | from math import sqrt | ||||||
|  |  | ||||||
|  | class Vec: | ||||||
|  |     def __init__(self, x: float = 0, y: float = 0) -> None: | ||||||
|  |         self.x = x | ||||||
|  |         self.y = y | ||||||
|  |      | ||||||
|  |     def __add__(self, v: Vec) -> Vec: | ||||||
|  |         return Vec(self.x+v.x, self.y+v.y) | ||||||
|  |      | ||||||
|  |     def __sub__(self, v: Vec) -> Vec: | ||||||
|  |         return Vec(self.x-v.x, self.y-v.y) | ||||||
|  |      | ||||||
|  |     def __mul__(self, f: float) -> Vec: | ||||||
|  |         return Vec(self.x*f, self.y*f) | ||||||
|  |      | ||||||
|  |     def __truediv__(self, f: float) -> Vec: | ||||||
|  |         return Vec(self.x/f, self.y/f) | ||||||
|  |      | ||||||
|  |     def mag(self) -> float: | ||||||
|  |         return sqrt(self.x**2 + self.y**2) | ||||||
|  |      | ||||||
|  |     def norm(self) -> Vec: | ||||||
|  |         mag = self.mag() | ||||||
|  |         if mag == 0: return Vec() | ||||||
|  |         return self/mag | ||||||
		Reference in New Issue
	
	Block a user