Skip to content

Commit

Permalink
Added test cases for constants and other methods in parse
Browse files Browse the repository at this point in the history
  • Loading branch information
TraXIcoN committed Oct 3, 2024
1 parent 23e87c5 commit e1542cb
Show file tree
Hide file tree
Showing 2 changed files with 244 additions and 87 deletions.
3 changes: 2 additions & 1 deletion parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -924,6 +924,7 @@ def make_sverilog(instr_dict):
endpackage
''')
sverilog_file.close()
print("9999999999999999",names_str)
def make_c(instr_dict):
mask_match_str = ''
declare_insn_str = ''
Expand Down Expand Up @@ -1027,7 +1028,7 @@ def make_go(instr_dict):
instr_str += f''' case A{i.upper().replace("_","")}:
return &inst{{ {hex(opcode)}, {hex(funct3)}, {hex(rs1)}, {hex(rs2)}, {signed(csr,12)}, {hex(funct7)} }}
'''

with open('inst.go','w') as file:
file.write(prelude)
file.write(instr_str)
Expand Down
328 changes: 242 additions & 86 deletions test.py
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()

0 comments on commit e1542cb

Please sign in to comment.