Comp Arc Group (4) Report
Comp Arc Group (4) Report
Group Members:
Table of Contents
Part -1: LMC Programming
2
Computer Architecture and Organization
The following table refers to a memory address in the RAM. The online LMC simulator has 100
different memory addresses in the RAM ranging from 00 to 99.
Mnemonic + Name Description OP code
INP(INPUT) Gets input from user and stores it in the accumulator 901
OUT(OUTPUT) Output the value stored in the accumulator 902
LDA(LOAD) Load the accumulator with the contents of the memory 5xx
address given
STA(STORE) Store the value in the accumulator in the memory 3xx
address given
ADD Add the contents of the memory address to the 1xx
accumulator
SUB(SUBTRACT) Subtract the contents of the memory address from the 2xx
accumulator
BRP (BRANCH IF Jump to the address given if the accumulator is +ve 8xx
POSITIVE)
BRZ (BRANCH IF Jump to the address given if the accumulator is 0 7xx
ZERO)
BRA (BRANCH Jump to the address given 6xx
ALWAYS)
HLT(HALT) Stop the code 000
DAT (DATA Used to associate a label to a free memory address
LOCATION)
Q #1) Write a program on LMC that will accept three numbers and outputs the
largest of the three numbers.
Below, we will create a computer program using LMC that takes three inputs and outputs the largest
of the three given inputs.
The following flowchart describes the steps we followed to implement the LMC program for
finding out which one is the largest number out of the three inputs.
3
Computer Architecture and Organization
Input A
Input B
Input C
False True
B is larger C is larger
(C-B) > 0
The LMC program below compares three of the given inputs and outputs the largest of all.
#Input
INP
STA A
INP
STA B
INP
STA C
#Logic
SUB B
BRP CBIG
LDA B
SUB A
BRP BL
BR AL
CBIG: LDA C
SUB A
4
Computer Architecture and Organization
BRP CL
BR AL
#Output
AL: LDA A
OUT
HLT
BL: LDA B
OUT
HLT
CL: LDA C
OUT
HLT
#Data
A: DAT 0
B: DAT 0
C: DAT 0
Q #2) Write a program on LMC to list the prime numbers between 0 and an
input number.
INP
STA num1
INP
STA num2
LDA num1
SUB num2
BRP positive
LDA num2
STA temp
LDA num1
STA num2
LDA temp
STA num1
positive LDA num1
SUB one
BRZ end
LDA num1
BRZ loop
STA div
5
Computer Architecture and Organization
LDA num1
SUB div
LDA div
SUB one
BRZ not_prime
LDA num1
SUB div
BRP loop
Not prime LDA num1
SUB one
STA num1
BRA positive
loop LDA num2
SUB one
STA num2
BRA positive
end HLT
num1 DAT 0
num2 DAT 0
temp DAT 0
div DAT 0
one DAT 1
1. The program prompts the user to input two numbers, which are stored in memory locations as
num1 and num2, in our case we can set either of the two to be 0.
2. The program then checks which number is larger, and if necessary, swaps their values so that
num1 is the smaller number and num2 is the larger number.
3. The program then enters a loop that starts at num1 and ends at num2. For each number in this
range, the program checks if it is a prime number by dividing it by all numbers between 2 and itself
- 1. If the number is prime, it is outputted to the console.
6
Computer Architecture and Organization
4. The program ends when all numbers between num1 and num2 have been checked.
Note that the program uses the LMC instruction BRP, which branches to the specified address if the
accumulator is positive. This is used to check if num1 is less than or greater than num2. If num1 is
less than num2, the program branches to the label positive. If num1 is greater than num2, the
program proceeds directly to the label positive.
The following LMC program calculates the factorial of a given number provided by the user.
7
Computer Architecture and Organization
counter DAT
ONE DAT 1
Here is a quick explanation on how the program works:
1. The code starts by inputting the number and storing it in the memory location num.
2. The factorial variable is initialized with the value of num.
3. The counter variable is also initialized with the value of num.
4. The loop begins with the LOOP label. It subtracts 1 from the counter and checks if it is zero.
If it is zero, the loop ends and the program jumps to the END label.
5. Inside the loop, the factorial variable is multiplied by the counter and the result is stored
back in the factorial variable.
6. The program then jumps back to the LOOP label to repeat the process until
the counter becomes zero.
7. After the loop ends, the program outputs the value of the factorial variable using
the OUT instruction.
8. Finally, the program halts using the HLT instruction.
8
Computer Architecture and Organization
Implementation Details
Programming Language
The program is written in Python due to its simplicity and readability, making it an ideal choice for
simulation projects.
Main Features
1. Direct Mapping:
• A simple mapping technique where each memory block maps to a specific cache line
using the formula:
Cache Index = Block Number % Cache Size
• If the cache line is occupied by a different block, it is overwritten.
2. Associative Mapping:
• Any memory block can be placed in any cache line.
• Replacement occurs when the cache is full, using user-selected strategies:
• FIFO: The oldest block is removed.
• Random: A random block is removed.
3. Set-Associative Mapping:
• Combines direct and associative mapping.
• Cache is divided into sets, and each set can hold a fixed number of blocks.
• Blocks map to a specific set using:
Set Index = Block Number % Number of Sets
• Replacement within a set uses user-selected strategies.
Key Functions
1. Cache Initialization:
• Direct Mapping: Initializes cache lines based on block numbers.
• Associative & Set-Associative Mapping: Initializes cache with sequential memory
blocks.
9
Computer Architecture and Organization
2. Replacement Policy:
• Provides a choice between FIFO and Random replacement strategies when the cache
is full.
3. Simulation:
• Randomly generates memory block requests.
• Determines if the requested block is in cache (hit) or needs to be loaded (miss).
• Updates cache content accordingly.
User Interaction
The program is interactive and provides:
1. Selection of cache mapping techniques.
2. Visualization of cache content after each operation.
3. Replacement strategy selection when the cache is full.
import random
class CacheMapping:
def __init__(self):
self.main_memory = [f"Word-{i}" for i in range(64)] # Simulating main memory
self.cache_size = 8 # Fixed cache size
self.cache = {} # Cache dictionary
self.mapping_type = None # Mapping type
self.replacement_policy = None # Replacement policy
self.associativity = 1 # Default associativity (1 for direct mapping)
def select_mapping_type(self):
print("\n=== Cache Mapping Options ===")
print("1. Direct Mapping")
print("2. Associative Mapping")
print("3. Set-Associative Mapping")
choice = int(input("Select the mapping type (1, 2, or 3): "))
if choice == 1:
self.mapping_type = "Direct"
elif choice == 2:
self.mapping_type = "Associative"
elif choice == 3:
self.mapping_type = "Set-Associative"
self.associativity = int(input("Enter the associativity (e.g., 2 for 2-way set): "))
else:
print("Invalid choice. Defaulting to Direct Mapping.")
self.mapping_type = "Direct"
if self.mapping_type != "Direct":
print("\n=== Replacement Policies ===")
print("1. LRU (Least Recently Used)")
print("2. FIFO (First In, First Out)")
policy_choice = int(input("Select the replacement policy (1 or 2): "))
if policy_choice == 1:
self.replacement_policy = "LRU"
elif policy_choice == 2:
self.replacement_policy = "FIFO"
else:
print("Invalid choice. Defaulting to LRU.")
self.replacement_policy = "LRU"
10
Computer Architecture and Organization
def generate_random_word(self):
return random.choice(self.main_memory)
if word in cache_set.values():
print(f"Cache Hit: {word} found in set {set_index}.")
else:
print(f"Cache Miss: {word} not found in set {set_index}.")
if len(cache_set) >= self.associativity:
self.replace_cache_block(word, set_index)
else:
self.cache[(set_index, len(cache_set))] = word
print(f"Loading {word} into set {set_index}.")
def display_cache(self):
print("\n=== Cache Content ===")
11
Computer Architecture and Organization
if not self.cache:
print("Cache is empty.")
else:
for slot, word in self.cache.items():
print(f"Slot {slot} -> {word}")
def run(self):
self.select_mapping_type()
for _ in range(5): # Simulate 5 random word requests
word = self.generate_random_word()
print(f"\nProcessor requests: {word}")
if self.mapping_type == "Direct":
self.simulate_direct_mapping(word)
elif self.mapping_type == "Associative":
self.simulate_associative_mapping(word)
elif self.mapping_type == "Set-Associative":
self.simulate_set_associative_mapping(word)
self.display_cache()
# Main Program
if __name__ == "__main__":
cache_mapping = CacheMapping()
cache_mapping.run()
Output
=== Cache Mapping Options ===
1. Direct Mapping
2. Associative Mapping
3. Set-Associative Mapping
Select the mapping type (1, 2, or 3): 1
12
Computer Architecture and Organization
13
Computer Architecture and Organization
14
Computer Architecture and Organization
15
Computer Architecture and Organization
16
Computer Architecture and Organization
17
Computer Architecture and Organization
return
def main():
# User input
implementation_type = input("Enter implementation type (V for vertical, H for horizontal): ")
registers = int(input("Enter the number of registers: "))
alu_functions = int(input("Enter the number of supported ALU functions: "))
instruction = input("Enter the instruction to execute (e.g., LOAD, ADD, SUB): ").upper()
bus_organization = input("Enter the number of buses (1, 2, or 3): ")
18
Computer Architecture and Organization
num_buses = int(bus_organization)
if implementation_type.upper() == 'V':
vertical_microprogramming(registers, alu_functions, instruction, num_buses)
elif implementation_type.upper() == 'H':
horizontal_microprogramming(registers, alu_functions, instruction, num_buses)
else:
print("Invalid implementation type. Please try again.")
if __name__ == '__main__':
main()
Output
19
Computer Architecture and Organization
VERTICAL_CONTROL_WORDS = {
"Load R1 to Bus A": "01",
"Load R2 to Bus B": "02",
"Perform R1 + R2 in ALU": "03",
"Perform R1 - R2 in ALU": "04",
"Store result in R3": "05",
"Move R1 to R2": "06",
}
# Functions for initializing registers and processor state
def initialize_registers(num_registers):
"""Initialize processor registers with user input or default values."""
registers = {}
use_default = input("Do you want to set register values manually? (y/n): ").strip().lower()
for i in range(1, num_registers + 1):
if use_default == 'y':
value = int(input(f"Enter value for R{i}: "))
else:
value = 0
registers[f"R{i}"] = value
return registers
def display_processor_state(state):
"""Display the current state of the processor."""
print("\n--- Processor State ---")
print(f"Registers: {state['registers']}")
print(f"ALU Output: {state['alu_output']}")
print(f"Result Register: {state['result_register']}\n")
# Main execution function
def execute_instruction(processor_state, microops, implementation_type):
"""Simulate the execution of an instruction."""
print("\n=== Executing Instruction ===")
sequence = [] # Store microinstruction sequence with binary codes
for i, microop in enumerate(microops, start=1):
20
Computer Architecture and Organization
binary_code = (
HORIZONTAL_CONTROL_WORDS[microop]
if implementation_type == "horizontal"
else VERTICAL_CONTROL_WORDS[microop]
)
sequence.append(f"{microop} ({binary_code})") # Append microinstruction and binary code
print(f"Step {i}: {microop} | Binary: {binary_code}")
# Simulate the effect of the microoperation
if microop == "Perform R1 + R2 in ALU":
processor_state["alu_output"] = (
processor_state["registers"]["R1"] + processor_state["registers"]["R2"]
)
elif microop == "Perform R1 - R2 in ALU":
processor_state["alu_output"] = (
processor_state["registers"]["R1"] - processor_state["registers"]["R2"]
)
elif microop == "Store result in R3":
processor_state["registers"]["R3"] = processor_state["alu_output"]
processor_state["result_register"] = "R3"
elif microop == "Move R1 to R2":
processor_state["registers"]["R2"] = processor_state["registers"]["R1"]
processor_state["result_register"] = "R2"
# Display processor state after each step
display_processor_state(processor_state)
processor_state["clock"] += 1
# Output the microinstruction sequence
output_microinstruction_sequence(sequence)
def output_microinstruction_sequence(sequence):
"""Output the microinstruction sequence in a single line."""
print("\nMicroinstruction Sequence:")
print(" -> ".join(sequence))
# Main program
21
Computer Architecture and Organization
def main():
"""Main function for the microprogrammed control simulator."""
print("Microprogrammed Control Simulator")
print("1. Vertical Implementation")
print("2. Horizontal Implementation")
implementation_choice = input("Select implementation type (1 for Vertical, 2 for Horizontal):
").strip()
implementation_type = "vertical" if implementation_choice == "1" else "horizontal"
# Get processor specifications
num_registers = int(input("Enter the number of registers: "))
instruction = input("Enter the instruction to execute (ADD/SUB/MOVE): ").strip().upper()
# Initialize processor state
registers = initialize_registers(num_registers)
processor_state = {
"registers": registers,
"clock": 0,
"alu_output": None,
"result_register": None
}
# Determine microoperations based on the instruction
if instruction == "ADD":
microops = [
"Load R1 to Bus A",
"Load R2 to Bus B",
"Perform R1 + R2 in ALU",
"Store result in R3"
]
elif instruction == "SUB":
microops = [
"Load R1 to Bus A",
"Load R2 to Bus B",
"Perform R1 - R2 in ALU",
22
Computer Architecture and Organization
23
Computer Architecture and Organization
Vertical Implentation
24
Computer Architecture and Organization
25
Computer Architecture and Organization
class InstructionPipeline:
def __init__(self, instructions):
self.instructions = instructions # List of instructions to execute
self.pipeline_stages = ["Fetch", "Decode", "Execute", "Memory", "Write-back"]
self.pipeline = [] # Current state of the pipeline
self.clock = 0 # Number of clock cycles elapsed
self.completed_instructions = [] # Instructions that have finished execution
def simulate_cycle(self):
"""Simulate one clock cycle of the pipeline."""
self.clock += 1
print(f"\nClock Cycle: {self.clock}")
# Move instructions through the pipeline
for i in range(len(self.pipeline) - 1, -1, -1):
if self.pipeline[i][1] < len(self.pipeline_stages) - 1:
self.pipeline[i][1] += 1
else:
self.completed_instructions.append(self.pipeline.pop(i))
# Fetch a new instruction if available
if len(self.pipeline) < len(self.pipeline_stages) and self.instructions:
self.pipeline.append([self.instructions.pop(0), 0])
# Display the current state of the pipeline
self.display_pipeline()
def display_pipeline(self):
"""Display the current state of the pipeline."""
pipeline_status = ["Empty"] * len(self.pipeline_stages)
for instr, stage in self.pipeline:
pipeline_status[stage] = instr
print("Pipeline State:")
for i, stage in enumerate(self.pipeline_stages):
print(f" {stage}: {pipeline_status[i]}")
26
Computer Architecture and Organization
completed_insts = []
for inst in self.completed_instructions:
completed_insts.append(inst[0])
print(f"Completed Instructions: {completed_insts}")
def simulate(self):
"""Simulate the entire instruction pipeline."""
print("Starting Instruction Pipeline Simulation")
while self.pipeline or self.instructions:
self.simulate_cycle()
if __name__ == "__main__":
instructions =[]
Num_Instructions = int(input("Enter Number of Instructions to be executed: "))
for i in range(Num_Instructions):
instruction = input(f"Enter Instruction {i+1}: ")
instructions.append(instruction)
pipeline = InstructionPipeline(instructions)
pipeline.simulate()
Output
27
Computer Architecture and Organization
28
Computer Architecture and Organization
29