mirror of
https://github.com/StepanovPlaton/Nand2Tetris.git
synced 2026-04-03 20:30:47 +04:00
Comleted 6 project
This commit is contained in:
118
Assignments/6_Assembler/assembler.py
Normal file
118
Assignments/6_Assembler/assembler.py
Normal file
@@ -0,0 +1,118 @@
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
|
||||
if (len(sys.argv) > 2):
|
||||
raise ValueError("Too many parameters")
|
||||
if (len(sys.argv) == 1):
|
||||
raise ValueError("Excepted .asm filename")
|
||||
if (not re.match(r".*\.asm", sys.argv[1])):
|
||||
raise ValueError(f"{sys.argv[1]} is not valid filename")
|
||||
if (not os.path.exists(sys.argv[1])):
|
||||
raise ValueError(f"{sys.argv[1]} not found")
|
||||
|
||||
with open(sys.argv[1], "r") as asm_file:
|
||||
asm_with_labels = list(
|
||||
filter(lambda line: len(line) > 0,
|
||||
map(lambda line: line.strip().replace(" ", "").split("//")[0],
|
||||
asm_file.readlines())))
|
||||
|
||||
labels: dict[str, int] = {
|
||||
"SP": 0x0000,
|
||||
"LCL": 0x0001,
|
||||
"ARG": 0x0002,
|
||||
"THIS": 0x0003,
|
||||
"THAT": 0x0004,
|
||||
**{f"R{i}": i for i in range(16)},
|
||||
"SCREEN": 0x4000,
|
||||
"KBD": 0x6000
|
||||
}
|
||||
variables: dict[str, int] = {}
|
||||
|
||||
for i, command in enumerate(asm_with_labels):
|
||||
if (bool(re.match(r"^\(.+\)$", command))):
|
||||
labels[command[1:-1]] = -1
|
||||
else:
|
||||
for k in labels.keys():
|
||||
if (labels[k] == -1):
|
||||
labels[k] = i-len(labels.keys())+7+16
|
||||
|
||||
asm = list(filter(lambda c: not bool(
|
||||
re.match(r"^\(.+\)$", command)), asm_with_labels))
|
||||
|
||||
jumps: dict[str, int] = {
|
||||
"JGT": 0b001,
|
||||
"JEQ": 0b010,
|
||||
"JGE": 0b011,
|
||||
"JLT": 0b100,
|
||||
"JNE": 0b101,
|
||||
"JLE": 0b110,
|
||||
"JMP": 0b111,
|
||||
}
|
||||
expressions: dict[str, int] = {
|
||||
"0": 0b101010,
|
||||
"1": 0b111111,
|
||||
"-1": 0b111010,
|
||||
"D": 0b001100,
|
||||
"A": 0b110000,
|
||||
"!D": 0b001101,
|
||||
"!A": 0b110001,
|
||||
"-D": 0b001111,
|
||||
"-A": 0b110011,
|
||||
"D+1": 0b011111,
|
||||
"A+1": 0b110111,
|
||||
"D-1": 0b001110,
|
||||
"A-1": 0b110010,
|
||||
"D+A": 0b000010,
|
||||
"D-A": 0b010011,
|
||||
"A-D": 0b000111,
|
||||
"D&A": 0b000000,
|
||||
"D|A": 0b010101,
|
||||
}
|
||||
|
||||
|
||||
hack: list[str] = []
|
||||
|
||||
for command in asm:
|
||||
if (command[0] == "@"):
|
||||
if (command[1:].isnumeric()):
|
||||
hack.append(bin(int(command[1:]))[2:].zfill(16))
|
||||
else:
|
||||
if (command[1:] in labels.keys()):
|
||||
hack.append(bin(labels[command[1:]])[2:].zfill(16))
|
||||
else:
|
||||
if (not (command[1:] in variables.keys())):
|
||||
variables[command[1:]] = \
|
||||
max(list(filter(lambda address: address >= 15 and address < 0x4000,
|
||||
[15, *variables.values()])))+1
|
||||
hack.append(bin(variables[command[1:]])[2:].zfill(16))
|
||||
else:
|
||||
memory, compute, destination, jump = 0, 0, 0, 0
|
||||
if (";" in command):
|
||||
jump = jumps[command[command.find(";")+1:]]
|
||||
command = command[:command.find(";")]
|
||||
if ("=" in command):
|
||||
destinations = command[:command.find("=")]
|
||||
if ("M" in destinations):
|
||||
destination += 0b001
|
||||
if ("D" in destinations):
|
||||
destination += 0b010
|
||||
if ("A" in destinations):
|
||||
destination += 0b100
|
||||
command = command[command.find("=")+1:]
|
||||
if ("M" in command):
|
||||
memory = 1
|
||||
command = command.replace("M", "A")
|
||||
compute = expressions[command]
|
||||
bin_code = 0b111_0_000000_000_000
|
||||
bin_code |= memory << 12
|
||||
bin_code |= compute << 6
|
||||
bin_code |= destination << 3
|
||||
bin_code |= jump
|
||||
hack.append(bin(bin_code)[2:].zfill(16))
|
||||
|
||||
with open(sys.argv[1].replace(".asm", ".hack"), "w") as hack_file:
|
||||
for i, command in enumerate(hack):
|
||||
hack_file.write(f"{command}")
|
||||
if (i != len(hack)-1):
|
||||
hack_file.write("\n")
|
||||
17
README.md
17
README.md
@@ -6,19 +6,20 @@
|
||||
В этом репозитории я сохраняю свои работы в ходе прохождения курса [Nand2tetris](https://www.nand2tetris.org)
|
||||
|
||||
### Программа курса с моим описанием содержания каждой главы:
|
||||
- #### Hardware
|
||||
- [Project 1: Boolean Logic](./Assignments/1_Boolean_Logic)
|
||||
- #### **Hardware**
|
||||
- **[Project 1: Boolean Logic](./Assignments/1_Boolean_Logic)**
|
||||
> Реализация [NAND-логики](https://en.wikipedia.org/wiki/NAND_logic), то есть создание основных логических блоков (AND, OR, NOT, XOR, MUX, DMUX, а так же их версий для работы с 16-битной шиной) с помощью операции NAND ([И-НЕ или Штрих Шеффера](https://ru.wikipedia.org/wiki/Штрих_Шеффера))
|
||||
- [Project 2: Boolean Arithmetic](./Assignments/2_Boolean_Arithmetic/)
|
||||
- **[Project 2: Boolean Arithmetic](./Assignments/2_Boolean_Arithmetic/)**
|
||||
> Создание [простого арифметико-логического устройства (ALU)](./Assignments/2_Boolean_Arithmetic/ALU.hdl) с помощью логических блоков из первого проекта, способного складывать и вычитать 16-битные числа
|
||||
- [Project 3: Memory](./Assignments/3_Sequential_Logic/)
|
||||
- **[Project 3: Memory](./Assignments/3_Sequential_Logic/)**
|
||||
> Вводим единицу времени - такт, за счёт чего появляется текущее и следующее состояние, которое можно запоминать и изменять. Создаём простейшую память. На основе DFF компонента создаём [однобитный регистр](./Assignments/3_Sequential_Logic/Bit.hdl), затем [16-битный регистр](./Assignments/3_Sequential_Logic/Register.hdl), из них собираем блоки оперативной памяти ([RAM8](./Assignments/3_Sequential_Logic/RAM8.hdl), [RAM64](./Assignments/3_Sequential_Logic/RAM64.hdl), [RAM512](./Assignments/3_Sequential_Logic/RAM512.hdl), [RAM4K](./Assignments/3_Sequential_Logic/RAM4K.hdl), [RAM16K](./Assignments/3_Sequential_Logic/RAM16K.hdl)), а так же создаём простой [счётчик](./Assignments/3_Sequential_Logic/PC.hdl), который может использоваться для хранения текущей выполняемой инструкции и перехода к новой инструкции
|
||||
- [Project 4: Machine Language](./Assignments/4_Machine_Language/)
|
||||
- **[Project 4: Machine Language](./Assignments/4_Machine_Language/)**
|
||||
> Разбираемся с тем, что такое машинный код и как компьютер выполняет комманды записанные с его помощью. Вводим понятие ассемблера, и изучаем язык ассемблера для создаваемой платформы. [Пишем пару простых программ](./Assignments/4_Machine_Language/), в том числе [реализуем простое чтение данных с клавиатуры и вывод картинки на эмулятор экрана](./Assignments/4_Machine_Language/Fill.asm)
|
||||
- [Project 5: Computer Architecture](./Assignments/5_Computer_Architecture/)
|
||||
- **[Project 5: Computer Architecture](./Assignments/5_Computer_Architecture/)**
|
||||
> Завершаем работу над аппаратной составляющей компьютера. [Собираем модуль памяти](./Assignments/5_Computer_Architecture/Memory.hdl), позволяющий, в том числе, взаимодействовать с клавиатурой и экраном. [Собираем ЦПУ](./Assignments/5_Computer_Architecture/CPU.hdl) из ранее созданных ALU, счётчика и регистров. Из памяти, ЦПУ и чипа ROM с набором инструкций [собираем компьютер Hack](./Assignments/5_Computer_Architecture/Computer.hdl)
|
||||
- #### Software
|
||||
- Project 6: Assembler
|
||||
- #### **Software**
|
||||
- **[Project 6: Assembler](./Assignments/6_Assembler/)**
|
||||
> На практике изучаем как язык ассемблера компилируется в двоичный код, [создавая ассемблер для компьютера Hack](./Assignments/6_Assembler/assembler.py)
|
||||
- Project 7: VM I: Stack Arithmetic
|
||||
- Project 8: VM II: Program Control
|
||||
- Project 9: High-Level Language
|
||||
|
||||
Reference in New Issue
Block a user