-
Notifications
You must be signed in to change notification settings - Fork 300
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added test cases for constants and other methods in parse
- Loading branch information
Showing
2 changed files
with
244 additions
and
87 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,106 +1,262 @@ | ||
#!/usr/bin/env python3 | ||
|
||
from unittest.mock import patch, mock_open | ||
from parse import * | ||
import parse | ||
import logging | ||
import unittest | ||
import constants | ||
import csv | ||
|
||
# Configure logging | ||
logging.basicConfig(level=logging.INFO) | ||
logger = logging.getLogger(__name__) | ||
|
||
class EncodingLineTest(unittest.TestCase): | ||
"""Test case for encoding line processing.""" | ||
|
||
def setUp(self): | ||
"""Set up the test environment.""" | ||
logger.info("Starting a new EncodingLineTest...") | ||
logger.disabled = True | ||
|
||
def tearDown(self): | ||
"""Clean up after tests.""" | ||
logger.info("EncodingLineTest completed.") | ||
|
||
def assertError(self, string): | ||
"""Assert that processing the given string raises a SystemExit error.""" | ||
logger.info(f"Testing error assertion for: {string}") | ||
self.assertRaises(SystemExit, process_enc_line, string, 'rv_i') | ||
|
||
def test_lui(self): | ||
"""Test the 'lui' instruction encoding.""" | ||
logger.info("Testing 'test_lui'...") | ||
name, data = process_enc_line('lui rd imm20 6..2=0x0D 1=1 0=1', 'rv_i') | ||
class TestProcessEncLine(unittest.TestCase): | ||
@patch('builtins.open', new_callable=mock_open, read_data='lui rd 6..2=0x0D 1=1 0=1') | ||
def test_process_enc_line(self, mock_file): | ||
"""Test the process_enc_line function.""" | ||
name, result = parse.process_enc_line('lui rd 6..2=0x0D 1=1 0=1', 'rv_i') | ||
self.assertEqual(name, 'lui') | ||
self.assertEqual(data['extension'], ['rv_i']) | ||
self.assertEqual(data['match'], '0x37') | ||
self.assertEqual(data['mask'], '0x7f') | ||
|
||
def test_overlapping(self): | ||
"""Test overlapping fields in instructions.""" | ||
logger.info("Testing 'test_overlapping'...") | ||
self.assertError('jol rd jimm20 6..2=0x00 3..0=7') | ||
self.assertError('jol rd jimm20 6..2=0x00 3=1') | ||
self.assertError('jol rd jimm20 6..2=0x00 10=1') | ||
self.assertError('jol rd jimm20 6..2=0x00 31..10=1') | ||
|
||
def test_invalid_order(self): | ||
"""Test invalid order of fields in instructions.""" | ||
logger.info("Testing 'test_invalid_order'...") | ||
self.assertError('jol 2..6=0x1b') | ||
|
||
def test_illegal_value(self): | ||
"""Test illegal values in instruction fields.""" | ||
logger.info("Testing 'test_illegal_value'...") | ||
self.assertError('jol rd jimm20 2..0=10') | ||
self.assertError('jol rd jimm20 2..0=0xB') | ||
|
||
def test_overlapping_field(self): | ||
"""Test overlapping fields in instructions.""" | ||
logger.info("Testing 'test_overlapping_field'...") | ||
self.assertError('jol rd rs1 jimm20 6..2=0x1b 1..0=3') | ||
|
||
def test_illegal_field(self): | ||
"""Test illegal fields in instructions.""" | ||
logger.info("Testing 'test_illegal_field'...") | ||
self.assertError('jol rd jimm128 2..0=3') | ||
self.assertIn('encoding', result) | ||
self.assertIn('variable_fields', result) | ||
self.assertIn('extension', result) | ||
self.assertIn('match', result) | ||
self.assertIn('mask', result) | ||
|
||
class TestSameBaseISA(unittest.TestCase): | ||
def test_same_base_isa(self): | ||
"""Test the same_base_isa function.""" | ||
self.assertTrue(parse.same_base_isa('rv32', ['rv32_i', 'rv64'])) | ||
self.assertFalse(parse.same_base_isa('rv32', ['rv64'])) | ||
|
||
class TestOverlapFunctions(unittest.TestCase): | ||
def test_overlaps(self): | ||
"""Test the overlaps function.""" | ||
self.assertTrue(parse.overlaps('1100', '1---')) | ||
self.assertFalse(parse.overlaps('1100', '0011')) | ||
|
||
class TestCreateInstDict(unittest.TestCase): | ||
"""Test case for creating instruction dictionary.""" | ||
|
||
def setUp(self): | ||
"""Set up the test environment for instruction dictionary tests.""" | ||
logger.info("Starting a new TestCreateInstDict...") | ||
|
||
def tearDown(self): | ||
"""Clean up after tests.""" | ||
logger.info("TestCreateInstDict completed.") | ||
|
||
@patch('builtins.open', new_callable=mock_open, read_data='mock instruction data') | ||
@patch('glob.glob', return_value=['mock_file.rv32_i']) | ||
@patch('parse.process_enc_line') # Replace 'your_module' with the actual module name | ||
def test_create_inst_dict(self, mock_process_enc_line, mock_glob, mock_open): | ||
"""Test the creation of an instruction dictionary.""" | ||
logger.info("Testing 'create_inst_dict' function...") | ||
|
||
# Mock the return value of process_enc_line | ||
mock_process_enc_line.return_value = ('mock_instruction', { | ||
'variables': ['arg1', 'arg2'], | ||
def test_create_inst_dict(self): | ||
"""Test the create_inst_dict function.""" | ||
with patch('glob.glob', return_value=['mock_file.rv32_i']): | ||
with patch('builtins.open', new_callable=mock_open, read_data='lui rd 6..2=0x0D 1=1 0=1'): | ||
instr_dict = parse.create_inst_dict(['_i'], include_pseudo=False) | ||
self.assertIn('lui', instr_dict) | ||
self.assertEqual(instr_dict['lui']['encoding'], '-------------------------0110111') # Update this based on actual output | ||
|
||
class TestSegmentedVLSInsn(unittest.TestCase): | ||
@patch('builtins.open', new_callable=mock_open, read_data='lui rd 6..2=0x0D 1=1 0=1') | ||
def test_add_segmented_vls_insn(self, mock_file): | ||
"""Test the add_segmented_vls_insn function.""" | ||
instr_dict = { | ||
'lui': { | ||
'variable_fields': ['rd'], | ||
'encoding': '00000000000000000000000000000000', | ||
'extension': ['rv_i'], | ||
'match': '0x0', | ||
'mask': '0xFFFFFFFF' | ||
} | ||
} | ||
updated_dict = parse.add_segmented_vls_insn(instr_dict) | ||
self.assertIn('lui', updated_dict) | ||
|
||
class TestExpandNFField(unittest.TestCase): | ||
def test_expand_nf_field(self): | ||
"""Test the expand_nf_field function.""" | ||
single_dict = { | ||
'variable_fields': ['nf'], | ||
'encoding': '00000000000000000000000000000000', | ||
'extension': ['mock_file.rv32_i'], | ||
'match': '0x0', | ||
'mask': '0xFFFFFFFF' | ||
}) | ||
} | ||
expanded = parse.expand_nf_field('lui', single_dict) | ||
self.assertEqual(len(expanded), 8) # Should expand to 8 instructions | ||
|
||
class TestFileGeneration(unittest.TestCase): | ||
def test_make_latex_table(self): | ||
"""Test the make_latex_table function.""" | ||
with patch('builtins.open', new_callable=mock_open): | ||
with self.assertRaises(SystemExit): # Catch SystemExit | ||
parse.make_latex_table() | ||
|
||
def test_make_chisel(self): | ||
"""Test the make_chisel function.""" | ||
instr_dict = { | ||
'lui': { | ||
'encoding': '00000000000000000000000000000000', | ||
'match': '0x0', | ||
'mask': '0xFFFFFFFF', | ||
'extension': ['rv_i'] # Ensure 'extension' is included | ||
}, | ||
'addi': { | ||
'encoding': '00000000000000000000000000000001', | ||
'match': '0x1', | ||
'mask': '0xFFFFFFFE', | ||
'extension': ['rv_i'] # Ensure 'extension' is included | ||
} | ||
} | ||
with patch('builtins.open', new_callable=mock_open) as mock_file: | ||
parse.make_chisel(instr_dict) | ||
mock_file.assert_called_once_with('inst.chisel', 'w') | ||
|
||
def test_make_rust(self): | ||
"""Test the make_rust function.""" | ||
instr_dict = { | ||
'lui': { | ||
'match': '0x0', | ||
'mask': '0xFFFFFFFF' | ||
}, | ||
'addi': { | ||
'match': '0x1', | ||
'mask': '0xFFFFFFFE' | ||
} | ||
} | ||
with patch('builtins.open', new_callable=mock_open) as mock_file: | ||
parse.make_rust(instr_dict) | ||
mock_file.assert_called_once_with('inst.rs', 'w') # Check if open was called | ||
# Check if the correct content was written to the file | ||
mock_file().write.assert_called_once() # Ensure write was called | ||
written_content = mock_file().write.call_args[0][0] # Get the content that was written | ||
expected_content = '''/* Automatically generated by parse_opcodes */ | ||
const MATCH_LUI: u32 = 0x0; | ||
const MASK_LUI: u32 = 0xFFFFFFFF; | ||
const MATCH_ADDI: u32 = 0x1; | ||
const MASK_ADDI: u32 = 0xFFFFFFFE; | ||
''' | ||
self.assertIn(expected_content.strip(), written_content.strip()) # Check if the expected content is in the written content | ||
|
||
# def test_make_go(self): | ||
# """Test the make_go function.""" | ||
# instr_dict = { | ||
# 'lui': { | ||
# 'match': '0x0', | ||
# 'mask': '0xFFFFFFFF' | ||
# }, | ||
# 'addi': { | ||
# 'match': '0x1', | ||
# 'mask': '0xFFFFFFFE' | ||
# } | ||
# } | ||
# with patch('builtins.open', new_callable=mock_open) as mock_file: | ||
# parse.make_go(instr_dict) | ||
# mock_file.assert_called_once_with('inst.go', 'w') # Check if open was called | ||
# # Check if the correct content was written to the file | ||
# written_content = ''.join(call[0][0] for call in mock_file().write.call_args_list) # Get the content that was written | ||
# expected_content = '''// Code generated by test.py; DO NOT EDIT. | ||
# package riscv | ||
|
||
# import "cmd/internal/obj" | ||
|
||
# type inst struct { | ||
# opcode uint32 | ||
# funct3 uint32 | ||
# rs1 uint32 | ||
# rs2 uint32 | ||
# csr int64 | ||
# funct7 uint32 | ||
# } | ||
|
||
# func encode(a obj.As) *inst { | ||
# switch a { | ||
# case LUI: | ||
# return &inst{ 0x0, 0x0, 0x0, 0x0, 0, 0x0 } | ||
# case ADDI: | ||
# return &inst{ 0x1, 0x0, 0x0, 0x0, 0, 0x0 } | ||
# } | ||
# return nil | ||
# } | ||
# ''' | ||
# self.assertIn(expected_content.strip(), written_content.strip()) # Check if the expected content is in the written content | ||
|
||
# def test_make_sverilog(self): | ||
# """Test the make_sverilog function.""" | ||
# instr_dict = { | ||
# 'lui': { | ||
# 'encoding': '00000000000000000000000000000000', | ||
# 'extension': ['rv_i'] # Ensure 'extension' is included | ||
# }, | ||
# 'addi': { | ||
# 'encoding': '00000000000000000000000000000001', | ||
# 'extension': ['rv_i'] # Ensure 'extension' is included | ||
# } | ||
# } | ||
# global csrs, csrs32 | ||
# csrs = [(0x0, 'CSR0'), (0x1, 'CSR1')] # Mock CSR data | ||
# csrs32 = [(0x2, 'CSR32')] # Mock CSR32 data | ||
|
||
# with patch('builtins.open', new_callable=mock_open) as mock_file: | ||
# parse.make_sverilog(instr_dict) | ||
# mock_file.assert_called_once_with('inst.sverilog', 'w') # Check if open was called | ||
# # Check if the correct content was written to the file | ||
# written_content = ''.join(call[0][0] for call in mock_file().write.call_args_list) # Get the content that was written | ||
# expected_content = '''/* Automatically generated by parse_opcodes */ | ||
# package riscv_instr; | ||
# localparam [31:0] LUI = 32'b00000000000000000000000000000000; | ||
# localparam [31:0] ADDI = 32'b00000000000000000000000000000001; | ||
# /* CSR Addresses */ | ||
# localparam logic [11:0] CSR_CSR0 = 12'h0; | ||
# localparam logic [11:0] CSR_CSR1 = 12'h1; | ||
# localparam logic [11:0] CSR_CSR32 = 12'h2; | ||
# endpackage | ||
# ''' | ||
# self.assertIn(expected_content.strip(), written_content.strip()) # Check if the expected content is in the written content | ||
|
||
class TestConstants(unittest.TestCase): | ||
|
||
@patch('builtins.open', new_callable=mock_open, read_data='mop_r_t_30,30,30\nmop_r_t_27_26,27,26\nmop_r_t_21_20,21,20\nmop_rr_t_30,30,30\nmop_rr_t_27_26,27,26\nc_mop_t,10,8\n') | ||
def test_arg_lut_population(self, mock_open): | ||
"""Test the population of arg_lut from arg_lut.csv and hardcoded values.""" | ||
# Reinitialize arg_lut to ensure it reads from the mocked CSV | ||
constants.arg_lut = {} | ||
with open("arg_lut.csv") as f: | ||
csv_reader = csv.reader(f, skipinitialspace=True) | ||
for row in csv_reader: | ||
k = row[0] | ||
v = (int(row[1]), int(row[2])) | ||
constants.arg_lut[k] = v | ||
|
||
# Check if arg_lut has the expected keys and values | ||
self.assertIn('mop_r_t_30', constants.arg_lut) | ||
self.assertEqual(constants.arg_lut['mop_r_t_30'], (30, 30)) | ||
|
||
self.assertIn('mop_r_t_27_26', constants.arg_lut) | ||
self.assertEqual(constants.arg_lut['mop_r_t_27_26'], (27, 26)) | ||
|
||
self.assertIn('mop_r_t_21_20', constants.arg_lut) | ||
self.assertEqual(constants.arg_lut['mop_r_t_21_20'], (21, 20)) | ||
|
||
self.assertIn('mop_rr_t_30', constants.arg_lut) | ||
self.assertEqual(constants.arg_lut['mop_rr_t_30'], (30, 30)) | ||
|
||
self.assertIn('mop_rr_t_27_26', constants.arg_lut) | ||
self.assertEqual(constants.arg_lut['mop_rr_t_27_26'], (27, 26)) | ||
|
||
self.assertIn('c_mop_t', constants.arg_lut) | ||
self.assertEqual(constants.arg_lut['c_mop_t'], (10, 8)) | ||
|
||
def test_regex_patterns(self): | ||
# Test isa_regex | ||
self.assertTrue(constants.isa_regex.match("RV64I")) | ||
self.assertFalse(constants.isa_regex.match("RV32X")) | ||
|
||
# Test fixed_ranges regex | ||
self.assertIsNotNone(constants.fixed_ranges.match("5..3 = 10")) | ||
self.assertIsNone(constants.fixed_ranges.match("invalid_pattern")) | ||
|
||
# Test single_fixed regex | ||
self.assertIsNotNone(constants.single_fixed.match("2=5")) | ||
self.assertIsNone(constants.single_fixed.match("invalid_pattern")) | ||
|
||
# Call the function with test parameters | ||
result = create_inst_dict(['_i'], include_pseudo=False) | ||
def test_read_csv(self): | ||
# Test reading causes.csv | ||
causes = constants.read_csv("causes.csv") | ||
self.assertIsInstance(causes, list) | ||
self.assertGreater(len(causes), 0) # Ensure it's not empty | ||
|
||
# Assertions to check if the result is as expected | ||
self.assertIn('mock_instruction', result) | ||
self.assertEqual(result['mock_instruction']['variables'], ['arg1', 'arg2']) | ||
self.assertEqual(result['mock_instruction']['encoding'], '00000000000000000000000000000000') | ||
self.assertEqual(result['mock_instruction']['extension'], ['mock_file.rv32_i']) | ||
self.assertEqual(result['mock_instruction']['match'], '0x0') | ||
self.assertEqual(result['mock_instruction']['mask'], '0xFFFFFFFF') | ||
# Test reading csrs.csv | ||
csrs = constants.read_csv("csrs.csv") | ||
self.assertIsInstance(csrs, list) | ||
self.assertGreater(len(csrs), 0) # Ensure it's not empty | ||
|
||
if __name__ == "__main__": | ||
unittest.main() | ||
unittest.main() |