Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a utils cli subcommand #3

Merged
merged 4 commits into from
Aug 21, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,18 @@ If you installed via pip you should now have a binary in your path that you can
dashmips
```

or equivalently

```sh
python -m dashmips
```

## "Compiling"

To compile or run a mips program you run:

```sh
dashmips compile -f FILE.mips
dashmips compile FILE.mips
```

What "compilation" means in dashmips is a conversion of the source file to a json format that is better understood by the program. You can use this json format to inspect the internals of how your mips program is interpreted by dashmips.
Expand Down
45 changes: 24 additions & 21 deletions dashmips/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,11 @@

def main_compile(args: argparse.Namespace) -> int:
"""Compile/Exec mips code."""
if args.file:
program = preprocess(args.file)
program = preprocess(args.FILE)
if args.out:
json.dump(program.to_dict(), args.out)

if args.json:
# Ending matches socket communication
else:
print(json.dumps(program.to_dict()))

if args.vscode:
snippets = generate_snippets()
print(json.dumps(snippets, indent=4))
print("\n\n\n")
print(instruction_name_regex())

return 0


Expand Down Expand Up @@ -75,44 +65,53 @@ def main_docs(args: argparse.Namespace) -> int:
print("Instructions")
print(f"{'format':<35}{'description'}")
print(f"{'------':<35}{'-----------'}")
snips = generate_snippets(examples=True)
snippets = generate_snippets(examples=True)
instr_list = list(Instructions.items())
instr_list.sort(key=lambda i: i[0])
for instrname, instruction in instr_list:
ex_str = snips[instrname]["example"]
desc = snips[instrname]["description"]
ex_str = snippets[instrname]["example"]
desc = snippets[instrname]["description"]
print(f"{ex_str:35}# ", end="")
print(f"{desc}")

return 0


def main_utils(args: argparse.Namespace) -> int:
"""General utilities to help a mips developer."""
if args.snippets:
snippets = generate_snippets()
print(json.dumps(snippets, indent=4))
if args.instruction_regex:
print(instruction_name_regex())
return 0


def main() -> NoReturn:
"""Entry function for Dashmips."""
parser = argparse.ArgumentParser("dashmips")

parser.add_argument("-v", "--version", action="version", version="0.0.11")
parser.add_argument("-v", "--version", action="version", version="0.1.0")

sbp = parser.add_subparsers(title="commands", dest="command")
compileparse = sbp.add_parser("compile", aliases=["c"])
runparse = sbp.add_parser("run", aliases=["r"])
debugparse = sbp.add_parser("debug", aliases=["d"])
docsparse = sbp.add_parser("docs", aliases=["h"])
utilsparse = sbp.add_parser("utils", aliases=["u"])

compileparse.add_argument("-f", "--file", type=argparse.FileType("r", encoding="utf8"), help="Input file")
compileparse.add_argument("FILE", type=argparse.FileType("r", encoding="utf8"), help="Input file")
compileparse.add_argument("-o", "--out", type=argparse.FileType("w", encoding="utf8"), help="Output file name")
compileparse.add_argument("-j", "--json", action="store_true", help="Output json to stdout")
compileparse.add_argument("--vscode", action="store_true", help="Output json for vscode")
compileparse.set_defaults(func=main_compile)

runparse.add_argument("FILE", type=argparse.FileType("r", encoding="utf8"), help="Input file")
runparse.add_argument("-a", "--args", dest="mips_args", nargs="*", help="Arguments to pass into the mips main")
runparse.add_argument("-t", "--vt100", action="store_true", help="Start VT100 Simulator")
runparse.add_argument("--vt100", action="store_true", help="Start VT100 Simulator")
runparse.set_defaults(func=main_run)

debugparse.add_argument("FILE", type=argparse.FileType("r", encoding="utf8"), help="Input file")
debugparse.add_argument("-a", "--args", dest="mips_args", nargs="*", help="Arguments to pass into the mips main")
debugparse.add_argument("-t", "--vt100", action="store_true", help="Start VT100 Simulator")
debugparse.add_argument("--vt100", action="store_true", help="Start VT100 Simulator")
debugparse.add_argument("-p", "--port", type=int, default=2390, help="run debugger on port")
debugparse.add_argument("-i", "--host", default="0.0.0.0", help="run debugger on host")
debugparse.add_argument("-l", "--log", dest="log", action="store_true", help="Log all network traffic")
Expand All @@ -122,6 +121,10 @@ def main() -> NoReturn:
docsparse.add_argument("-i", "--instr", action="store_true", help="Show instruction table")
docsparse.set_defaults(func=main_docs)

utilsparse.add_argument("--snippets", action="store_true", help="Output snippets json")
utilsparse.add_argument("--instruction_regex", action="store_true", help="Output regex that matches instructions")
utilsparse.set_defaults(func=main_utils)

prog_args = parser.parse_args()
if not hasattr(prog_args, "func"):
# This is for python 3.6 compatibility
Expand Down
30 changes: 6 additions & 24 deletions dashmips/debugger.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,19 @@
import os
from typing import List, Dict, Any, Tuple

from .utils import MipsException
from .models import MipsProgram
from .run import next_instruction, run
from .utils import MipsException


def debug_start(program: MipsProgram, params=None) -> Dict[str, int]:
"""Debug start.

:param operation: dict
:param program: MipsProgram
"""
"""Debug start."""
program.registers["pc"] = program.labels["main"].value
return {"pid": os.getpid()}


def debug_step(program: MipsProgram, params) -> Dict[str, Any]:
"""Debug step.

:param operation: dict
:param program: MipsProgram
"""
"""Debug step."""
try:
next_instruction(program)

Expand All @@ -43,20 +35,14 @@ def debug_step(program: MipsProgram, params) -> Dict[str, Any]:


def debug_continue(program: MipsProgram, params) -> Dict[str, Any]:
"""Debug continue.

:param program: MipsProgram
"""
"""Debug continue."""
starting_pc = program.registers["pc"]
# vscode should have done the translation
# these are pc values (aka index into srclines)
verified, breakpoints = verify_breakpoints(program, params)

def breaking_condition(program: MipsProgram) -> bool:
"""Condition function to stop execution.

:param program:
"""
"""Condition function to stop execution."""
nonlocal starting_pc
if program.registers["pc"] == starting_pc:
# current instruction will execute even if on breakpoint
Expand All @@ -79,11 +65,7 @@ def breaking_condition(program: MipsProgram) -> bool:


def debug_stop(program: MipsProgram, params) -> Dict[str, bool]:
"""Stop messages incoming mean nothing to a server.

:param operation: dict
:param program: MipsProgram
"""
"""Stop messages incoming mean nothing to a server."""
return {"exited": True}


Expand Down
56 changes: 10 additions & 46 deletions dashmips/directives.py
Original file line number Diff line number Diff line change
@@ -1,91 +1,55 @@
"""Directive handling."""
from typing import Union

from .utils import parse_int, bytesify
from .hardware import Memory
from .utils import parse_int, bytesify, MipsException


def directive_align(data: str, memory: Memory):
"""Align directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
raise Exception("Unsupported directive.")
"""Align directive."""
raise MipsException("Unsupported directive.")
return None


def directive_asciiz(data: str, memory: Memory) -> int:
"""Asciiz directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
"""Asciiz directive."""
string = data[1:-1].encode("ascii", "ignore").decode("unicode_escape")
address = memory.extend_data(bytesify(string, null_byte=True))
return address


def directive_ascii(data: str, memory: Memory) -> int:
"""Ascii directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
"""Ascii directive."""
string = data[1:-1].encode("ascii", "ignore").decode("unicode_escape")
address = memory.extend_data(bytesify(string, null_byte=False))
return address


def directive_byte(data: str, memory: Memory) -> int:
"""Byte directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
"""Byte directive."""
value = bytesify(parse_int(data), size=1)
address = memory.extend_data(value)
return address


def directive_half(data: str, memory: Memory) -> int:
"""Half directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
"""Half directive."""
value = bytesify(parse_int(data), size=2)
address = memory.extend_data(value)
return address


def directive_word(data: str, memory: Memory) -> int:
"""Word directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
"""Word directive."""
value = bytesify(parse_int(data), size=4)
address = memory.extend_data(value)
return address


def directive_space(data: str, memory: Memory) -> int:
"""Space directive.
:param name: str:
:param data: str:
:param memory: Memory:
"""
"""Space directive."""
value = parse_int(data)
if value > 0x77359400:
# 2 Gigabytes of space...
raise Exception("Please use less memory...")
raise MipsException("Please use less memory...")
address = memory.extend_data(bytes([0] * value))
return address
3 changes: 1 addition & 2 deletions dashmips/extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,14 @@ def generate_snippets(examples: bool = False) -> Dict[str, Dict[str, str]]:
"scope": "mips",
}
if examples:
example = build_example(ins.name, ins.pattern, ins.label)
example = build_example(ins.name, ins.pattern)
snippets[name]["example"] = example
return snippets


def build_body(name: str, pattern: str, label: bool) -> str:
"""Create snippet body.
:param label:
:param name: Instruction name
:param pattern: Instruction regex pattern
"""
Expand Down
9 changes: 4 additions & 5 deletions dashmips/instructions/Instruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,8 @@
class Instruction:
"""Instruction Class, callable."""

def __init__(self, fn, regex_ptrn: str, parser, label: bool = False):
"""
Regex and argument parser for instruction.
def __init__(self, fn, regex_pattern: str, parser, label: bool = False):
"""Regex and argument parser for instruction.

Adds itself to list upon instantiation.
"""
Expand All @@ -27,8 +26,8 @@ def __init__(self, fn, regex_ptrn: str, parser, label: bool = False):
self.description = ""

self.label = label
self.pattern = regex_ptrn
self.regex = f"({self.name}){regex_ptrn}".format(**RE.ALL)
self.pattern = regex_pattern
self.regex = f"({self.name}){regex_pattern}".format(**RE.ALL)
self.parser = parser

def __call__(self, program: MipsProgram, args: Iterable[Any] = tuple()):
Expand Down
12 changes: 2 additions & 10 deletions dashmips/instructions/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,16 @@
NOTE: If you add a new file/module to this package *YOU MUST*
import the file to `dashmips/__init__.py`
"""
from typing import Union

from .Instruction import Instruction

Instructions = {}


def mips_instruction(pattern: str, parser, label: bool = False):
"""Make an Instruction object from decorated function.
:param pattern: param parser:
:param parser:
"""
"""Make an Instruction object from decorated function."""
def decorator(function) -> Instruction:
"""Instruction Decorator wrapper.
:param function:
"""
"""Instruction Decorator wrapper."""
instr = Instruction(function, pattern, parser, label=label)
Instructions[instr.name] = instr
return instr
Expand Down
17 changes: 3 additions & 14 deletions dashmips/instructions/imm_instructions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,18 @@


def parse(args: Tuple[str, str, str]) -> Tuple[str]:
"""Parse label to pass to instruction function.

:param args:
"""
"""Parse label to pass to instruction function."""
return (args[2],)


@mips_instruction(PATTERN, parse, label=True)
def j(program: MipsProgram, address: str):
"""Jump unconditionally to label.

:param program:
:param address:
"""
"""Jump unconditionally to label."""
program.registers["pc"] = program.labels[address].value - 1


@mips_instruction(PATTERN, parse, label=True)
def jal(program: MipsProgram, address: str):
"""Jump unconditionally to label and set $ra to current $pc.

:param program:
:param address:
"""
"""Jump unconditionally to label and set $ra to current $pc."""
program.registers["$ra"] = program.registers["pc"] + 1
program.registers["pc"] = program.labels[address].value - 1
Loading