From 04b6ed4c4bc98fe76292ca1d8530b077c8c9741f Mon Sep 17 00:00:00 2001 From: Brandon Rodriguez <brodriguez8774@gmail.com> Date: Sat, 29 Feb 2020 22:17:43 -0500 Subject: [PATCH] Update project to work with direct mapped class video example --- documents/references.md | 15 ++++ main.py | 149 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 155 insertions(+), 9 deletions(-) diff --git a/documents/references.md b/documents/references.md index 31804cf..2ebef18 100644 --- a/documents/references.md +++ b/documents/references.md @@ -8,6 +8,21 @@ Includes anything from stack overflow links to notes about logic from previous w ### Parsing Command Line Args with ArgParse <https://docs.python.org/3/library/argparse.html> +### Display Int as Binary +<https://stackoverflow.com/a/699891> + +### Exponents and Logarithms +<https://docs.python.org/3.8/library/math.html#power-and-logarithmic-functions> + +### Splitting a String on Regex Match +<https://stackoverflow.com/a/13209313> + +### Dynamically Creating Bit Masks +<https://stackoverflow.com/a/26303439> + +### Bitwise Operations +<https://www.tutorialspoint.com/python/bitwise_operators_example.htm> + ## Makefile * Purpose of ".PHONY" - <https://stackoverflow.com/a/2145605> diff --git a/main.py b/main.py index 14eb0de..f2eb6c9 100644 --- a/main.py +++ b/main.py @@ -10,25 +10,156 @@ Simulates system use of a cache for data storage. Cache Settings Arguments: * S: Number of sets in cache. * E: Lines per set. - * B: Block size (number of bits per block). + * B: Block size (number of bytes per block). + * s: Bit count to identify set. + * e: Bit count to identify line. + * b: Bit count to identify block. """ # System Imports. -import argparse +import argparse, math, re # User Imports. -def main(set_count, line_count, block_size, file_name, verbose): +def main(set_identifier_bit_count, line_count, block_identifier_bit_count, file_name, verbose): """ Program main. """ print('main():') - print(' set_count: {0}'.format(set_count)) + print(' set_identifier_bit_count: {0}'.format(set_identifier_bit_count)) print(' line_count: {0}'.format(line_count)) - print(' block_size: {0}'.format(block_size)) + print(' block_identifier_bit_count: {0}'.format(block_identifier_bit_count)) print(' file_name: {0}'.format(file_name)) print(' verbose: {0}'.format(verbose)) + print('') + + # Calculate total sizes of cache structures. + s = set_identifier_bit_count + S = set_count = int(math.pow(2, s)) + E = line_count + e = line_identifier_bit_count = math.log2(E) + b = block_identifier_bit_count + B = block_size = int(math.pow(2, b)) + m = address_identifier_bit_count = E * S + M = total_bytes = int(math.pow(2, m)) + C = capacity = S * E * B + tag_identifier_bit_count = m - (b + s) + + # Create cache object. + cache = [] + for set in range(set_count): + cache.append([]) + + # Create lines in set. + for line in range(line_count): + cache[len(cache) - 1].append({ + 'valid': False, + 'tag': 0, + 'block': 0, + }) + + # print('Address Bit Count: {0}'.format(address_identifier_bit_count)) + # print('B: {0}'.format(B)) + # print('S: {0}'.format(S)) + # print('E: {0}'.format(E)) + # print('Tag Bits: {0}'.format(tag_identifier_bit_count)) + # print('Cache: {0}'.format(cache)) + + run_simulation(cache, file_name, M, B, S) + + +def run_simulation(cache, file_name, M, B, S): + """ + + :param cache: + :return: + """ + hits = 0 + misses = 0 + evictions = 0 + + # Open file to read in values. + with open(file_name) as file: + # Read in line. + for line in file: + # print('Line: {0}'.format(line)) + cache, hits, misses, evictions = handle_line(cache, line, M, B, S, hits, misses, evictions) + + # print('M: {0} As Bits: {1:b}'.format(M, M - 1)) + # print('B: {0} As Bits: {1:b}'.format(B, B - 1)) + # print('S: {0} As Bits: {1:b}'.format(S, S - 1)) + + print('hits:{0} misses:{1} evictions:{2}'.format(hits, misses, evictions)) + + +def handle_line(cache, line, M, B, S, hits, misses, evictions): + """ + + :param cache: + :param line: + :return: + """ + split_line = re.split(r'[ ,\n]', line) + # print('split_line: {0}'.format(split_line)) + + # Check if instruction load. If so, we can skip line. + if split_line[0] == 'I': + # Found instruction load. Returning. + return + else: + line = line.strip() + + # Not an instruction load. Keep processing. Start by getting address. + address = int(split_line[2]) % M + value_size = int(split_line[3]) + + # Get mask values. + full_mask = M - 1 + block_mask = B - 1 + set_mask = S + B + tag_mask = set_mask + block_mask + 1 + + # print('Address: {0} As Bits: {0:b}'.format(address)) + # print('full_mask: {0} As Bits: {0:b}'.format(full_mask)) + # print('block_mask: {0} As Bits: {0:b}'.format(block_mask)) + # print('set_mask: {0} As Bits: {0:b}'.format(set_mask)) + # print('tag_mask: {0} As Bits: {0:b}'.format(tag_mask)) + + # Use masks to get address chunks. + block = address & block_mask + set = (address & set_mask) - B - 1 + tag = address & tag_mask + + # print('block: {0:b}'.format(block)) + # print('set: {0:b}'.format(set)) + # print('tag: {0:b}'.format(tag)) + + # We have our values. Now compare against the cache. + # print('set: {0}'.format(set)) + # print('cache[set]: {0}'.format(cache[set])) + if cache[set][0]['valid'] == True and cache[set][0]['tag'] == tag: + # Match found. + print('{0} hit'.format(line)) + hits += 1 + else: + # Not a match. Examine why. + misses += 1 + if cache[set][0]['valid'] == True: + # Cache location was set, but tag did not match. Conflict miss. + print('{0} miss eviction'.format(line)) + cache[set][0]['tag'] = tag + else: + # Cache location was not set. Cold miss. + print('{0} miss'.format(line)) + cache[set][0]['valid'] = True + cache[set][0]['tag'] = tag + evictions += 1 + # print('cache: {0}'.format(cache)) + + return (cache, hits, misses, evictions) + + if __name__ == '__main__': @@ -37,13 +168,13 @@ if __name__ == '__main__': # Define our argparser and get command line args. parser = argparse.ArgumentParser(description='Cache Simulator') parser.add_argument('-v', '-V', action='store_true', default=False, help='Flag for verbose mode.', dest='verbose') - parser.add_argument('-s', '-S', action='store', required=True, help='Total sets.', dest='set_count') - parser.add_argument('-e', '-E', action='store', required=True, help='Lines per set.', dest='line_count') - parser.add_argument('-b', '-B', action='store', required=True, help='Bits per block.', dest='block_size') + parser.add_argument('-s', action='store', required=True, help='Total sets.', dest='set_count') + parser.add_argument('-E', action='store', required=True, help='Lines per set.', dest='line_count') + parser.add_argument('-b', action='store', required=True, help='Bytes per block.', dest='block_size') parser.add_argument('-t', '-T', action='store', required=True, help='File to read in.', dest='file_name') args = parser.parse_args() # If args parsed properly, run program main. - main(args.set_count, args.line_count, args.block_size, args.file_name, args.verbose) + main(int(args.set_count), int(args.line_count), int(args.block_size), args.file_name, args.verbose) print('Terminating program.') -- GitLab