← SEARCHABLE ARCHIVE
Nand2Tetris · 2026-05-23

Materiales didácticos coreanos de Nand2Tetris: hoja de ruta completa

Conectando 12 capítulos a la vez, desde puertas lógicas hasta sistemas operativos

INTERACTIVE READING MODE →

Materiales de conferencias coreanas de Nand2Tetris

Los artículos escritos en este blog fueron creados con el objetivo de enseñar. Además, la información del artículo puede ser incorrecta, así que tenga cuidado.

Nand2Tetris es el proceso de creación de una computadora, un compilador y un sistema operativo a partir de una única puerta NAND. Si observa cada capítulo individualmente, parece una colección de código HDL o código Python, pero de hecho, los resultados del capítulo anterior se convierten en el material para el siguiente.

buenas noches. En este artículo, conectemos el código existente de los Capítulos 1 al 12 en un solo flujo.

flujo completo

NAND
  ↓
puerta lógica
  ↓
Sumador y ALU
  ↓
registros y memoria
  ↓
Hackear CPU y computadora
  ↓
ensamblador
  ↓
Traductor de máquinas virtuales
  ↓
Compilador Jack
  ↓
sistema operativo jack

Los capítulos 1-5 crean hardware, Los capítulos 6 a 8 crean un traductor de bajo nivel. Los capítulos 9 a 12 cubren lenguajes de alto nivel, compiladores y sistemas operativos.

Capítulo 1. Lógica booleana y puertas básicas.

objetivo

  • Cree otra puerta lógica usando solo NAND.
  • Mire la tabla de verdad y piense en las conexiones HDL.
  • Comprenda cómo Mux y DMux seleccionan y distribuyen datos.

NAND genera 0 solo cuando ambas entradas son 1. Puede parecer simple, pero conectar las entradas a la misma línea crea NO, y combinar NO nuevamente puede crear Y y O.

Not(a) = Nand(a, a)
And(a, b) = Not(Nand(a, b))
Or(a, b) = Nand(Not(a), Not(b))

mux esselSeleccione aob dependiendo de. DMux, por otro lado, envía una entrada a a o b.

Capítulo 1 Ver código

problema de verificación

  1. ¿Por qué NO ocurre cuando pongo el mismo valor en ambas entradas de NAND?
  2. Expliquemos la diferencia entre Mux y DMux en términos de dirección de datos.
  3. Mux16¿Qué es lo mismo que un Mux de 1 bit?

Capítulo 2. Aritmética booleana y ALU

objetivo

  • Comprenda la diferencia entre medio sumador y sumador completo.
  • Veamos el proceso de llevar la suma de múltiples bits.
  • Comprenda ALU, que realiza varias operaciones con bits de control.

Un medio sumador agrega dos bits para crear suma y acarreo. El sumador completo recibe el acarreo de la posición anterior como entrada.

HalfAdder: a + b
FullAdder: a + b + carry-in
Add16: sumador de 16 bits conectado a FullAdder

La clave de ALU no es crear un circuito separado para cada operación. zx, nx, zy, ny, f, noUn circuito se utiliza de varias maneras cambiando la entrada y salida con señales.

Capítulo 2 Ver código

problema de verificación

  1. ¿Por qué se utiliza XOR como suma de suma?
  2. ¿Qué sucede si descarta el último acarreo en una suma de 16 bits?
  3. ALUzr, ng¿Para qué función se utilizará la salida en el próximo capítulo?

Capítulo 3. Lógica secuencial y memoria.

objetivo

  • Comprender la diferencia entre lógica combinacional y lógica secuencial.
  • Entiendo que DFF es la unidad más pequeña que almacena tiempo.
  • Vea cómo se expanden Bit, Registro, RAM y PC.

En los circuitos de los capítulos 1 y 2, la salida está determinada únicamente por la entrada de corriente. Sin embargo, la memoria debe recordar el valor del reloj anterior.

La salida de DFF no es la entrada actual, sino la entrada en un momento anterior. Al adjuntar un Mux aquí, puede crear un Bit que almacene un nuevo valor solo cuando la carga es 1.

DFF → Bit → Register → RAM8 → RAM64 → RAM512 → RAM4K → RAM16K

La PC esreset, load, incLas prioridades son importantes. Por lo general, el reinicio es el más fuerte, luego la carga y el último es el inc.

Capítulo 3 Ver código

problema de verificación

  1. Expliquemos con Mux el proceso por el cual un bit mantiene su valor existente cuando la carga es 0.
  2. ¿Por qué necesitamos DMux y Mux en RAM8?
  3. ¿Qué tipo de errores ocurrirán si se invierten las prioridades de las señales de control de la PC?

Capítulo 4. Hackear el lenguaje de máquina

objetivo

  • Distinga entre comandos A y comandos C.
  • Comprender las funciones de los registros A, D y M.
  • Vea cómo se expresan las ramas y los bucles en el ensamblaje.

La instrucción A pone un valor en el registro A.

@10

Las instrucciones C expresan cálculo, ubicación de almacenamiento y condiciones de salto en una línea.

D=M+1;JGT

Mno es un registro separado.RAM[A]medio. Si pasa por alto este punto, es fácil confundirse sobre si el registro A se utiliza como valor o como dirección.

Capítulo 4 Ver código

práctica

  1. RAM[2] = RAM[0] + RAM[1]Escribir .
  2. Escribe un bucle que sume del 1 al 10.
  3. Compruebe por qué la dirección de PANTALLA es 16384 en el código de llenado.

Capítulo 5. Hackear la arquitectura informática

objetivo

  • Conecte la CPU, la memoria y la ROM32K en una computadora.
  • Comprenda cómo los bits de instrucciones controlan la ALU y los registros.
  • Vemos una estructura donde se repiten buscar y ejecutar.

La CPU interpreta la instrucción actual y decide dónde almacenar el resultado de ALU: A, D o M. Si la condición de salto es verdadera, el valor del registro A se inserta en la PC; de lo contrario, pasa a la siguiente instrucción.

Para Memoria, seleccione RAM16K, Pantalla y Teclado según el rango de direcciones. En otras palabras, puede operar la pantalla y el teclado simplemente leyendo y escribiendo direcciones de memoria.

Capítulo 5 Vista de código

problema de verificación

  1. instruction[15]¿Por qué los comandos del A/C se dividen entre ?
  2. writeMCuando es 1, ¿en qué dirección se almacena realmente el valor?
  3. ¿Por qué el teclado no necesita una señal de carga?

Capítulo 6. Hackear ensamblador

objetivo

  • .asmarchivo de 16 bits.hackConvertir a archivo.
  • Etiquetas de proceso y símbolos de variables.
  • Comprenda por qué es necesario leer dos veces.

Las etiquetas no son instrucciones reales y no deben incrementar la dirección ROM. Entonces en el primer pase(LOOP)Se recopilan las direcciones de la misma etiqueta y las instrucciones reales se traducen en una segunda pasada.

1er pase: etiqueta → dirección ROM
2do paso: instrucción A/C → código de 16 bits
Símbolos variables: asignados en orden a partir de la RAM[16]

Capítulo 6 Ver código

práctica

  1. Escriba una función de preprocesamiento para eliminar espacios y comentarios.
  2. Incluso si la misma variable aparece varias veces, verifique que la dirección se asigne solo una vez.
  3. dest, comp, jumpSe genera un error cuando se encuentra una entrada que no está en la tabla.

Capítulo 7. Traductor VM I

objetivo

  • Comprender las máquinas virtuales basadas en pila.
  • Convierta instrucciones aritméticas y segmentos de memoria en ensamblaje Hack.
  • Comprenda por qué las operaciones de comparación requieren etiquetas únicas.

La mayoría de las instrucciones de VM toman valores de la pila, los calculan y luego vuelven a colocar los resultados.

push constant 7
push constant 8
add

local, argument, this, thatsigue la dirección base, temp, pointer, staticCada uno utiliza sus propias reglas de dirección establecidas.

Capítulo 7 Ver código

problema de verificación

  1. ¿Por qué presionar y hacer clic cambian el SP en un orden diferente?
  2. eq, gt, lt¿Qué pasa si no creas una etiqueta única para cada uno?
  3. ¿Por qué los nombres de las variables estáticas deberían incluir el nombre del archivo?

Capítulo 8. Traductor VM II

objetivo

  • Label, goto e if-goto se procesan dentro del alcance de la función.
  • Comprender los marcos de pila de función, llamada y retorno.
  • Comprenda qué hace el código de arranque.

Al llamar a una función, se deben guardar la dirección del remitente y el estado actual del marco.

return-address
LCL
ARG
THIS
THAT

el regreso esFRAME = LCL, RET = *(FRAME - 5)Primero guarde el segmento de la persona que llama y luego restáurelo. Dado que el LCL cambia durante la recuperación, primero se debe guardar RET.

Capítulo 8 Ver código

práctica

  1. Compruebe que las etiquetas de retorno no se superpongan en llamadas a funciones recursivas.
  2. varios.vmCompruebe que el segmento estático del archivo no entre en conflicto.
  3. En bootstrap, establezca SP en 256 ySys.initLlamar .

Capítulo 9. Lenguaje de alto nivel de Jack.

objetivo

  • Distinga entre la clase, el constructor, el método y la función de Jack.
  • Comprender cómo se almacenan los objetos y las matrices en la memoria.
  • Procese la entrada y salida utilizando la API del sistema operativo.

Jack se parece a Java, pero su funcionalidad es mucho más simple. Los campos del objeto se almacenan en el montón y la dirección del objeto actual se almacena en el método.thisSe convierte.

El constructor asigna memoria del tamaño requerido y luegothisregresa. Las matrices también están más cerca de bloques de memoria contiguos que de estructuras de datos especiales.

Capítulo 9 Ver código

práctica

  1. Cree dos objetos Counter y asegúrese de que los valores se mantengan separados.
  2. Evita el procesamiento duplicado mientras se presiona continuamente la entrada de una tecla.
  3. Explica por qué es necesario desechar los objetos que se han utilizado.

Capítulo 10. Analizador Jack

objetivo

  • Comprenda el proceso mediante el cual un tokenizador divide el código fuente en tokens.
  • La gramática de Jack se implementa como un analizador de descenso recursivo.
  • Genere el árbol de análisis como XML.

Los símbolos dentro de cadenas y comentarios externos deben manejarse de manera diferente. Por lo tanto, simplemente dividir por espacio no creará un tokenizador correcto.

El analizador mira el token actual y decide qué función gramatical llamar.

class
 ├─ classVarDec
 ├─ subroutineDec
 └─ statements

Capítulo 10 Vista de código

problema de verificación

  1. en la cuerda//¿Por qué no puedo eliminarlo con un comentario?
  2. ¿Qué resulta conveniente de separar expresión y término?
  3. ¿Cuál es el beneficio de comprobar el tipo esperado antes de consumir el token?

Capítulo 11. Compilador Jack

objetivo

  • Convierta el árbol de análisis en instrucciones de VM.
  • Distinga entre símbolos de alcance de clase y de alcance de subrutina.
  • Comprenda el comportamiento oculto de las llamadas a métodos y llamadas a constructores.

La tabla de símbolos no solo almacena nombres. El tipo, el tipo y el índice se almacenan juntos para determinar qué segmento de VM usar.

static   → static
field    → this
argument → argument
var      → local

El método recibe el objeto actual como primer argumento.pointer 0Conéctate a El constructor es tanto como el número de campos.Memory.allocDespués de llamar, la dirección del remitente espointer 0Mételo.

Capítulo 11 Vista de código

práctica

  1. Compruebe qué símbolo se selecciona cuando una variable local del mismo nombre oscurece un campo.
  2. En la asignación de matrices, organizamos el orden en que las direcciones y los valores deben almacenarse en la pila.
  3. dovalor de retorno de la consultatemp 0Explique el motivo de su descarte.

Capítulo 12. Sistema operativo Jack

objetivo

  • Implementa directamente la biblioteca básica utilizada por el programa Jack.
  • Separe las responsabilidades de Matemáticas, Cadenas, Matriz y Memoria.
  • Completa el último espacio en blanco entre el hardware y el lenguaje de alto nivel.

Un sistema operativo no comienza con un núcleo enorme. La clave es implementar las funciones esperadas por el programa Jack en el lenguaje Jack.

  • Matemáticas: multiplicación, división, valor absoluto
  • Cadena: almacenamiento de caracteres, longitud, conversión de salida
  • Matriz: asignación de memoria contigua
  • Memoria: asignación y desasignación de montón
  • Pantalla: salida de píxeles y formas
  • Teclado: entrada de teclas
  • Salida: letras y números de salida
  • Sistema: Inicializar, En espera, Apagar

Capítulo 12 Vista de código

problema de verificación

  1. ¿Por qué se pueden implementar la multiplicación y la división sin instrucciones de la CPU?
  2. ¿Por qué un objeto String tiene longitud y capacidad separadas?
  3. ¿Qué problemas ocurrirán en el programa Jack si no se libera la memoria?

Orden de aprendizaje recomendado

Es mejor continuar con cada capítulo en el siguiente orden.

  1. Antes de mirar el código completo, escriba primero la tabla de verdad y de entrada/salida.
  2. Pruebe primero las piezas pequeñas.
  3. Si la prueba pasa, se utiliza como componente de la siguiente etapa.
  4. Si falla, no mire simplemente la salida, sino averigüe en qué capa cambió el valor.
  5. Al final, compare el código del blog existente con su propio código.

Si ingresa el código correcto tal como está, el proyecto se completará rápidamente. Pero lo importante en Nand2Tetris es comprender cómo la capa un nivel por debajo de la respuesta admite la capa actual.

Una vez que vemos el flujo de NAND que conduce a un sistema operativo, las computadoras ya no parecen mágicas.