Skip to content

Commit

Permalink
Fully close issue ucu-computer-science#7
Browse files Browse the repository at this point in the history
  • Loading branch information
MykhailoBronytskyi committed Nov 1, 2022
1 parent f320ee6 commit eb9c7dc
Show file tree
Hide file tree
Showing 49 changed files with 226 additions and 204 deletions.
2 changes: 1 addition & 1 deletion docs/INSTRUCTION_SET.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ This emphasizes the complexity of CISC instructions and eases the actual program

## Instructions for each architecture with short descriptions

| RISC STACK | RISC ACCUMULATOR | RISC REGISTER | CISC REGISTER |
| STACK | ACCUMULATOR | REGISTER | REGISTER |
|------------|------------------|---------------|---------------|
| **Registers** ||||
| *```tos``` - Points to the top of the register stack in the memory* | *```acc``` - Points to the accumulator register*| *```R00``` - General-purpose 16-bit word, R00H-high byte, R00L-low byte; ```R01``` - General-purpose 16-bit word, R01H-high byte, R01L-low byte; ```R02``` - General-purpose 16-bit word, R02H-high byte, R02L-low byte; ```R03``` - General-purpose 16-bit word, R03H-high byte, R03L-low byte;* | *```R00``` - General-purpose 16-bit word, R00H-high byte, R00L-low byte; ```R01``` - General-purpose 16-bit word, R01H-high byte, R01L-low byte; ```R02``` - General-purpose 16-bit word, R02H-high byte, R02L-low byte; ```R03``` - General-purpose 16-bit word, R03H-high byte, R03L-low byte;* |
Expand Down
6 changes: 3 additions & 3 deletions docs/help.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"risc1": [
"stack": [
"Instruction Set for Stack ISA",
{
"name": "load",
Expand Down Expand Up @@ -226,7 +226,7 @@
"description": "Does not do anything"
}
],
"risc2": [
"accumulator": [
"Instruction Set for Accumulator ISA",
{
"name": "load",
Expand Down Expand Up @@ -513,7 +513,7 @@
"description": "Does not do anything"
}
],
"risc3": [
"risc": [
"Instruction Set for RISC-Register ISA",
{
"name": "load",
Expand Down
4 changes: 2 additions & 2 deletions docs/progress_tracker.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
1. ~~RISC-Register final tests for every instruction~~
1. ~~Stack ISA advanced instructions tests~~
1. ~~Accumulator ISA advanced instructions tests~~
1. ~~Alphabet output example program (RISC1, RISC2, RISC3, CISC)~~
1. ~~Hello world output example program (RISC1, RISC2, RISC3, CISC)~~
1. ~~Alphabet output example program (Stack, Accumulator, RISC, CISC)~~
1. ~~Hello world output example program (Stack, Accumulator, RISC, CISC)~~
1. ~~Add more example programs showcasing something more or less meaningful (bubble sorting, polynomial calculation)~~

#### Bonus advanced functionality:
Expand Down
14 changes: 7 additions & 7 deletions modules/assembler.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ def __init__(self):
# Creating the command line parser and main arguments
parser = argparse.ArgumentParser()
parser.add_argument("-f", "--file", help="provide the assembly program filepath")
parser.add_argument("--isa", help="specify the ISA architecture: RISC1 (Stack), "
"RISC2 (Accumulator), RISC3 (Register), CISC (Register)")
parser.add_argument("--isa", help="specify the ISA architecture: Stack, "
"Accumulator, RISC (Register), CISC (Register)")
parser.add_argument("-o", "--output", help="Specify the output file")

# Parsing the command line arguments
Expand All @@ -75,7 +75,7 @@ def __init__(self):
raise AssemblerError("Assembly program filepath not provided")

# Check if the ISA is provided and actually exists
valid_isa = ['risc1', 'risc2', 'risc3', 'cisc']
valid_isa = ['stack', 'accumulator', 'risc', 'cisc']
if not args.isa or args.isa.lower() not in valid_isa:
raise AssemblerError("Specify the valid instruction set architecture")

Expand Down Expand Up @@ -126,7 +126,7 @@ def __init__(self, isa, program_text):
self.register_names = {register[0]: register[2] for register in registers}

# Determining the size of the instructions to read
instruction_sizes = {"risc1": (6, 6), "risc2": (8, 8), "risc3": (16, 6), "cisc": (8, 8)}
instruction_sizes = {"stack": (6, 6), "accumulator": (8, 8), "risc": (16, 6), "cisc": (8, 8)}
self.instruction_size = instruction_sizes[isa]
self.jump_label_allowed = ["jmp", "call", "je", "jne", "jl", "jle", "jg", "jge", "jc"]
self.mov_label_allowed = ["mov", "load", "store", "push", "mov_low", "mov_high", "cmp", "cmpe", "cmpb", "mul",
Expand Down Expand Up @@ -444,11 +444,11 @@ def __encode_operands(self, operands, instruction_info, instruction_name, instru
else:
num = int(operand[1:])

# RISC-Stack has to divide the number into two 6-bit bytes
# RISC-Accumulator and CISC have to divide the number into two 8-bit bytes
# Stack has to divide the number into two 6-bit bytes
# Accumulator and CISC have to divide the number into two 8-bit bytes
# Immediate constant length is undefined for Risc-Register architecture,
# and thus is set for every instruction
bit_lengths = {"risc1": "12", "risc2": "16", "risc3": op_type[3:], "cisc": "16"}
bit_lengths = {"stack": "12", "accumulator": "16", "risc": op_type[3:], "cisc": "16"}
bit_len = int(bit_lengths[self.isa])

# Check if the size of the number is valid
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Alphabet PrintOut | Accumulator-RISC example Assembly program
# Alphabet PrintOut | Accumulator example Assembly program

# Following instructions printout the alphabet
# Directive .start contains starting point (ASCII-code of A)
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Bubble Sort | Accumulator-RISC example Assembly program
# Bubble Sort | Accumulator example Assembly program

# These instructions sort a manually 'created' list
# Directive .start contains the starting index of the list (0 in that example)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Hello World PrintOut | Accumulator-RISC example Assembly program
# Hello World PrintOut | Accumulator example Assembly program

# Push the ASCII encodings onto the stack, and load the first letter into ACC register
# Directive .end contains last element 'Hello World!'
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Polynomial Calculation | Accumulator-RISC example Assembly program
# Polynomial Calculation | Accumulator example Assembly program

# These instructions calculate a value of a polynomial expression
# In that example polynomial is 2*x^2 + 3*x - 7, x = 2
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
25 changes: 25 additions & 0 deletions modules/demos/risc/bubble_sort.bin
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
0001101100000010
0001101000000000
0001100000000000
1010000000000000
0000010000100000
0000110100100110
0000010010100000
0101010000010000
0111110000001010
1010000000000000
0001010000010000
1010010010000000
0001000100100110
0000100100000000
0000110100100110
0000100100010000
1010010000000000
1010000110000000
0101100100000110
0111101111110001
0001100000000000
1010010000000000
0101010000110000
0110101111101001
1000110000000000
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Alphabet PrintOut | Stack-RISC example Assembly program
# Alphabet PrintOut | Stack example Assembly program

# Following instructions printout the alphabet
# Directive .start contains starting point (ASCII-code of A)
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Bubble Sort | Stack-RISC example Assembly program
# Bubble Sort | Stack example Assembly program

# These instructions sort a manually 'created' list
# Directive .start contains the starting index of the list (0 in that example)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Hello World PrintOut | Stack-RISC example Assembly program
# Hello World PrintOut | Stack example Assembly program

# These next instructions load ASCII encodings of characters in "Hello world!" into the register stack
# backwards, so that when the values are popped from the stack, we can output the values in a normal way
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Polynomial Calculation | Stack-RISC example Assembly program
# Polynomial Calculation | Stack example Assembly program

# These instructions calculate a value of a polynomial expression
# In that example polynomial is 2*x^2 + 3*x - 7, x = 2
Expand Down
6 changes: 3 additions & 3 deletions modules/instructions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"comments": "Each architecture contains a dict of instructions: encoding, name, result destination and list of operands",
"risc1": {
"stack": {
"000000": [
"halt",
"halt"
Expand Down Expand Up @@ -347,7 +347,7 @@
[]
]
},
"risc2": {
"accumulator": {
"00000000": [
"halt",
"halt"
Expand Down Expand Up @@ -785,7 +785,7 @@
[]
]
},
"risc3": {
"risc": {
"000000": [
"halt",
"halt",
Expand Down
46 changes: 22 additions & 24 deletions modules/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ def __init__(self, isa, architecture, io_arch, program_text, program_start=512,
self.instructions_dict = json.load(file)[self.isa]

# Determining the size of the instructions to read (size of the instruction, opcode size, byte size)
instruction_sizes = {"risc1": (6, 6, 6), "risc2": (8, 8, 8), "risc3": (16, 6, 8), "cisc": (8, 8, 8)}
instruction_sizes = {"stack": (6, 6, 6), "accumulator": (8, 8, 8), "risc": (16, 6, 8), "cisc": (8, 8, 8)}
self.instruction_size = instruction_sizes[self.isa]

# Set the instruction pointer to the starting point of the program and load the specified program into memory
Expand Down Expand Up @@ -281,7 +281,7 @@ def __read_instruction(self):

# If the first bit of the encoded binary instruction indicates that the next two
# bytes are going to be an immediate constant, change the read_state
if self.isa in ["risc1", "risc2"] and self.opcode[0]:
if self.isa in ["stack", "accumulator"] and self.opcode[0]:
constant_reader = 1
elif self.isa == "cisc":
# Styles of CISC architecture with counters for register and constant readers
Expand Down Expand Up @@ -386,9 +386,9 @@ def execute(self):
start_point = self.__determine_start_point()

# Reading the list of operands encoded in the binary instruction
if self.isa in ["risc3", "cisc"]:
if self.isa in ["risc", "cisc"]:
operands_aliases = self.instructions_dict[self.opcode.to01()][-1]
elif self.isa == "risc1":
elif self.isa == "stack":
operands_aliases = self.instructions_dict[self.opcode.to01()][1][1:]
else:
operands_aliases = self.instructions_dict[self.opcode.to01()][1]
Expand All @@ -406,7 +406,7 @@ def execute(self):
f"Destination: {result_destination}, TOS_Push: {tos_push})")

# Different architectures have different kinds of instructions encodings
if self.isa in ["risc3", "cisc"]:
if self.isa in ["risc", "cisc"]:
res_type = self.instructions_dict[self.opcode.to01()][1]
else:
res_type = self.instructions_dict[self.opcode.to01()][1][0]
Expand All @@ -416,15 +416,15 @@ def execute(self):

# Remember the next instruction after the one which called the 'call' function
next_instruction = self.program_pointer + 1
if self.isa == "risc3":
if self.isa == "risc":
self.registers["LR"].write_data(bin(next_instruction)[2:])
else:
self.__push_stack(bitarray(bin(next_instruction)[2:].rjust(16, '0')))

# There is only one operand for a call function, and it determines the program_start from the IP
operand = operands_aliases[0]
if operand.startswith("imm") or ((len(operands_aliases) > 1) and operands_aliases[1] == "imm"):
if self.isa == "risc3":
if self.isa == "risc":
# Calculate the new location of the instruction pointer, change it
imm_len = int(operand[3:])
jump_num = twos_complement(int(operands_values[0].to01(), 2), imm_len)
Expand Down Expand Up @@ -456,7 +456,7 @@ def execute(self):
# TODO: Should we zero out the Link Register register after returning to it once?
# In RISC-Register architecture we retrieve the caller address in the Link Register,
# otherwise we just pop it on the stack
if self.isa == "risc3":
if self.isa == "risc":
return_point = int(self.registers["LR"]._state.to01(), 2)
else:
return_point = int(self.__pop_stack().to01(), 2)
Expand Down Expand Up @@ -504,13 +504,13 @@ def execute(self):

# If the program_start was specified with the number, its length was specified as well
# Else, just use the register length or long immediate length
if operands_aliases[0].startswith("imm") and self.isa == "risc3":
if operands_aliases[0].startswith("imm") and self.isa == "risc":
num_len = int(operands_aliases[0][3:])
else:
num_len = 16

# Calculate the new program_start in instructions
if self.isa in ["risc3", "cisc"]:
if self.isa in ["risc", "cisc"]:
jump_num = twos_complement(int(operands_values[0].to01(), 2), num_len)
else:
# Figure out if the value we should jump for was pushed on to the stack, or is in the instruction
Expand Down Expand Up @@ -652,7 +652,7 @@ def __determine_start_point(self):
:return: start_point - int, representing the bit value in the instruction from which the opcodes begin
"""
# Figure out the operands details for the RISC-Register ISA
if self.isa == "risc3":
if self.isa == "risc":

# Load the special case moves for RISC-Register architecture
low_high_load_risc = ["mov_low", "mov_high"]
Expand All @@ -664,8 +664,8 @@ def __determine_start_point(self):
start_point = 5
else:
start_point = 6
# We don't really include operands in instructions for RISC1, RISC2 and CISC. This really speaks volumes about
# how all of this was 'engineered', ahem, starting with RISC3 and having no idea whatsoever about the future
# We don't really include operands in instructions for Stack, Accumulator and CISC. This really speaks volumes about
# how all of this was 'engineered', ahem, starting with RISC and having no idea whatsoever about the future
# modifications, which, turns out, do not conform to the standard workflow and require tweaks and hacks
# This *should* work, anyway :=)
else:
Expand All @@ -686,10 +686,9 @@ def __determine_result_dest(self, start_point, operands_aliases):

# Determining where to save the result of the operation depending on type of the operation specified
#
# RISC-Stack ISA
if self.isa == "risc1":

# Determining the result destination for RISC-Stack iSA
# Stack ISA
if self.isa == "stack":
# Determining the result destination for Stack iSA
if (res_type := self.instructions_dict[self.opcode.to01()][1][0]) in ["tos", "in", "swap"]:
memory_write_access, tos_push = True, True
result_destination = int(self.registers["TOS"]._state.to01(), 2)
Expand All @@ -705,11 +704,10 @@ def __determine_result_dest(self, start_point, operands_aliases):
result_destination = self.registers["FR"]
elif res_type == "out":
result_destination = self.ports_dictionary[str(int(self.long_immediate_result.to01(), 2))]
# Accumulator
elif self.isa == "accumulator":

# Accumulator-RISC
elif self.isa == "risc2":

# Determining the result destination for RISC-Accumulator ISA
# Determining the result destination for Accumulator ISA
if (res_type := self.instructions_dict[self.opcode.to01()][1][0]) in ["acc", "in"]:
result_destination = self.registers["ACC"]
elif res_type == "stackpop":
Expand All @@ -724,9 +722,9 @@ def __determine_result_dest(self, start_point, operands_aliases):
result_destination = self.registers["FR"]
elif res_type == "ir":
result_destination = self.registers["IR"]

# Register-RISC and CISC architectures
elif self.isa in ["risc3", "cisc"]:
elif self.isa in ["risc", "cisc"]:

# If the result is to be saved into the first operand
if (res_type := self.instructions_dict[self.opcode.to01()][1]) in ["firstop", "in", "stackpop", "simd", "simdstore"]:
Expand Down Expand Up @@ -823,7 +821,7 @@ def __add_operands(self, start_point, operands_aliases):

# If the operand is the immediate constant, add its value and go to the next operand
elif operand.startswith("imm"):
if self.isa in ["risc1", "risc2", "cisc"]:
if self.isa in ["stack", "accumulator", "cisc"]:
operands_values.append(self.long_immediates.pop())
else:
immediate_length = int(operand[3:])
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# There are 48 different instructions for RISC1 ISA (counting different operand types for the same instructions)
# There are 48 different instructions for Accumulator RISC2 ISA (counting different operand types for the same instructions)
# This assembly program aims to meaningfully test all of them, with edge cases considered
#########################################################################################
mov $512
Expand Down
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# There are 38 different instructions for RISC1 ISA (counting different operand types for the same instructions)
# There are 38 different instructions for Stack RISC1 ISA (counting different operand types for the same instructions)
# This assembly program aims to meaningfully test all of them, with edge cases considered
#########################################################################################
mov $1022
Expand Down
File renamed without changes.
6 changes: 3 additions & 3 deletions modules/registers.json
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
{
"comments": "Each ISA architecture contains a list of registers for it, including: name, general_purpose bool, encoding",
"risc1": [
"stack": [
["FR", 0, "000", "Flag Register"],
["SP", 0, "001", "Stack Pointer"],
["IP", 0, "010", "Instruction Pointer"],
["TOS", 1, "011", "Top Of the Stack pointer"]
],
"risc2": [
"accumulator": [
["FR", 0, "000", "Flag Register"],
["SP", 0, "001", "Stack Pointer"],
["IP", 0, "010", "Instruction Pointer"],
["IR", 0, "011", "Index Register"],
["ACC", 1, "100", "Accumulator Register"]
],
"risc3": [
"risc": [
["SP", 0, "100", "Stack Pointer"],
["IP", 0, "101", "Instruction Pointer"],
["LR", 0, "110", "Link Register"],
Expand Down
4 changes: 2 additions & 2 deletions modules/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def __init__(self):
parser = argparse.ArgumentParser()
parser.add_argument("--file", help="provide the binary code filepath")
parser.add_argument("--isa",
help="specify the ISA architecture: RISC1 (Stack), RISC2 (Accumulator), RISC3 (Register), CISC (Register)")
help="specify the ISA architecture: Stack, Accumulator, RISC (Register), CISC (Register)")
parser.add_argument("--architecture",
help="specify the data/program architecture: neumann, harvard, harvardm")
parser.add_argument("--output", help="specify the type of I/O: mmio, special")
Expand All @@ -33,7 +33,7 @@ def __init__(self):
args = parser.parse_args()

# Lists of valid architecture types
valid_isa = ['risc1', 'risc2', 'risc3', 'cisc']
valid_isa = ['stack', 'accumulator', 'risc', 'cisc']
valid_architectures = ['neumann', 'harvard', 'harvardm']
valid_io = ['mmio', 'special']

Expand Down
Loading

0 comments on commit eb9c7dc

Please sign in to comment.