initial commit
This commit is contained in:
commit
ab12333184
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
|
Loading…
Reference in New Issue
Block a user