Add a DEC, NOP, STOP, and basic format tests

This commit is contained in:
2019-12-21 20:52:18 -08:00
parent 2b4664162b
commit cb222cc6bb
9 changed files with 247 additions and 13 deletions

View File

@@ -6,6 +6,9 @@ import sys
from .instructions import Instruction
from .instructions.inc import Inc
from .instructions.dec import Dec
from .instructions.nop import Nop
from .instructions.stop import Stop
from .arguments import ArgumentType, Argument
from typing import Callable, Dict, List, Optional
@@ -16,7 +19,10 @@ COMMENT_CHAR = '#'
LABEL_SUFFIX = ':'
GB_INSTRUCTIONS = [
Inc()
Nop(),
Stop(),
Inc(),
Dec()
]
def build_instruction_map() -> Dict[str, Instruction]:
@@ -88,8 +94,8 @@ def assemble(lines: str) -> bytes:
# Tokenize
tokens = line.split()
logging.info("Line:", line)
logging.info("Tokens:", tokens)
logging.info("Line: {}".format(line))
logging.info("Tokens: {}".format(tokens))
if len(tokens) == 0:
continue

View File

@@ -0,0 +1,49 @@
from .Instruction import Instruction
from ..arguments.ArgumentTypes import Register8, Register16
from ..arguments import Argument
from typing import Callable, List
class Dec(Instruction):
def __init__(self):
argtypes = [[Register8()], [Register16()]]
super().__init__("DEC", argtypes)
def num_bytes(self, arguments) -> int:
return 1
def to_bytes(self, arguments: List[Argument],
label_resolver: Callable[[str], int]) -> bytes:
if len(arguments) != 1:
raise ValueError("Incorrect number of arguments")
value = arguments[0].value
if value == "BC":
return bytes([0x0B])
if value == "DE":
return bytes([0x1B])
if value == "HL":
return bytes([0x2B])
if value == "SP":
return bytes([0x3B])
if value == "A":
return bytes([0x3D])
if value == "B":
return bytes([0x05])
if value == "C":
return bytes([0x0D])
if value == "D":
return bytes([0x15])
if value == "E":
return bytes([0x1D])
if value == "H":
return bytes([0x25])
if value == "L":
return bytes([0x2D])
if value == "(HL)":
return bytes([0x35])
raise ValueError("Unknown value: {}".format(value))

View File

@@ -0,0 +1,21 @@
from .Instruction import Instruction
from ..arguments import Argument
from typing import Callable, List
class Nop(Instruction):
def __init__(self):
argtypes = [[]]
super().__init__("NOP", argtypes)
def num_bytes(self, arguments) -> int:
return 1
def to_bytes(self, arguments: List[Argument],
label_resolver: Callable[[str], int]) -> bytes:
if len(arguments) != 0:
raise ValueError("Incorrect number of arguments")
return bytes([0x00])

View File

@@ -0,0 +1,21 @@
from .Instruction import Instruction
from ..arguments import Argument
from typing import Callable, List
class Stop(Instruction):
def __init__(self):
argtypes = [[]]
super().__init__("STOP", argtypes)
def num_bytes(self, arguments) -> int:
return 1
def to_bytes(self, arguments: List[Argument],
label_resolver: Callable[[str], int]) -> bytes:
if len(arguments) != 0:
raise ValueError("Incorrect number of arguments")
return bytes([0x10])

View File

@@ -0,0 +1,20 @@
---
name: two_nop
program: |
NOP
NOP
expected:
- 0x00
- 0x00
---
name: unused_labels
program: |
start:
NOP
middle:
NOP
end:
expected:
- 0x00
- 0x00
---

View File

@@ -0,0 +1,19 @@
---
name: two_nop
program: |
NOP
NOP
expected:
- 0x00
- 0x00
---
name: unused_labels
program: |
start:
NOP
middle:
NOP
end:
expected:
- 0x00
- 0x00

View File

@@ -0,0 +1,74 @@
---
name: dec_a
program: |
DEC A
expected:
- 0x3D
---
name: dec_b
program: |
DEC B
expected:
- 0x05
---
name: dec_c
program: |
DEC C
expected:
- 0x0D
---
name: dec_d
program: |
DEC D
expected:
- 0x15
---
name: dec_e
program: |
DEC E
expected:
- 0x1D
---
name: dec_h
program: |
DEC H
expected:
- 0x25
---
name: dec_l
program: |
DEC L
expected:
- 0x2D
---
name: dec_(hl)
program: |
DEC (HL)
expected:
- 0x35
---
name: dec_bc
program: |
DEC BC
expected:
- 0x0B
---
name: dec_de
program: |
DEC DE
expected:
- 0x1B
---
name: dec_hl
program: |
DEC HL
expected:
- 0x2B
---
name: dec_sp
program: |
DEC SP
expected:
- 0x3B

View File

@@ -0,0 +1,12 @@
---
name: nop
program: |
NOP
expected:
- 0x00
---
name: stop
program: |
STOP
expected:
- 0x10

View File

@@ -6,8 +6,10 @@ import yaml
import pytest
import logging
logging.basicConfig(format="")
logging.getLogger().setLevel(logging.INFO)
logging.basicConfig()
logger = logging.getLogger(__name__)
class AssembleCase(object):
@@ -17,28 +19,38 @@ class AssembleCase(object):
self.expected = expected
def find_case_files():
def find_case_files(subdir: str):
test_root = Path(os.path.dirname(os.path.abspath(__file__)))
case_root = test_root / "cases" / "instructions"
case_root = test_root / "cases" / subdir
return case_root.glob("**/*.yaml")
def get_test_cases():
def get_test_cases(subdir: str):
cases = []
files = find_case_files()
files = find_case_files(subdir)
for f in files:
index = 0
with open(str(f), "r") as yaml_file:
test_descs = yaml.safe_load_all(yaml_file)
for desc in test_descs:
case = AssembleCase(desc['name'], desc['program'], bytes(desc['expected']))
try:
case = AssembleCase(desc['name'], desc['program'], bytes(desc['expected']))
except TypeError:
logger.exception("Failed to parse yaml: {}".format(desc))
cases.append(case)
return cases
cases = get_test_cases()
print(cases)
@pytest.mark.parametrize("case", cases, ids=[case.name for case in cases])
instruction_cases = get_test_cases("instructions")
@pytest.mark.parametrize("case", instruction_cases,
ids=[case.name for case in instruction_cases])
def test_assemble_instruction(case):
lines = case.program.split("\n")
assembled = assemble(lines)
assert assembled == case.expected
format_cases = get_test_cases("format")
@pytest.mark.parametrize("case", format_cases,
ids=[case.name for case in format_cases])
def test_format_instruction(case):
lines = case.program.split("\n")
assembled = assemble(lines)
assert assembled == case.expected