项目作者: blroot

项目描述 :
Procesador MIPS segmentado
高级语言: VHDL
项目地址: git://github.com/blroot/MIPS-Segmentado.git
创建时间: 2019-07-25T14:09:21Z
项目社区:https://github.com/blroot/MIPS-Segmentado

开源协议:

下载


Práctica de Laboratorio: Microprocesador MIPS Segmentado

  • Trabajo Práctico
  • Arquitectura de Computadoras I
  • Universidad Nacional de Tres de Febrero

Integrantes

  • Chavez, Matias. Legajo N° 41902
  • Lottero, Bruno. Legajo N° 18434

Objetivo

El objetivo de esta práctica es ampliar a la implementación el microprocesador MIPS (visto en clase de teoría) en
VHDL. En concreto, se va a realizar la versión segmentada del microprocesador, cuyos detalles se
pueden encontrar en: “Computer Organization and Design: The Hardware/Software Interface “, por
David A.Patterson y John L. Hennessy.
El modelo de las memorias de datos y programas proporcionado (archivo memory.vhd) no introduce
ciclos de espera y responde en el mismo ciclo. Además, utiliza dos archivos separados para el
contenido inicial de cada memoria, archivo llamado “program1” para memoria de instrucciones y
“data” para memoria de datos. Se proporcionan un archivo de ejemplo (program1.s) para utilizar
junto con el testbench de la práctica, si bien se pueden generar otros archivos correspondientes a
otros códigos para hacer más pruebas.

Ejercicio

Se dispone de la implementación de un procesador completo que admite las siguientes
instrucciones: add, sub, and, or, lw, sw, slt y beq. En cualquier caso, la instrucción beq, que implica
riesgos de control por ser un salto, funcionará “anómalamente” en la versión básica del ejercicio
obligatorio.

Se pide que al diseño completo del procesador MIPS segmentado realizado por la cátedra,
incorporar las siguientes instrucciones y verificar el diseño utilizando el archivo “program1”
proporcionado por la cátedra.

Instrucciones a implementar



Resolución

Agregado de Inmediatos

Para el agregado de las instrucciones LUI, ADDI, AND y ORI, se realizaron cambios sobre

  • processor.vhd
    • Se aumento la dimension de la señal de control de la ALU de 2 a 3 bits, para soportar los inmediatos nuevos.
      1. signal ALUOp: std_logic_vector(2 downto 0);
    • Se definieron en la etapa ID, las señales de control para las operaciones según fue necesario
      1. --LUI--
      2. when "001111" =>
      3. ID_RegWrite<= '1';
      4. ID_MemToReg<= '0';
      5. ID_MemRead<= '0';
      6. ID_MemWrite<= '0';
      7. ID_Branch<= '0';
      8. ID_RegDst<= '0';
      9. ID_AluOp<= "100";
      10. ID_ALUSrc<= '1';
      11. --ADDI--
      12. when "001000" =>
      13. ID_RegWrite<= '1';
      14. ID_MemToReg<= '0';
      15. ID_MemRead<= '0';
      16. ID_MemWrite<= '0';
      17. ID_Branch<= '0';
      18. ID_RegDst<= '0';
      19. ID_AluOp<= "101";
      20. ID_ALUSrc<= '1';
      21. --ANDI--
      22. when "001100" =>
      23. ID_RegWrite<= '1';
      24. ID_MemToReg<= '0';
      25. ID_MemRead<= '0';
      26. ID_MemWrite<= '0';
      27. ID_Branch<= '0';
      28. ID_RegDst<= '0';
      29. ID_AluOp<= "110";
      30. ID_ALUSrc<= '1';
      31. --ORI--
      32. when "001101" =>
      33. ID_RegWrite<= '1';
      34. ID_MemToReg<= '0';
      35. ID_MemRead<= '0';
      36. ID_MemWrite<= '0';
      37. ID_Branch<= '0';
      38. ID_RegDst<= '0';
      39. ID_AluOp<= "111";
      40. ID_ALUSrc<= '1';
      41. --J--
      42. when "000010" =>
      43. ID_RegWrite<= '1';
      44. ID_MemToReg<= '0';
      45. ID_MemRead<= '0';
      46. ID_MemWrite<= '0';
      47. ID_Branch<= '0';
      48. ID_Jump <= '1';
      49. ID_RegDst<= '0';
      50. ID_AluOp<= "011"; --alu va por others
      51. ID_ALUSrc<= '1';
    • Se definieron en la etapa EX los casos anteriores en la unidad de control para la ALU
      1. when "100" => -- LUI
      2. AluControl <= "100";
      3. when "101" => -- ADDI
      4. AluControl <= "010";
      5. when "110" => -- ANDI
      6. AluControl <= "000";
      7. when "111" => -- ORI
      8. AluControl <= "001";
  • alu.vhd
    • En la ALU se adecuó la operación para LUI y luego se redefinieron los valores del case en 3 bits
      ```vhdl
      process(a, b, control)
      begin
      case control is
      when “000” => aux <= a and b;
      when “001” => aux <= a or b;
      when “010” => aux <= a + b;
      when “110” => aux <= a - b;
      when “111” =>
      1. if(a<b) then
      2. aux <= x"00000001";
      3. else aux <= x"00000000";
      4. end if;
      when “100” => aux <= b(15 downto 0) & x”0000”;
      when others => aux <= x”00000000”;
      end case;

end process;

  1. ### Agregado de Jump
  2. Para el agregado de la J, se realizaron cambios sobre processor.vhd
  3. - En primer lugar se creo la señal de Jump y las señales que resguardan el cálculo del salto
  4. ```vhdl
  5. -- Control de mux jump
  6. signal Jump: std_logic;
  7. --ETAPA ID--
  8. signal ID_Jump: std_logic;
  9. --ETAPA EX--
  10. signal EX_Jump: std_logic;
  11. -- Para direccion de salto en jump
  12. signal EX_PC_Jump: std_logic_vector (31 downto 0);
  • En la etapa ID se agrega el seteo de la señal de control del jump en CONTROL_UNIT según corresponda
    1. ID_Jump <= '1';
    o
    1. ID_Jump <= '0';
  • Además se propaga la señal de control
    1. EX_Jump <= ID_Jump;
    • A continuación en la etapa EX, se realiza el cálculo del salto para el J y se propaga la señal
  1. -- Calculo dirección de salto (Jump)
  2. EX_PC_Jump <= EX_PC_4(31 downto 28)&EX_immediate(25 downto 0)&"00";
  3. -- Control de Jump
  4. Jump <= EX_Jump;
  • Por ultimo, en la etapa IF, se aplica nueva lógica para decidir como cargar el PC según como se hayan cargado las señales antes mencionadas
  1. next_PC <= MEM_PC_Branch when (PcSrc = '1') else
  2. EX_PC_jump when ((PcSrc = '0') and (Jump = '1')) else
  3. PC_4;

Mediante esta lógica podemos tener una instrucción BEQ y a continuación una J en memoria de instrucciones y el funcionamiento va a ser el esperado (no se necesitan NOP) se escribió el programa probando_beq_j.s para comprobar dicho funcionamiento.

Flush del datapath ante saltos

Para complementar lo visto en clase y por una cuestión de consistencia con la lógica anterior, optamos por agregar el flush de las etapas que corresponden.
El diseño de este procesador MIPS trabaja sin predicción de saltos, o tambien podriamos decir que realiza predicción no efectiva (se asume que el salto no es efectivo).
De esta manera, cuando realmente se efectua un salto, es necesario limpiar las etapas que contienen instrucciones mal cargadas.
Para realizar esto, aplicamos una logica de reset en los cambios de etapa, a saber:

  • La existencia de un BEQ se conoce en la etapa ID sobre la señal ID_Branch y la misma se propaga hasta la etapa MEM en
    la señal Branch, ya que recién en la etapa EX se confirma la efectividad del salto.
    Luego, en caso positivo, se limpian los registros IF/ID-ID/EX-EX/MEM para poder cargar el PC correcto a donde apunta el salto.

  • Luego para el caso del J, se conoce tambien en la etapa ID la señal ID_Jump, la misma se propaga hasta EX en
    donde se carga finalmente la señal Jump. Luego al avanzar un ciclo, estando el J en etapa MEM, se deben limpiar los registros IF/ID-ID/EX-

  • Para probar el funcionamiento, se escribieron los programas adicionales de prueba:

    • probando_flush_beq.s
      • probando_flush_j.s
      • También es válido para probar esto el programa Program1.s provisto originalmente
  1. -- REGISTRO DE SEGMENTACION IF/ID
  2. if (PcSrc = '1' or Jump = '1') then
  3. ID_PC_4 <= (others => '0');
  4. ID_Instruction <= (others => '0');
  5. -- REGISTRO DE SEGMENTACION ID/EX
  6. if ( PcSrc = '1' or Jump = '1') then
  7. EX_data1_rd <= (others =>'0');
  8. EX_data2_rd <= (others =>'0');
  9. EX_RegWrite <= '0' ;
  10. EX_MemToReg <= '0' ;
  11. EX_MemRead <= '0' ;
  12. EX_MemWrite <= '0' ;
  13. EX_Branch <= '0' ;
  14. EX_Jump <= '0' ;
  15. RegDst <= '0' ;
  16. ALUOp <= (others =>'0');
  17. ALUSrc <= '0' ;
  18. EX_immediate <= (others => '0');
  19. EX_rt <= (others => '0');
  20. EX_rd <= (others => '0');
  21. -- REGISTRO DE SEGMENTACION EX/MEM
  22. if ( PcSrc = '1') then
  23. MEM_RegWrite <= '0';
  24. MEM_MemToReg <= '0';
  25. MEM_MemRead <= '0';
  26. MEM_MemWrite <= '0';
  27. Branch <= '0';
  28. MEM_Zero <= '0';
  29. MEM_AluResult <= (others => '0');
  30. MEM_data2_rd <= (others => '0');
  31. MEM_Instruction_RegDst <= (others => '0');
  32. MEM_PC_Branch <= (others => '0');