Nand2Tetris: El curso que todo apasionado de la informática debería hacer

Si simplemente tuviera que decir una frase acerca de este curso, diría que es el mejor curso que he realizado en mi vida. Y si esta frase no hubiese sido suficiente para llamar tu atención, tal vez la propuesta del curso lo haga: partiendo de una puerta lógica NAND y las condiciones true y false, construiremos un sencillo computador, desarrollaremos un ensamblador, un compilador, un sistema operativo y finalmente programaremos un Tetris o algún otro jueguecillo al que jugar en este nuevo computador. Y todo "con nuestras propias manos" ¿interesante no?.

Nand2Tetris Dios
Figura 1. En ciencias de la computación Dios nos da la puerta Nand, nosotros construimos todo lo demás

1. ¿Dónde lo encuentro?

El curso tiene una web oficial y puede realizarse mediante la plataforma Coursera. Está sólo en inglés, pero ya te digo que si tienes un mínimo de nivel lo podrás seguir sin ningún tipo de problema. Dispones de los subtítulos en inglés, pero probablemente ni los necesitarás ya que se les entiende muy muy bien. Si, como yo, estás trabajando en mejorar tu comprensión auditiva verás que es una oportunidad de oro para hacer oído.

En lo que respecta al registro y al acceso al curso ambos son gratuitos, aunque si quieres usar la plataforma de corrección automática de los proyectos en Coursera y obtener así unos certificados con los que vacilar en tu Linkedin al lado de tu puesto de CEO, tendrás que pagar. A pesar de no tener la corrección online, siempre podrás comprobar si tus proyectos los has realizado correctamente probando con las baterías de test que te ofrecen junto con sus herramientas (todas gratuitas). Además de los propios foros dentro de la plataforma, en la web del curso tienes foros de acceso gratuito en los que encontrarás respuesta a muchas de tus dudas.

Junto a todo el material disponible en su web, existe un libro de texto que sí es de pago pero que no es necesario tenerlo para completar el curso ya que todo se explica en las clases. A pesar de esto, sí que te recomiendo que lo tengas como referencia si vas a realizar la segunda parte del curso.

2. ¿A quién va dirigido?

Como expondré y detallaré a continuación, este curso se divide en dos partes y ambas partes son un curso independiente en la plataforma Coursera: en la primera parte se construye el hardware y en la otra el software. La primera de las partes yo la clasificaría como "para todos los públicos" ya que no es necesario ningún conocimiento previo ni saber programar para realizarla. Esta parte podría incluso darse a alumnos de tecnología de bachillerato o FPs de grado medio de electrónica o informática.

La segunda parte la clasificaría, si me permites la expresión, como "mucho más gore". Ya lo detallaré posteriormente, pero el que se haya dividido en dos partes no se debe a que el temario visto en cada una de las partes esté equilibrado ni mucho menos. En esta ocasión sí que se necesita cierta habilidad previa de programación y conocimientos de algunas estructuras de datos. Como veremos posteriormente, podrás hacer los proyectos en cualquier lenguaje de programación: Java, php, c, python, perl, go…​ Esta parte estaría indicada para gente que tenga experiencia programando, universitarios y estudiantes de FP de grado superior de informática.

3. ¿Por qué hacer este curso?

Llegados a este punto es muy probable que estés diciendo…​ sí, todo esto parece muy bonito, pero en mi trabajo me exigen saber Linux, programar en Java, configurar un equipo Cisco…​ ¿para qué voy a perder el tiempo en construir un ordenador, hacer un compilador, etc?. Además…​ muchas de esas cosas las vi en la carrera y tal como las aprendí las olvidé, al fin y al cabo…​ en "el mundo real" no son útiles.

Bueno, te reconozco que cuando era joven y rebelde pensaba así. Han sido los años de experiencia los que me han hecho apreciar y valorar el conocimiento "base". He aprendido que lo importante es saber resolver problemas, y que para resolverlos es mucho más útil entender los principios (algoritmos, estructuras de datos, arquitectura, estadística, etc) que las herramientas.

En mi opinión, creo que el problema es que el conocimiento "base" suele enseñarse con mucha teoría y poca práctica. La falta de contexto generalmente hace que las prácticas parezcan carentes de sentido y las asignaturas inconexas: estudias digital, arquitectura, programación, compiladores, sistemas operativos…​ cada una por su lado y con diferentes profesores, es como si te diesen los puntos, pero ¿dónde están las líneas que los unen?.

Pues bien, este curso podría ser esas líneas. Como veremos a continuación, el temario está muy simplificado y además de darnos una perspectiva global del funcionamiento completo de un computador y puede servir de complemento perfecto a todas las asignaturas antes citadas. Y al contrario que suele ocurrir todas estas asignaturas, es eminentemente práctico. El libro de texto del curso comienza con una frase de Confucio que representa muy bien el enfoque usado:

"Me lo contaron y lo olvidé; lo vi y lo entendí; lo hice y lo aprendí"

4. ¿Cuál es el contenido del curso?

Como ya he comentado previamente, el curso se compone de dos partes. Ambas se dividen en 6 temas y en cada tema hay que realizar un proyecto. Según la planificación, cada curso tiene unas 7 semanas, pero como ya avancé, no tienen nada que ver en dificultad. Para que te hagas una idea, yo la primera parte del curso (hardware) la realicé en menos de una semana y en la segunda parte fui hasta apurado para cumplir en alguno de los proyectos con los plazos establecidos. Por lo que, de manera orientativa, podría decirse que toda la primera parte equivale en tiempo a un tema de la segunda.

El planteamiento del curso es que el alumno asumirá el rol de implementador. Los profesores, Noam y Shimon, serán los diseñadores de todos los componentes del sistema y nos proporcionarán todo el diseño y las interfaces que como alumnos deberemos de implementar. Además nos darán todas las herramientas necesarias y unas baterías de pruebas con las que se comprobará que nuestra implementación cumple con los requisitos.

Como se verá, todos los diseños realizados en el curso son muy simples y elegantes. El objetivo no es sólo implementar y aprender cómo funciona lo que se desarrolla, el objetivo también es proporcionar modelos que sean ejemplo de buenos diseños. Como se verá en el curso, se insiste continuamente en la abstracción y el diseño de interfaces, que junto con el desarrollo orientado a tests introduce al alumno en las buenas prácticas de desarrollo.

Perspectiva curso Nand2Tetris
Figura 2. Perspectiva temas del curso

4.1. Parte 1: Hardware

Esta parte corresponde con el curso: Nand2Tetris Parte 1: hardware en la plataforma Coursera. En esta parte se abarca desde la definición de la puerta NAND, la creación del Hack Computer (así es como llaman a la máquina que hay que construir) y la creación del ensamblador de la arquitectura. Los temas tratados son:

Lógica booleana

En este primer tema se introduce al alumno a la lógica digital y se ven las principales puertas lógicas y sus tablas de verdad. El proyecto de este tema consiste en implementar las puertas lógicas Nor, Or, etc y multiplexores y demultiplexores.

En este tema ya se introduce el simulador de hardware de este curso con el que se trabajará hasta la definición del lenguaje máquina. Este simulador admite un lenguaje parecido a VHDL con el que desarrollar los chips e incluye un lenguaje de scripting de test con los que probar los circuitos.

Este simulador hardware podría ser de mucha utilidad para hacer prácticas introductorias a la electrónica digital en la que se desarrollasen circuitos combinacionales y secuenciales sin la necesidad de usar simuladores más complejos como Spice.

Aritmética booleana

En este tema se ve toda la codificación binaria, complemento a dos, etc y se implementan circuitos sumadores y la ALU que usaremos para nuestro computador.

Como se puede suponer, nuestra ALU implementará operaciones muy sencillas y se dejará para la capa software realizar las operaciones más complejas de multiplicación, división, etc.

Además, en el curso únicamente se verá lo esencial de la lógica digital, no se entrará en complicadas simplificaciones lógicas ni diagramas de Karnaugh ni nada por el estilo. Como se verá, el diseño de la ALU es muy elegante y hace que la implementación sea prácticamente trivial.

Lógica secuencial

En este tema se implementa un biestable básico, los registros, bancos de memorias RAM y circuitos contadores. Por supuesto, se ve también cómo funciona el reloj.

En este caso, el proyecto consistirá en implementar todos estos componentes con el lenguage pseudo VHDL del simulador.

Lenguaje Máquina

En este tema los profesores definen el lenguaje máquina que tendrá nuestra computadora. Es tremendamente sencillo y elegante, con únicamente dos formatos de instrucción con los que se podrá implementar todo. Además se establecen una serie de convenios que definirán la arquitectura, que estará basada en acumulador y dos registros. Junto al formato de instrucción nos definirán también todos los mnemónicos correspondientes a las instrucciones máquina y los símbolos con los que se definirá el lenguaje ensamblador.

En lo que respecta a la entrada y salida se realizará por memoria, una dirección contendrá la información del teclado y una zona de memoria estará mapeada a la pantalla del simulador.

Si estás leyendo esto y crees que es muy complicado es porque todavía no has hecho este curso ;)

En este tema la práctica consiste en implementar mediante el lenguaje ensamblador propuesto unos pequeños problemas. Para ello se utilizará otro simulador y los tests correspondientes.

Arquitectura de computador

En este tema se explica cómo funciona un computador y todos sus componentes: CPU, ALU, registros, lógica de control, memoria, etc. y las fases de ejecución de una instrucción. Todo esto para que nosotros seamos capaces de construir el Hack Computer.

Pero no hay que asustarse, la máquina es muy simple, es una monociclo, tiene la memoria de instrucciones separada de datos y no existen interrupciones. Además los profesores dan el problema casi resuelto, dando todas las conexiones y el camino de datos y control de la CPU. La tarea del alumno será implementar en VHDL el diseño propuesto e implementar la lógica de control que será muy sencilla debido al elegante diseño.

Ensamblador

Este tema es el último de esta parte del curso. En él se explican los detalles de implementación de un ensamblador: la tabla de símbolos y explicando cómo genera el código máquina que finalmente implementa nuestro Hack Computer.

En esta ocasión hay posibilidad de realizar dos proyectos distintos: uno para gente que sepa programar y otro para gente que no sepa. No se cómo será el que es para gente que no sabe programar, yo hice el otro. Si optas por programar, es la práctica más costosa en tiempo de toda esta parte. Obviamente el tiempo que te cueste también dependerá de tu habilidad como programador. Para implementar el ensamblador podrás utilizar prácticamente cualquier lenguaje: Java, Pyhton, Perl, C, PHP, Go…​ En mi caso opté por realizar este y el resto de programas del curso en lenguaje Perl debido a la facilidad del manejo de expresiones y cadenas.

Si bien los ordenadores reales son muchísimo más complejos y no se han visto importantísimos conceptos como las interrupciones, memorias caché, soporte de memoria virtual, organizaciones escalares y superescalares, ejecución fuera de orden, predicción de saltos, etc. Se aprende la base de cómo funciona un computador, consiguiendo el objetivo de construir un sencillo ordenador que funciona: el Hack Computer así como un ensamblador para su arquitectura.

Sí, también existe una implementación en FPGA del Hack Computer.

4.2. Parte 2: Software

Esta parte corresponde con el curso: Nand2Tetris Parte 2:software en la plataforma Coursera. En esta ocasión con el Hack Computer desarrollado así como un lenguaje ensamblador, se realizará un compilador para el lenguaje de programación Jack Language, se desarrollará un pequeño sistema operativo para el Hack computer con este lenguaje y se implementará un pequeño videojuego. En esta ocasión el temario es el siguiente:

Máquina Virtual I: Aritmética en la pila

Para realizar el compilador del Jack Language se opta por un diseño que compila en dos fases mediante una especie de lenguaje intermedio para una máquina virtual (como hacía Pascal y con sus muchas diferencias hace Java). Por ello en este tema se define la máquina virtual para la que se compila, que es una máquina muy sencilla basada en pila.

En este tema se ve cómo se realizan las operaciones aritméticas con una máquina basada en stack, su sencillez y elegancia. Los profesores especifican el diseño de esta máquina virtual: los comandos, palabras reservadas, operaciones aritméticas, lógicas y acceso y segmentación de la memoria.

El proyecto en este tema consiste en implementar lo que llaman el VM Translator (nuevamente lo implementaremos en el lenguaje que nosotros queramos) que lo que hace es tomar código para la máquina virtual y convertirlo en lenguaje ensamblador del Hack Computer. Nuevamente tendremos programas de prueba contra los que validar nuestra implementación en un simulador específico de la VM.

Virtual Machine II: Control de programa

En este tema se definen las estructuras de control de flujo de programa de esta máquina virtual y el protocolo de llamadas a funciones. El proyecto consiste en implementar el VM Translator con estas funcionalidades y así tener esta parte del compilador lista.

Lenguaje de Alto nivel

En este tema se especifica el lenguaje de programación Jack Language para el que escribiremos posteriormente el compilador. Para habituarnos al lenguaje se nos propone como proyecto la implementación de un juego en este lenguaje. En este caso no hay autocorrección, tienes que subirlo para otros alumnos lo evalúen y tú a cambio debes evaluar 3 trabajos. No es difícil…​ a mi por mi YASG: Yet Another Snake Game me pusieron un 10 xP.

Juego YASG
Figura 3. Echando una partidita en el simulador a mi YASG

Compilador I: Análisis de sintaxis

Una vez que se conoce bien el Jack Language, se pasa a implementar el compilador que genera de código Jack a código de la máquina virtual. Esta tarea la divide en dos partes, siendo la primera el analizador sintáctico.

Aquí se define la gramática del Jack Language y cómo funciona un compilador durante el análisis sintáctico: la tokenización y el parseo. A esta parte tampoco hay que tenerle miedo, ya que el lenguaje está diseñado con la máxima sencillez en mente para que sea fácil implementar el compilador, ya que hay que hacerlo a mano, no vale tirar de YACC y BISON. Esta parte del compilador generará un fichero XML con el árbol sintáctico que nuevamente será validado con las herramientas que provee el curso.

Compilador II: Generación de código

Tras el análisis sintáctico hay que generar el código y esto es lo que se hace en este tema. Para ello se ve la tabla de símbolos, cómo se mapean los tipos de datos, el manejo de arrays y objetos, el manejo de expresiones, llamadas a funciones, estructuras de control, etc. Con todo esto se debe implementar la parte del generador de código. Nuevamente se proveerán de herramientas para probar que todo funciona correctamente.

Sistema operativo

Este es el último de los temas, aquí se implementa un pequeño "sistema operativo". Es algo muy muy sencillo, no nos esperemos implementar un Minix ni nada por el estilo.

En primer lugar se implementan las operaciones matemáticas de multiplicación, división y raíces cuadradas. Aquí se da el concepto de coste computacional y enseña unos algoritmos eficientes para realizar estas operaciones. También se implementa un sencillo sistema de gestión dinámica de la memoria para los objetos del Jack Language (es como si implementásemos nuestro propio malloc y free). Aquí nos enfrentaremos a problemas de fragmentación de la memoria y veremos algunos tradeoffs al respecto. Se implementará también el soporte a arrays y cadenas, la gestión de la entrada y salida. Especialmente interesante es la parte en la que se trata el dibujado en pantalla, ya que deberemos de realizar el renderizado de primitivas de gráficos vectoriales a pixeles sobre el buffer de memoria y la impresión de caracteres.

Personalmente, esta último tema fue el que me resultó más "duro" ya que los problemas eran los más complejos y obviamente había que escribir el sistema operativo en Jack Language. Sin embargo, también fue el tema con el que más satisfacción tuve al terminarlo.

5. Conclusiones

Como has podido ver, este curso es fantástico, te lo recomiendo encarecidamente. Si además eres docente, te recomiendo también que eches un vistazo a todo el material, hay verdaderas joyas.

Personalmente no tuve la asignatura de compiladores en mi carrera y la segunda parte del curso me resultó de muchísima utilidad para aprender algunos conceptos fundamentales a este respecto. Además me sirvió para repasar muchos conceptos que ya sabía y me aportó mucha más claridad y perspectiva. Por mi experiencia con el curso, te puedo garantizar que si decides hacerlo serás un mejor profesional.