Add a DEC, NOP, STOP, and basic format tests
This commit is contained in:
@@ -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
|
||||
|
||||
49
src/python/src/gbasm/instructions/dec.py
Normal file
49
src/python/src/gbasm/instructions/dec.py
Normal 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))
|
||||
21
src/python/src/gbasm/instructions/nop.py
Normal file
21
src/python/src/gbasm/instructions/nop.py
Normal 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])
|
||||
21
src/python/src/gbasm/instructions/stop.py
Normal file
21
src/python/src/gbasm/instructions/stop.py
Normal 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])
|
||||
20
src/python/test/cases/format.yaml
Normal file
20
src/python/test/cases/format.yaml
Normal 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
|
||||
---
|
||||
19
src/python/test/cases/format/format.yaml
Normal file
19
src/python/test/cases/format/format.yaml
Normal 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
|
||||
74
src/python/test/cases/instructions/dec.yaml
Normal file
74
src/python/test/cases/instructions/dec.yaml
Normal 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
|
||||
12
src/python/test/cases/instructions/special.yaml
Normal file
12
src/python/test/cases/instructions/special.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
name: nop
|
||||
program: |
|
||||
NOP
|
||||
expected:
|
||||
- 0x00
|
||||
---
|
||||
name: stop
|
||||
program: |
|
||||
STOP
|
||||
expected:
|
||||
- 0x10
|
||||
@@ -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:
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user