From f17539a61ccefaaabf4c129088530a577f442e40 Mon Sep 17 00:00:00 2001 From: Craig Thomas Date: Sun, 9 Oct 2022 11:47:59 -0400 Subject: [PATCH] Allow for multi-word declarations. --- README.md | 2 +- cocoasm/instruction.py | 3 ++- cocoasm/operands.py | 15 ++++++++++++-- cocoasm/values.py | 27 +++++++++++++++++++++++++ test/test_integration.py | 10 ++++++++++ test/test_values.py | 43 ++++++++++++++++++++++++++++++++++++++-- 6 files changed, 94 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index d0a2136..0c07670 100644 --- a/README.md +++ b/README.md @@ -474,7 +474,7 @@ as well as the number of cycles used to execute each operation. |-----------|----------------------------------------------------------------------------|-----------------------| | `FCB` | Defines a byte constant value. Separate multiple bytes with `,`. | `FCB $1C,$AA` | | `FCC` | Defines a string constant value enclosed in a matching pair of delimiters. | `FCC "hello"` | -| `FDB` | Defines a two byte constant value. | `FDB $2000` | +| `FDB` | Defines a word constant value. Separate multiple word with `,`. | `FDB $2000,$CAFE` | | `END` | Defines the end of the program. | `END` | | `EQU` | Defines a symbol with a set value. | `SCRMEM EQU $1000` | | `INCLUDE` | Includes another assembly source file at this location. | `INCLUDE globals.asm` | diff --git a/cocoasm/instruction.py b/cocoasm/instruction.py index ef00b26..714b74b 100644 --- a/cocoasm/instruction.py +++ b/cocoasm/instruction.py @@ -80,6 +80,7 @@ class Instruction(NamedTuple): is_16_bit: bool = False is_lea: bool = False is_multi_byte: bool = False + is_multi_word: bool = False INSTRUCTIONS = [ @@ -236,7 +237,7 @@ class Instruction(NamedTuple): Instruction(mnemonic="SET", is_pseudo=True), Instruction(mnemonic="RMB", is_pseudo=True), Instruction(mnemonic="FCB", is_pseudo=True, is_multi_byte=True), - Instruction(mnemonic="FDB", is_pseudo=True), + Instruction(mnemonic="FDB", is_pseudo=True, is_multi_word=True), Instruction(mnemonic="FCC", is_pseudo=True, is_string_define=True), Instruction(mnemonic="SETDP", is_pseudo=True), Instruction(mnemonic="INCLUDE", is_pseudo=True, is_include=True), diff --git a/cocoasm/operands.py b/cocoasm/operands.py index bd86f9c..02d0c4b 100644 --- a/cocoasm/operands.py +++ b/cocoasm/operands.py @@ -10,7 +10,8 @@ from abc import ABC, abstractmethod -from cocoasm.values import NoneValue, Value, NumericValue, DirectNumericValue, ExtendedNumericValue, MultiByteValue +from cocoasm.values import NoneValue, Value, NumericValue, DirectNumericValue, ExtendedNumericValue, MultiByteValue, \ + MultiWordValue from cocoasm.instruction import CodePackage from cocoasm.operand_type import OperandType from cocoasm.exceptions import OperandTypeError, ValueTypeError @@ -190,6 +191,8 @@ def __init__(self, operand_string, instruction): raise OperandTypeError("[{}] is not a pseudo instruction".format(instruction.mnemonic)) if instruction.is_multi_byte: self.value = MultiByteValue(operand_string) if "," in operand_string else Value.create_from_str(operand_string, instruction) + elif instruction.is_multi_word: + self.value = MultiWordValue(operand_string) if "," in operand_string else Value.create_from_str(operand_string, instruction) else: self.value = NoneValue() if instruction.is_include else Value.create_from_str(operand_string, instruction) @@ -215,7 +218,15 @@ def translate(self): ) if self.instruction.mnemonic == "FDB": - return CodePackage(additional=NumericValue(self.value.int, size_hint=4), size=2, max_size=2) + return CodePackage( + additional=self.value, + size=self.value.byte_len(), + max_size=self.value.byte_len() + ) if self.value.is_multi_word() else CodePackage( + additional=NumericValue(self.value.int, size_hint=4), + size=2, + max_size=2 + ) if self.instruction.mnemonic == "RMB": return CodePackage( diff --git a/cocoasm/values.py b/cocoasm/values.py index fbb74dc..cf8f12f 100644 --- a/cocoasm/values.py +++ b/cocoasm/values.py @@ -79,6 +79,7 @@ class ValueType(Enum): LEFT_RIGHT = 7 ADDRESS_EXPRESSION = 8 MULTI_BYTE = 9 + MULTI_WORD = 10 class Value(ABC): @@ -174,6 +175,9 @@ def is_negative(self): def is_multi_byte(self): return self.type == ValueType.MULTI_BYTE + def is_multi_word(self): + return self.type == ValueType.MULTI_WORD + def resolve(self, symbol_table): """ Attempts to resolve the proper value of the object given the supplied symbol table @@ -334,6 +338,29 @@ def is_16_bit(self): return False +class MultiWordValue(Value): + def __init__(self, value): + super().__init__(value) + self.hex_array = [] + self.type = ValueType.MULTI_WORD + if "," not in value: + raise ValueTypeError("multi-word declarations must have a comma in them") + values = value.split(",") + self.hex_array = [NumericValue(x).hex(size=4) for x in values if x != ""] + + def hex(self, size=0): + return "".join(self.hex_array) + + def hex_len(self): + return len(self.hex()) + + def is_8_bit(self): + return False + + def is_16_bit(self): + return False + + class StringValue(Value): """ Represents a numeric value that can be retrieved as an integer or hex value diff --git a/test/test_integration.py b/test/test_integration.py index f65acb8..826e60a 100644 --- a/test/test_integration.py +++ b/test/test_integration.py @@ -854,6 +854,16 @@ def test_multi_byte_declaration(self): program.translate_statements() self.assertEqual([0x55, 0x44, 0x11, 0xAA], program.get_binary_array()) + def test_multi_word_declaration(self): + statements = [ + Statement(" FDB $DEAD,$BEEF"), + Statement(" FDB $CAFE"), + ] + program = Program() + program.statements = statements + program.translate_statements() + self.assertEqual([0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE], program.get_binary_array()) + # M A I N ##################################################################### diff --git a/test/test_values.py b/test/test_values.py index 37444b7..5d1bbb7 100644 --- a/test/test_values.py +++ b/test/test_values.py @@ -10,7 +10,7 @@ from cocoasm.values import NumericValue, StringValue, NoneValue, SymbolValue, \ AddressValue, Value, ExpressionValue, ExplicitAddressingMode, LeftRightValue, \ - MultiByteValue + MultiByteValue, MultiWordValue from cocoasm.instruction import Instruction, Mode from cocoasm.exceptions import ValueTypeError @@ -280,7 +280,7 @@ def test_numeric_negative_int_value_get_negative_correct_16_bit(self): class TestMultiByteValue(unittest.TestCase): """ - A test class for the StringValue class. + A test class for the MultiByteValue class. """ def setUp(self): """ @@ -317,6 +317,45 @@ def test_multi_byte_16_bit_correct(self): self.assertFalse(result.is_16_bit()) +class TestMultiWordValue(unittest.TestCase): + """ + A test class for the StringValue class. + """ + def setUp(self): + """ + Common setup routines needed for all unit tests. + """ + pass + + def test_multi_word_raises_on_no_delimiter(self): + with self.assertRaises(ValueTypeError) as context: + MultiWordValue('$DEAD') + self.assertEqual("multi-word declarations must have a comma in them", str(context.exception)) + + def test_multi_word_no_values_correct(self): + result = MultiWordValue(",") + self.assertEqual("", result.hex()) + self.assertEqual(0, result.hex_len()) + + def test_multi_word_single_value_correct(self): + result = MultiWordValue("$DEAD,") + self.assertEqual("DEAD", result.hex()) + self.assertEqual(4, result.hex_len()) + + def test_multi_word_many_values_correct(self): + result = MultiWordValue("$DEAD,$BEEF") + self.assertEqual("DEADBEEF", result.hex()) + self.assertEqual(8, result.hex_len()) + + def test_multi_byte_8_bit_correct(self): + result = MultiWordValue("$DEAD,$BEEF") + self.assertFalse(result.is_8_bit()) + + def test_multi_byte_16_bit_correct(self): + result = MultiWordValue("$DEAD,$BEEF") + self.assertFalse(result.is_16_bit()) + + class TestStringValue(unittest.TestCase): """ A test class for the StringValue class.