Hola,
Acabo de terminar un circuito que puede ser útil. Toma una entrada ASCII del puerto serie y la convierte a binario.

Este circuito nos permite enviar directamente números (del 0 al 255) desde cualquier terminal serie, como por ejemplo el de Arduino, o en un futuro muy próximo desde el propio Icestudio. Antes de crear este módulo estaba usando (y lo seguiré haciendo porque es un script serie muy versátil) "
ScriptCommunicator" para poder hacer eso, y lo hacía en hexadecimal. Poder englobar cualquier terminal serie nos hace la vida un poco más fácil a todos, independientemente de: en qué parte estemos de la curva de aprendizaje.
Introducción:
Cuando desde un terminal serie escribimos, por ejemplo, "gato" y le damos enter o enviar, tenemos la sensación de que de forma muy rápida se están enviando las letras 'g' y luego 'a' y luego 't' y finalmente 'o'. En realidad esto no es así. Lo que se envía son números que tanto podemos interpretar en decimal (0..255) como en hexadecimal (00..FF). Así que, por ejemplo en decimal, cuando enviamos la palabra "gato" estamos enviando 4 números que sería: 103 (corresponde a la 'g'), 97 (que corresponde a la 'a'), 116 (que corresponde con la 't') y 111 (que corresponde con la 'o'). Y la mayoría de las veces va acompañado de un número más, que suele ser: LF que vale "10" en decimal y significa "nueva línea" o bien un CR que vale 13 en decimal y significa retorno de carro. La
tabla ASCII es un acuerdo internacional donde todo el mundo entiende (por ejemplo) que el número 97 se corresponde la letra 'a', etc.
Por esta razón, cuando escribes desde un terminal serie (por ejemplo) 123 y le das al enter o enviar, no estás enviando esas cifras tal cual, ni tampoco estás enviando ese número directamente en binario de 8 bits, sino que envías tres números: el 49, 50 y 51, que como ya estás deduciendo, el 49 significa 1, el 50 significa 2, y 51 significa 3.
Cómo funciona el circuito:
Cuando el receptor serie recibe un caracter ASCII (recuerda que en realidad es un número que por acuerdo se corresponde con un símbolo) lo primero que hace el circuito es detectar si lo que ha recibido es un LF o un CR, o si por el contrario es otra cosa de esas dos.

Si recibe LF o CR dará un pulso por la salida "rst" de lo contrario dará un pulso por la salida "tic". Las puertas not y and están ahí para que cuando reciba un LF o CR no salga el pulso por "tic", es decir, sólo puede salir un pulso por una de las dos salidas, nunca a la vez.
En esta siguiente imagen vemos muchos registros de 8 bits. Son registros especiales, pero lo interesante es ver que a medida que van entrando bytes se van ordenando de tal forma que siempre queda ordenado la unidad, decena y centenas.

Por ejemplo, al recibir el número 123 (y vamos a imaginar que realmente es así, aunque no es así por lo que comenté en la introducción) primero llega el 1, luego el 2 y después el 3. Como es un registro de desplazamientos se irán acumulando cada número en un registro determinado, pero lo importante aquí es ver que hacemos la entrada desde abajo para que queden las cifras ordenadas en forma inversa, ya que si hubiéramos hecho la carga desde arriba nos saldría al revés. Esto que comento no es sencillo de ver a la primera. Para rizar el rizo, además de eso, se consigue que si sólo enviamos un número de una cifra o de dos, las cifras no rellenadas valdrán 0. Es decir, que si envío el número 5 y le doy a enviar, consigo que el circuito lo interprete como 005.
Cuando el circuito recibe el LF o CR la información contenida en los registros de desplazamientos se transfiere a registros "normales" (los de la derecha) para mantener esa información y a la vez se pone a 0 todos los registros de desplazamientos.
Estos registros están configurados interiormente para funcionar con la "lógica" ASCII, así que cuando recibe un tic en los resets no se pone a 0, sino que adquiere el valor 48 (en decimal) que se corresponde al 0 en ASCII. Parecido sucede con los registros de la derecha, que se inicializan (al ponerse en marcha el circuito) con el valor 48.
Hasta ahora lo único que hemos conseguido es recibir los datos y ordenarlos. Ahora viene la parte que realmente pasa de ASCII a binario.

Está en Verilog y es muy sencillo de comprender. Todo lo que ves ahí dentro se hace a la vez, así que no hay un orden dónde mirar, y esto es lo que marca la diferencia entre la electrónica pura y la programación, a la hora de resolver problemas y donde la electrónica saca pecho. De todas formas para comprender lo que sucede puedes poner poner una mirada secuencial (aunque no es así).
Tomamos los números en ASCII que hay en las entradas y se han de convertir a BCD. Para ello lo único que tenemos que hacer es restar la entrada con 48. El 0 es el primer número y su valor ASCII es 48. Entonces 48 - 48 = 0. Si fuese el 1, como vale 49: 49 - 48 = 1 y así con cualquier número que recibamos.
Una vez pasado a BCD lo hemos de convertir a binario. Ahora el orden de las cifras son importantes, porque hay que tener presente si es unidad, decena o centena.
Así que si la centena vale 1, ese 1 se ha de multiplica por 100 para convertirse en centena. Si es decena entonces el número que esté en esa posición se ha de multiplicar por 10, y a la unidad no hay que hacer nada. Finalmente se suma todo y por fin tenemos el número convertido a binario.
Lo que se ve por el medio con comparaciones, lo puse para filtrar de tal modo que si algo no es un número lo haga valer 0, pero en este sentido: (son ejemplos)
* Si envío: w12, lo interpreta como 12.
* Si envío: 12r, lo interpreta como 120.
* Si envío: 1Q2, lo interpreta como 102.
Otras cosas que suceden, ejemplos:
* Si envío una cadena muy larga, sin importar si son números o letras, sólo se quedará con las últimas 3 cifras y lo que haya como letras o símbolos lo hará valer 0:
- 213896498234912391323649130, lo interpretará como 130.
- rywoirw7687wr967erGVS4h7: lo interpretará como 407.
* Y si se escribe números mayores de 255, volverá a comenzar desde 0, en este sentido:
256 -----> 0
257 -----> 1
258 ------> 2
...etc.
Adjunto módulo conversor y ejemplo con leds.
Saludos.