-
Notifications
You must be signed in to change notification settings - Fork 0
/
CPU.py
153 lines (131 loc) · 6.11 KB
/
CPU.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
from Core import Core
from PCBDataStructure import PCBDataStructure
from MainMemory import MainMemory
from threading import Barrier, Lock, Thread
from SimulationStatistics import SimulationStatistics
class CPU:
def __init__(self, hilillos_to_run, quantum):
self.__pcb = PCBDataStructure()
self.threads_barrier = Barrier(2)
self.__dead_barrier = False
self.__killing_lock = Lock() # Lock used to kill the barrier
self.__waiting_lock = Lock()
self.__system_main_memory = MainMemory(self.__pcb, hilillos_to_run)
self.__simulation_statistics = SimulationStatistics()
self.__core0 = Core(0, self)
self.__core1 = Core(1, self)
self.__core_count = 2
self.running_cores = 2
self.__system_clock = 0
self.__default_quantum = quantum
self.__core_finished = False
self.__core_finished_counter = 0
# Data buss, instruction buss, cache 0, cache 1
self.__locks = [Lock(), Lock(), Lock(), Lock()]
self.__lock_owner = [-1, -1, -1, -1]
# Starts the cores for the simulation and prints statistics after the cores are finished
def start_cores(self):
self.__core1.start()
if self.__core_count > 1:
self.__core0.start()
thread = Thread(target=self.print_statistics(), args=())
thread.start()
# Print the statistics
def print_statistics(self):
self.__core0.join()
self.__core1.join()
self.__simulation_statistics.add_cache(0, self.__core0.get_data_cache())
self.__simulation_statistics.add_cache(1, self.__core1.get_data_cache())
self.__simulation_statistics.add_data_memory(self.__system_main_memory.get_data_memory())
self.__simulation_statistics.print_statistics()
print("Simulation Finished")
# Method to use the barrier
def wait(self):
if self.__core_count > 1:
if not self.__core_finished:
try:
barrier_thread_id = self.threads_barrier.wait()
if barrier_thread_id == 0:
self.__system_clock += 1
print("Ciclo de reloj: " + str(self.__system_clock))
except:
self.__system_clock += 1
print("Ciclo de reloj: " + str(self.__system_clock))
else:
self.__system_clock += 1
print("Ciclo de reloj: " + str(self.__system_clock))
if self.__core_finished_counter == 2:
self.__simulation_statistics.add_data_memory(self.__system_main_memory.get_data_memory())
# Method to kill the barrier
def kill_barrier(self):
self.__killing_lock.acquire(True)
if not self.__dead_barrier:
self.threads_barrier.abort()
self.__dead_barrier = True
self.__killing_lock.release()
# Method to acquire specific lock
def acquire__lock(self, lock_index, core_id):
if self.__locks[lock_index].acquire(False):
self.__lock_owner[lock_index] = core_id
return True
return False
# Method to release specific lock
def release_lock(self, lock_index):
self.__lock_owner[lock_index] = -1
self.__locks[lock_index].release()
# Method to release all the locks acquired by the core
def release_locks(self, core_id):
for index in range(0, 4):
if self.__lock_owner[index] == core_id:
self.__locks[index].release()
self.__lock_owner[index] = -1
# Method to get the PCB structure
def get_pcb_ds(self):
return self.__pcb
# Method to get the main memory
def get_main_memory(self):
return self.__system_main_memory
# Method to invalidate
# Receives the number of the core (0 or 1), and the memory_address of the block to change,
# and the new state of that block
def change_state_of_block_on_core_cache(self, core, memory_address, new_state):
if core == 0:
self.__core0.change_cache_block_state(memory_address, new_state)
else:
self.__core1.change_cache_block_state(memory_address, new_state)
# Return if the memory address its on the other core cache
def get_if_mem_address_is_on_core_cache(self, core, memory_address):
if core == 0 or self.__core_count <= 1:
return self.__core0.get_if_mem_address_is_on_self_cache(memory_address)
else:
return self.__core1.get_if_mem_address_is_on_self_cache(memory_address)
# Return the state of the memory address block on the core cache
def get_state_of_mem_address_on_core(self, core, memory_address):
if core == 0 or self.__core_count <= 1:
return self.__core0.get_memory_address_state_on_cache(memory_address)
else:
return self.__core1.get_memory_address_state_on_cache(memory_address)
# Method to store the cache block of the core on the main memory
def store_data_cache_block_on_mm_on_core(self, memory_address, cache_block_new_state, core):
if core == 0 or self.__core_count <= 1:
return self.__core0.store_data_cache_block_on_main_mem(memory_address, cache_block_new_state)
else:
return self.__core1.store_data_cache_block_on_main_mem(memory_address, cache_block_new_state)
# Method to invalidate RL on core, assumes that core has both cores and data bus locks
def invalidate_rl_on_core(self, mem_address, core):
if core == 0 or self.__core_count <= 1:
return self.__core0.invalidate_self_rl(mem_address)
else:
return self.__core1.invalidate_self_rl(mem_address)
# Method to set core finished bool to true
def notify_core_finished(self):
self.__core_finished = True
# Method to get the default quantum
def get_default_quantum(self):
return self.__default_quantum
# Method to get the simulation statistics
def get_simulation_statistics(self):
return self.__simulation_statistics
# Method to increase the finished cores counter
def increase_finished_counter(self):
self.__core_finished_counter += 1