Vi una buena pregunta de entrevista para VHDL: crea un sistema que recibe un número y detecta si se puede dividir entre 5 sin resto. Traté de resolver eso con una máquina de estado (supongo que no quieren que uses mod o rem ) y aunque tuve éxito inicial (números como 5, 10, 15 y números como 20, 40, 80 funcionaron ), otros números como 130, 75, etc. me fallaron.
Mostraría mi máquina de estados, pero es un desastre total (no es un código, es un dibujo) y, como dije, ni siquiera funciona.
Básicamente, lo que intenté hacer es escribir en números binarios que son divisibles por 5, y construir una máquina de estado que funcione para ellos.
Me alegraría que me mostraras cómo resolver este problema y cómo pensar al enfrentar algo como esto.
¡Gracias!
fuente
Respuestas:
Hacer una operación restante en forma serial es realmente bastante fácil. La suposición clave es que los datos vienen primero en MSB si son seriales. Solo necesita N estados para calcular el resto del módulo N. Comience en el estado "0" y si termina en el estado "0" después del último bit (no importa cuántos bits haya), el resto es cero.
simular este circuito : esquema creado con CircuitLab
Piense en cómo haría una división larga si lo único que necesitara hacer un seguimiento fue el resto:
fuente
2n mod 5
, y la flecha 1 apunta a(2n + 1) mod 5
.state
,din
yN
a su código?También puede diseñar una máquina de estado si los datos vienen primero con LSB:
La existencia de dicho autómata finito determinista (DFA) se deduce directamente de la otra respuesta , que describe el DFA para MSB-first. Debido a que los idiomas aceptados por los DFA son regulares y se sabe que los idiomas regulares están cerrados bajo inversión (por ejemplo, consulte aquí ), debe haber un DFA que acepte el siguiente idioma:
Construcción
Copie el primer DFA de MSB de la respuesta de Dave Tweed . Usé la herramienta de autómata JFLAP para eso.
Aplique el algoritmo de transformación explícito para las reversiones de DFA, por ejemplo, como se describe en CS.SE: Diseño de un DFA y su reverso .
Puede ver el resultado (no minimizado) de este paso en la revisión anterior de esta respuesta.
De hecho, el autómata resultante da las respuestas correctas:
fuente
Una forma de crear la máquina de estado (primero MSB) es la siguiente:
El número recibido hasta ahora es
N
. Suponga que conoce el restoM = N mod 5
.Hay una nueva entrada y ahora hay un nuevo valor
N' = N*2 + b
.Nuevo resto es entonces
M' = (N*2 + b) mod 5 = (M*2 + b) mod 5
.Esto es bastante fácil de tabular a mano:
Lo que coincide con la máquina de estado en la respuesta de Dave Tweed.
fuente
Uno espera que la pregunta de la entrevista fuera sobre cómo resolvería el problema, en lugar de los entresijos de VHDL o Verilog. Los detalles del idioma son sencillos una vez que tiene un algoritmo.
Si el número se pasa bit a bit con MSB primero, entonces el valor del número módulo 5 se puede calcular inicializando el estado y luego acumulando el valor conS=0 S←(2S+d) mod 5 S S,d S=0,⋯,4
fuente
Dependiendo de para qué se está escribiendo el VHDL, es posible que desee adoptar un enfoque que lo describa como un cálculo directo y combinacional. Recibir un número puede significar que el número completo estará en un registro durante un ciclo de reloj.
Podría, por ejemplo, anotar el mod 5 del valor que representa cada uno de los bits, sumarlos y luego repetir el proceso hasta que quede algo menor que 5. Implemente esto de manera combinada para todos los pasos de reducción, o reutilice la lógica para un pequeño número de ciclos.
Pero si usa el operador rem VHDL, esa puede ser la respuesta correcta. Suponiendo que la compañía tenga herramientas de síntesis decentes, eso le daría una implementación bastante eficiente, quizás un poco más de área que las soluciones de máquina de estado, pero rendimiento total y, por lo tanto, probablemente una buena energía por cálculo. ¡Es la opción que costaría menos tiempo de implementación y, por lo tanto, probablemente el menor dinero para el empleador!
Para ser justos, probablemente no sea la respuesta que buscan con esa pregunta, pero también es una oportunidad para mostrar cualquier experiencia de diseño real.
fuente
Si el número se presenta en fragmentos de más de un bit, puede ser útil usar algunos cálculos paralelos para calcular el residuo mod 15, con la condición de que el cálculo pueda producir 15 es exactamente si el residuo es cero. Una manera simple de calcular el residuo de mod-15 es observar que para cualquier valor de N> = 1, al agregar los 4N bits más a la izquierda a la parte de un número más allá, se obtendrá un valor congruente con el mod 15. Esto permite que el problema se subdivida de muchas maneras diferentes según los recursos disponibles.
Por ejemplo, si uno comienza con un valor de 32 bits, eso puede tratarse como ocho valores de 4 bits. Esos se pueden sumar por pares para obtener cuatro valores de 5 bits, que a su vez se pueden combinar en dos valores de 6 bits o un valor de 7 bits. Agregar los tres bits superiores de ese valor de 7 bits a los 4 bits inferiores producirá un valor de 5 bits que es como máximo 21. Por lo tanto, se puede determinar si el valor original es un múltiplo de 5 al observar si el valor final es uno de 0, 5, 10, 15 o 20.
fuente
No recuerdo mi VHDL, pero aquí hay un boceto de la idea que se me ocurrió por primera vez:
Los últimos dígitos (en la base 10) de las primeras potencias de dos son 1, 2, 4, 8, 6, 2, ... y el ciclo se repite. Por lo tanto, los restos mod 5 de potencias de dos son 1, 2, 4, 3, ...
Usando eso, podríamos cambiar en bits desde el LSB y acumular los restos mod 5 correspondientes a la posición cada vez que
1
se ve un bit. Realice el mod 5 de acumulación también, y es suficiente para verificar si la suma es cero al final.fuente
Podemos usar la idea de la respuesta aquí , que en la base 4 podemos deducir que un número es divisible por 5 solo si la suma de dígitos alterna es. Nosotros por lo tanto
Probemos con el número 166 = (10) (10) (01) (10): 2,2,1,2
2-2 + 1-2 = -1
que es <= 3 en valor absoluto y no 0 por qué podemos concluir en una sola iteración que 166 no está dividido equitativamente por 5.
Podría ser que una memoria pequeña podría ser más barata / mejor en términos de velocidad / nr de puertas que iterar. Por supuesto, uno puede calcular previamente lo peor (el mayor resultado posible dadas las entradas permitidas) y planificar el diseño en consecuencia.
fuente
El enfoque MSB es definitivamente más fácil, pero logré hacer el diagrama de estado LSB sin necesidad de generar la solución MSB ... solo me tomó un par de horas. Resulta ser equivalente al que muestra @ComFreek, solo anotado de manera diferente.
Vamos a seguir dos números. Primero, vamos a rastrear la suma acumulada, módulo 5 ("SUMA"). En segundo lugar, rastrearemos el valor de la próxima potencia de 2 que se cambiará, módulo 5 ("NEXT"). Representaré cada estado con posibles valores para "SUMA" en la parte superior, y sus correspondientes valores "SIGUIENTE" debajo de ellos.
Comenzaremos con el caso donde "SUMA" módulo 5 es 0:
Tenga en cuenta que un estado que se parece a:
3,2,4,1
1,4,3,2
es equivalente a:
1,3,4,2
2,1,3,4
Debido a que ambos estados representan que:
SUM = 1 y NEXT = 4 OR
SUM = 2 y NEXT = 3 OR
SUM = 3 y NEXT = 2 OR
SUM = 4 y NEXT = 1.
Bien, entonces ahora necesitamos desarrollar estados adicionales, ya que la mayoría de los entrevistadores no se impresionarán con un diagrama de estado con un solo estado. Terminamos cuando cada estado tiene dos transiciones.
Cada vez que realice la transición a un nuevo estado, cada número en "SIGUIENTE" se duplica, luego el módulo 5. Para la "SUMA", siga estas reglas:
Entonces, comencemos completando las transiciones cuando el bit entrante es 1.
Muy bien, ahora completamos los ceros. Solo hay un estado agregado, así que seguiremos adelante y completaremos sus transiciones también.
¡Y voilá! Tenemos una máquina de estado que acepta el LSB primero, sin tener que generar la solución MSB.
fuente
¡Todo lo anterior parece tan complicado! Hay una manera matemática fácil de detectar si un entero binario es divisible por cinco. Para empezar, ¿recuerdas cómo hacer "lanzar nueves" en la aritmética decimal ordinaria? El módulo de residuo 9 de un entero decimal es el mismo que el módulo de residuo 9 de la suma de sus dígitos. Esto funciona porque 9 es uno menos que la base numérica.
Hay un proceso similar, "expulsar once", donde los signos de dígitos alternativos se ponen negativos. Esto funciona porque once es uno mayor que la base numérica.
Entonces, si queremos "echar cinco", podríamos representar nuestro número entero en la base número cuatro. Luego comenzamos con el par de dígitos más bajo como una suma inicial, y lo restamos del siguiente par de dígitos para obtener la siguiente suma. Después de pasar por nuestro entero candidato de esta manera, la suma final será cero o divisible por 5 si nuestro entero original es divisible por 5.
Ejemplo 70: 01 00 01 10 -> 01 00 -1 -> 01 01 -> 00, divisible por 5 Ejemplo 49: 11 00 01 -> 11 -1 -> 1 00 -> 1, NO divisible por 5
Tenga en cuenta que debe llevar bits extra para el signo de la diferencia acumulada y para los casos en los que hay transporte.
Otra forma de hacerlo es simplemente agregar los dígitos hexadecimales para obtener el módulo de residuo 15. Por supuesto, necesita un paso lógico final para identificar los tres resultados aceptables de cero, cinco y diez.
Ejemplo 70: 4 6 -> A, entonces 70 es divisible por 5 (pero no por 15) Ejemplo 49: 3 1 -> 4, entonces 70 no es divisible por 5.
Tenga en cuenta que puede usar diferentes bases numéricas para construir muchas pruebas de divisibilidad, aunque en lógica informática las que tienen potencias de 2 +/- 1 son más fáciles de implementar.
En aritmética decimal, uno de mis favoritos es mi prueba para el mod 7 de residuos. Tenga en cuenta que 100 es dos mayor que un múltiplo de 7, por lo tanto, agrupe los dígitos en pares (trabaje en la base de número 100) y agregue los cientos DOS VECES de las unidades. Aquí trabajamos de izquierda a derecha ...
Ejemplo: 98 76 -> 2 72 -> 76, entonces 9876 no es divisible por 7. Es 6 mod 7. Ejemplo: 03 45 67 -> 51 67 -> 1 69 -> 71 entonces es 1 mod 7.
Por supuesto, en binario, simplemente tome la suma de los dígitos octales (grupos de 3 bits).
Lo siento, desearía ser un gurú de Verilog, pero la aritmética es todo lo que puedo ofrecer en esta etapa de la vida. Vea "Dead Reckoning" de Ron Doerfler para muchos trucos como este.
fuente
Una pregunta de entrevista VHDL debería dar lugar a algún código VHDL.
Tuve la oportunidad de encontrar un error de backend de ghdl llvm con una implementación de la tabla de transición de estado de Dave Tweed donde el autor de ghdl destiló la implementación en una función en 17 líneas:
El caso de prueba asociado es bastante pequeño, lo que permite una depuración más fácil y utiliza nombres de estado compatibles con VHDL en los tipos enumerados:
(creado con Dia)
La idea aquí es que la función (o incluso un ejemplo de programa VHDL de 27 líneas) es lo suficientemente corta como para escribir una respuesta VHDL durante una entrevista. No es necesario preocuparse por estropear una pregunta de la entrevista que requiere la demostración de conocimiento y habilidad, se espera que un entrevistado defienda una implementación cuando se le pregunta.
(El error de backend llvm se ha solucionado en commit 1f5df6e hoy).
Una de las cosas notables es que la tabla de transición de estado también nos dice dónde un bit de cociente sería un '1' que se muestra mediante una transición a un estado con un valor restante más bajo (o ambas transiciones para r4) al restar 5 del dividendo. Eso se puede codificar en una tabla separada (o una tabla de un tipo de registro que parece engorroso). Hacemos esto históricamente en hardware de gráficos que trata con resoluciones de pantalla horizontales que se multiplican por 5 píxeles.
Hacerlo nos da un div / mod5 que produce un cociente y resto:
Implementado aquí con una declaración de generación, una declaración de generación interna que produce bits de cociente. La matriz remaindr proporciona una traza de transición de estado:
Todo sin una operación aritmética.
También es posible implementar en un procedimiento sin que todos los registros aprovechen los parámetros con el modo fuera. Eso se acercaría a un número mínimo de líneas para una entrevista.
Una implementación secuencial con reloj requeriría un contador de bits y control de flujo (un flip flop JK y un par de compuertas).
Hay una compensación de tiempo / complejidad que depende del tamaño del dividendo que probablemente también deba defender en una entrevista.
fuente