¿Cómo diseñar eficientemente el código de operación para una CPU?

12

Estoy construyendo una CPU simple de 16 bits en Logisim y tengo la ALU lista y los códigos de operación que quiero tener. Ahora me resulta muy difícil encontrar la codificación correcta para los comandos, de modo que los diferentes subcircuitos (por ejemplo, lógica, aritmética) no necesiten todos los cables de control (que construyen la codificación) como entrada, sino la menor cantidad posible. ¿Existen estrategias o métodos que ayuden con un diseño eficiente de código de operación?

gracias por adelantado

Benjoyo
fuente
1
Primero construya su ALU y vea qué cables de control necesita. Luego, conéctelos directamente al registro de "instrucción actual". Lo mismo para la lógica de control de acceso a la memoria y cualquier otra clase importante de códigos de operación. Luego use los bits restantes para seleccionar qué subcircuito está activado.
user253751
1
También está el documento original de Ken Chapman de su máquina de estado programable de 8 bits KCPSM, también conocido como PicoBlaze. Describe cómo eligió las instrucciones y diseñó el ISA. dc.uba.ar/materias/disfpga/2010/c2/descargas/…
Paebbels

Respuestas:

9

Creo que es un buen enfoque estudiar algunos otros conjuntos de instrucciones.

Uno pequeño sería el MSP430 de TI, es un procesador de 16 bits con aproximadamente 22 instrucciones.

http://www.physics.mcmaster.ca/phys3b06/MSP430/MSP430_Instruction_Set_Summary.pdf

También puede consultar los AVR de Atmel, que también tienen un conjunto de instrucciones bastante pequeño.

En un pequeño proyecto mío intenté desarrollar un procesador simple de 32 bits en VHDL con un pequeño conjunto de instrucciones (14 instrucciones):

http://www.blog-tm.de/?p=80

Debido a mi tiempo libre actual no está completamente terminado. Las instrucciones se implementan pero dos no se prueban y tal vez faltan algunos indicadores de estado.

TM90
fuente
Pero no encontré algo donde pudiera ver cuál es la codificación real y por qué fue elegida para ser así.
Benjoyo
Puede encontrar la codificación actual en el repositorio: github.com/TM90/MISC_Processor/raw/master/Documentation/… . La razón por la que elijo estas codificaciones de manera que la lógica en el decodificador de instrucciones sea mínima.
TM90
7

Estudie (pero no reproduzca) el enfoque ARM para la codificación de instrucciones. Está muy orientado a prefijos (como el enfoque del árbol Huffman recomendado por Dzarda) y es muy uniforme en términos de dónde está la parte de selección de registro de la instrucción.

El enfoque poco imaginativo pero confiable es enumerar todas las señales de control que tiene, que probablemente serán más de 16 bits, y luego intentar hacer una minimización lógica de estilo de mapa de Karnaugh en ellas.

pjc50
fuente
Realmente no entiendo lo que quieres decir con señales de control.
Benjoyo
Lo que encontré y me gustó del ARM es el campo de condición, lo incluiré.
Benjoyo
Las señales de control son las entradas a los diversos multiplexores y permiten que los datos directos entre las partes de la CPU.
pjc50
Para una arquitectura de 16 bits, no creo que la codificación de instrucciones de ARM sea apropiada. Mayby thumb2 es mejor. Pero me gusta la forma de codificación de MIPS, simple y fácil de entender, aunque un poco despilfarro
phuclv
4

Una vez intenté hacer una CPU de 4 bits con núcleo de longitud de instrucción de 8 bits en Logisim. Terminé con una máquina de estado simple, más que una CPU, realmente.

Cosas al azar para buscar

  • Árboles huffman
  • Codificación de longitud fija o variable?
  • ¿Es un diseño de von Neumann con espacio de una sola dirección, o estilo Harvard con datos / programa separados?

Excelente video en Computerphile sobre los árboles Huffman:

https://www.youtube.com/watch?v=umTbivyJoiI

Dzarda
fuente
La codificación de Huffman no funcionará para una codificación de longitud fija, ¿verdad?
Benjoyo
@Benjoyo Puedo imaginar un escenario con los bits de repuesto utilizados para variaciones de las instrucciones más utilizadas, proporcionando así más funcionalidad.
Dzarda
Pero no entiendo qué tipo de optimización trae esto. No me ayuda con el diseño del circuito. ¿Cuál es el objetivo cuando se usa la codificación Huffman para opcode?
Benjoyo
4

El ISA que escribí para la clase tenía un código operativo de 4 bits como este: 1XXX ALU instructions 01XX jump, jump register, call etc 001X branch not equal, branch equal zero 000X 0 - load, 1 - store

En lugar de ser el más óptimo, este es uno de los estilos más fáciles de construir / diseñar puertas porque la señal de entrada de un solo bit puede controlar por completo qué camino lógico se toma. Alternativamente, puede codificar con Huffman sus símbolos más utilizados y ponerlos a cero para obtener un código operativo de longitud fija.


fuente
Este tipo de optimización es lo que estoy buscando en este momento. Pero tengo un código de operación de 5 bits y me cuesta agrupar los comandos para que tenga sentido en el circuito.
Benjoyo
@Benjoyo, podrías tener muchas más instrucciones de ALU con el conjunto de bits superior. Además, la cobertura de mi condición de salto era bastante débil y la mayoría de las ramas normales requerirían dos instrucciones. En general, pensé en las categorías como: Matemáticas / Control / Memoria
3

Una cosa que deberá considerar es si permite cualquier forma de instrucción de varias palabras, o cualquier cosa que pueda "actuar" como una instrucción de varias palabras; si lo hace, es posible que desee considerar si usar palabras de instrucción adicionales después de la instrucción principal o prefijar las palabras antes. Permitir prefijos y palabras de continuación puede aumentar la complejidad del manejo de interrupciones, pero puede evitar la necesidad de ajustar las instrucciones de uso poco frecuente en el mismo espacio de código de operación que las de uso común.

Si las instrucciones se obtienen en el ciclo antes de que se ejecuten, se podría tener una instrucción de "ramificación condicional" que haga que se omita la siguiente palabra de instrucción o que su contenido se transfiera directamente al contador del programa; dicho diseño podría agregar cierta complejidad adicional para interrumpir la secuenciación, pero podría aliviar la necesidad de utilizar una gran parte del espacio de código de operación para las instrucciones de "ramificación", "salto" y "llamada", al tiempo que permite un rango mucho más amplio de condiciones de ramificación de lo contrario sería posible. Dado que una rama que se toma generalmente requerirá un ciclo muerto después de la ejecución de la instrucción en sí misma, independientemente de dónde provenga la dirección, hacer que la dirección provenga de la siguiente palabra que se ha obtenido pero no se ejecutará no tiene ningún costo adicional hora.

Aunque mover la dirección de destino fuera de las instrucciones de bifurcación reducirá la cantidad de espacio de código de operación que engullen, un formato de código de operación de 16 bits sigue siendo bastante limitado. Usar instrucciones de prefijo puede ayudar con eso. Si, por ejemplo, uno quiere tener 32 registros, lo que permite que cualquier registro se especifique independientemente como fuente1, fuente2 y destino requeriría 15 bits en el código de operación, lo que permite un total enorme de dos instrucciones. No muy útil Por otro lado, sería bueno poder usar cualquiera de los 32 registros para cada uno de los tres operandos. Uno podría equilibrar los dos objetivos haciendo que cualquier operación ALU que no esté precedida por un prefijo use ocho bits para hacer dos selecciones de registro de uno de dieciséis, pero que una operación ALU que sigue inmediatamente a un prefijo use algunos bits en el prefijo a lo largo con ocho de las siguientes instrucciones, para permitir la selección independiente de ambas fuentes y el destino del conjunto completo de 32. Las instrucciones que usan los registros superiores tomarían dos palabras / ciclos en lugar de uno, pero en algunos casos tal compensación podría valer la pena. La mayor dificultad con el uso de prefijos es que uno debe evitar que ocurra una interrupción entre un prefijo y la siguiente instrucción o bien asegurarse de que si se produce una interrupción allí, la instrucción después del prefijo seguirá utilizando los registros correctos [por ejemplo, al tener el programa -lógica de guardar contador almacena la dirección de la última instrucción sin prefijo ejecutada]. pero en algunos casos, tal compensación podría valer la pena. La mayor dificultad con el uso de prefijos es que uno debe evitar que ocurra una interrupción entre un prefijo y la siguiente instrucción o bien asegurarse de que si se produce una interrupción allí, la instrucción después del prefijo seguirá utilizando los registros correctos [por ejemplo, al tener el programa -lógica de guardar contador almacena la dirección de la última instrucción sin prefijo ejecutada]. pero en algunos casos, tal compensación podría valer la pena. La mayor dificultad con el uso de prefijos es que uno debe evitar que ocurra una interrupción entre un prefijo y la siguiente instrucción o bien asegurarse de que si se produce una interrupción allí, la instrucción después del prefijo seguirá utilizando los registros correctos [por ejemplo, teniendo el programa -lógica de guardar contador almacena la dirección de la última instrucción sin prefijo ejecutada].

El uso de instrucciones de varias palabras hará que algunos aspectos del diseño sean más difíciles, pero puede reducir la necesidad de tomar otras decisiones difíciles.

Super gato
fuente
0

Este tipo tiene los mejores detalles sobre la comprensión del cableado de la parte codificada de un decodificador, que explica las líneas de control para una CPU codificada: http://minnie.tuhs.org/CompArch/Tutes/week03.html Como puede ver, su elección en Opcodes realmente impacta cuán compleja es la lógica Decode.

cmacdona101
fuente