{"id":559,"date":"2020-11-11T17:52:05","date_gmt":"2020-11-11T17:52:05","guid":{"rendered":"http:\/\/dsd.webs.upv.es\/?p=559"},"modified":"2020-11-27T08:11:57","modified_gmt":"2020-11-27T08:11:57","slug":"diseno-de-un-microprocesador-simple","status":"publish","type":"post","link":"https:\/\/dsd.webs.upv.es\/?p=559","title":{"rendered":"Verificaci\u00f3n hardware de un microprocesador simple"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Con este ejemplo queremos mostrar algunas caracter\u00edsticas que puedan ser \u00fatiles en el dise\u00f1o de sistemas m\u00e1s complejos; pero la arquitectura de este microprocesador (Multi-Cycle Processor) tiene poco que ver con las solicitadas en la tarea 3 fase 2 (single cycle processor) y 3 (pipeline processor) :<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Realizaci\u00f3n de un interfaz para modelar un bus triestado de interconexi\u00f3n de los diferentes elementos de un microprocesador. <ul><li>El bus triestado incomoda bastante a una FPGA y solo las c\u00e9lulas I\/O de las FPGA tienen capacidad para implementarlo.<\/li><li>El c\u00f3digo es sintetizable en nuestra FPGA Cyclone V<\/li><\/ul><\/li><li>Determinaci\u00f3n del funcionamiento del microprocesador mediante una especificaci\u00f3n ASM (con 11 estados)<\/li><li>Es un Multi-Cycle Processor ( se requieren 6 ciclos para completar cada instrucci\u00f3n) sin posibilidad de comenzar una nueva instrucci\u00f3n hasta que ha finalizado la anterior, en contraposici\u00f3n a los denominados \u00abpipeline processors\u00bb como el que vais a dise\u00f1ar en la fase 3<\/li><li>Realizaci\u00f3n de un control cableado (FSM) en lugar de un control microprogramado<\/li><li>Implementaci\u00f3n de una memoria RAM en la que se almacena el programa y los datos.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">La estructura del microprocesador que vamos a dise\u00f1ar es la de la siguiente figura<\/p>\n\n\n\n<figure class=\"wp-block-image size-large is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/dsd.webs.upv.es\/wp-content\/uploads\/2020\/11\/image-2.png\" alt=\"\" class=\"wp-image-564\" width=\"559\" height=\"461\" srcset=\"https:\/\/dsd.webs.upv.es\/wp-content\/uploads\/2020\/11\/image-2.png 735w, https:\/\/dsd.webs.upv.es\/wp-content\/uploads\/2020\/11\/image-2-300x247.png 300w\" sizes=\"auto, (max-width: 559px) 100vw, 559px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Veamos como ser\u00eda el c\u00f3digo del interfaz y del top de la jerarqu\u00eda.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Interfaz<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">El interfaz lo voy a utilizar tanto para la distribuci\u00f3n de los datos (mediante un bus triestado denomindo sysbus) como para la distribuci\u00f3n de las se\u00f1ales de control que ir\u00e1n desde el control path a cada unos de los elementos del data-path (PC,IR, ALU y RAM) y para la recepci\u00f3n de las se\u00f1ales de estado desde el control-path procedentes del data-path.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:verilog decode:true \">import cpu_defs::*;\n\ninterface CPU_bus (input logic clock, n_reset,\n                   inout wire [WORD_W-1:0] sysbus);\n\n\/\/senyales de control\nlogic ACC_bus, load_ACC, PC_bus, load_PC, load_IR,\n      load_MAR, MDR_bus, load_MDR, ALU_ACC, ALU_add,\n      ALU_sub, INC_PC, Addr_bus, CS, R_NW;\n\/\/senyales de estado\nlogic  z_flag;\nlogic [OP_W-1:0] op;\n\nmodport IR_port(input clock, n_reset, \n                input Addr_bus, load_IR,\n                inout sysbus,\n                output op);\n\nmodport RAM_port (input clock, n_reset, \n                  input MDR_bus, load_MDR, load_MAR, CS, R_NW,\n                  inout sysbus);\n\nmodport ALU_port (input clock, n_reset, \n                  input ACC_bus, load_ACC, ALU_ACC, ALU_add, ALU_sub,\n                  inout sysbus,\n                  output z_flag);\nmodport PC_port (input clock, n_reset,\n                 input PC_bus, load_PC, INC_PC,\n                 inout sysbus);\n\nmodport seq_port (input clock, n_reset, \n                  input op, z_flag, \n                  output ACC_bus, load_ACC, PC_bus,\n                         load_PC, load_IR, load_MAR,\n                         MDR_bus, load_MDR, ALU_ACC,\n                         ALU_add, ALU_sub, INC_PC,\n                         Addr_bus, CS, R_NW);\n\nendinterface<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">siendo el \u00abpackage\u00bb importado el siguiente<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:verilog decode:true \">package cpu_defs;\n\nparameter WORD_W = 8;\nparameter OP_W = 3;\nenum logic[2:0] {LOAD=3'b101,\n                 STORE=3'b110,\n                 ADD=3'b010,\n                 SUB=3'b011,\n                 BNE=3'b111} opcodes;\nendpackage<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Como puede observarse nuestro microprocesador es de 8 bits y tenemos tan solo 3 bits para codificar instrucciones. Vamos a definir \u00fanicamente 5 instrucciones.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Top de la jerarqu\u00eda<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Ahora la descripci\u00f3n del top de la jerarqu\u00eda se ve altamente simplificada. Es sin duda una de las cosas que se pretend\u00eda con el uso de la construcci\u00f3n \u00abinterface\u00bb <\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"tab-convert:true lang:verilog decode:true \">import cpu_defs::*;\n\nmodule CPU (input logic CLOCK_50,\n           input logic [0:0]  KEY,\n           inout wire [WORD_W-1:0] sysbus);\n\t\t\t\t\nlogic clock;\nassign clock=CLOCK_50;\nlogic n_reset;\nassign n_reset=KEY[0];\n\nCPU_bus bus (.*);\n\nsequencer s1 (.*);\n\nIR i1 (.*);\n\nPC p1 (.*);\n\nALU a1 (.*);\n\nRAM r1 (.*);\n\nendmodule<\/pre><\/div>\n\n\n\n<h1 class=\"wp-block-heading\">Elementos del data-path<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Veamos los elementos del data path<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">PC<\/h4>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:verilog decode:true \">import cpu_defs::*;\n\nmodule PC (CPU_bus.PC_port bus);\n\nlogic [WORD_W-OP_W-1:0] count;\nassign bus.sysbus = bus.PC_bus ?{{OP_W{1'b0}},count} : 'z;\n\nalways_ff @(posedge bus.clock, negedge bus.n_reset)\n  begin\n\tif (!bus.n_reset)\n\t\tcount &lt;= 0;\n\telse\n\t\tif (bus.load_PC)\n\t\t\tif (bus.INC_PC)\n\t\t\t\tcount &lt;= count + 1;\n\t\t\telse\n\t\t\t\tcount &lt;= bus.sysbus;\n  end\nendmodule<\/pre><\/div>\n\n\n\n<h4 class=\"wp-block-heading\">ALU<\/h4>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:verilog decode:true \">import cpu_defs::*;\n\nmodule ALU (CPU_bus.ALU_port bus);\n\nlogic [WORD_W-1:0] acc;\n\nassign bus.sysbus = bus.ACC_bus ? acc : 'Z;\nassign bus.z_flag = acc == 0 ? '1 : '0;\n\nalways_ff @(posedge bus.clock, negedge bus.n_reset)\n  begin\n  if (!bus.n_reset)\n    acc &lt;= 0;\n  else\n    if (bus.load_ACC)\n        if (bus.ALU_ACC)\n        begin\n\t    if (bus.ALU_add)\n               acc &lt;= acc + bus.sysbus;\n            else if (bus.ALU_sub)\n               acc &lt;= acc - bus.sysbus;\n        end\n        else\n            acc &lt;= bus.sysbus;\n  end\nendmodule<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Este modulo implementa m\u00e1s bien un registro A(o ACC) y un sumador\/restador conectados en modo acumulaci\u00f3n, de forma que se puedan hacer operaciones de sumas y restas sin problemas.<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">IR<\/h4>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:verilog decode:true \">import cpu_defs::*;\n\nmodule IR (CPU_bus.IR_port bus);\n\nlogic  [WORD_W-1:0] instr_reg;\n\nassign bus.sysbus = bus.Addr_bus ?{{OP_W{1'b0}}, instr_reg[WORD_W-OP_W-1:0]}:'z;\n\nalways_comb\n  bus.op = instr_reg[WORD_W-1:WORD_W-OP_W];\n\nalways_ff @(posedge bus.clock, negedge bus.n_reset)\n  begin\n  if (!bus.n_reset)\n    instr_reg &lt;= 0;\n  else\n    if (bus.load_IR)\n      instr_reg &lt;= bus.sysbus;\n  end\n\nendmodule<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n\n\n\n<h4 class=\"wp-block-heading\">RAM<\/h4>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:verilog decode:true \">import cpu_defs::*;\n\nmodule RAM (CPU_bus.RAM_port bus);\n\nlogic [WORD_W-1:0] mdr;\nlogic [WORD_W-1:0] salida_mem;\nlogic [WORD_W-OP_W-1:0] mar;\n\nassign bus.sysbus = bus.MDR_bus ? salida_mem : 'z;\n\nalways_ff @(posedge bus.clock, negedge bus.n_reset)\nbegin\n\tif (!bus.n_reset)\n            begin\n             mar &lt;='0;\n             mdr&lt;='0;\n            end\n\telse\n\t\tif (bus.load_MAR)\n\t\t\tmar &lt;= bus.sysbus[WORD_W-OP_W-1:0];\n\t\telse if (bus.load_MDR)\n\t\t\tmdr &lt;= bus.sysbus;\nend\n\nlogic [WORD_W-1:0] mem [0:(1&lt;&lt;(WORD_W-OP_W))-1];\ninitial\n   $readmemb(\"PGM_best.TXT\",mem,0);\n\nalways_ff @(posedge bus.clock)\nbegin\n if (bus.CS)\n\tif (!bus.R_NW)\n\t\tmem[mar] &lt;= mdr;\n\telse\n\t\tsalida_mem= mem[mar];\nend\n\nendmodule<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Este \u00faltimo componente si que tiene algunas caracter\u00edsticas que conviene resaltar:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Tenemos una memoria \u00absingle port\u00bb de lectura s\u00edncrona<\/li><li>Tenemos dos registros de apoyo, uno (mdr) que registra  el dato de entrada y otro (mar) que registra la direcci\u00f3n.<\/li><\/ul>\n\n\n\n<h1 class=\"wp-block-heading\">Control-path<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">El control path podemos observarlo en el siguiente fichero<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:verilog decode:true \">import cpu_defs::*;\n\nmodule sequencer (CPU_bus.seq_port bus);\n\nenum {s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10}  state;\n\nalways_ff @(posedge bus.clock, negedge bus.n_reset)\n  begin: seq\n    if (!bus.n_reset)\n      state &lt;= s0;\n    else\n       case (state)\n          s0: state &lt;= s1;\n          s1: state &lt;= s2;\n          s2: state &lt;= s3;\n          s3: if (bus.op == STORE)\n                 state &lt;= s4;\n               else\n                 state &lt;= s6;\n          s4: state &lt;= s5;\n          s5: state &lt;= s0;\n          s6: if (bus.op == LOAD)\n                 state &lt;= s7;\n               else if (bus.op == BNE)\n                  if (~bus.z_flag)\n                   state &lt;= s9;\n                  else\n                   state &lt;= s10;\n               else\n                   state &lt;= s8;\n          s7: state &lt;= s0;\n          s8: state &lt;= s0;\n          s9: state &lt;= s0;\n          s10: state &lt;= s0;\n    endcase\n  end\nalways_comb\nbegin: com\n  \/\/ reset all the control signals to default\n  bus.ACC_bus = '0;\n  bus.load_ACC = '0;\n  bus.PC_bus = '0;\n  bus.load_PC = '0;\n  bus.load_IR = '0;\n  bus.load_MAR = '0;\n  bus.MDR_bus = '0;\n  bus.load_MDR = '0;\n  bus.ALU_ACC = '0;\n  bus.ALU_add = '0;\n  bus.ALU_sub = '0;\n  bus.INC_PC = '0;\n  bus.Addr_bus = '0;\n  bus.CS = '0;\n  bus.R_NW = '0;\n  case (state)\n    s0: begin      bus.PC_bus = '1;\n      bus.load_MAR = '1;\n      bus.INC_PC = '1;\n      bus.load_PC = '1;\n      end\n    s1: begin\n      bus.CS = '1;\n      bus.R_NW = '1;\n      end\n    s2: begin\n      bus.MDR_bus = '1;\n      bus.load_IR = '1;\n      end\n    s3: begin\n      bus.Addr_bus = '1;\n      bus.load_MAR = '1;\n      end\n    s4: begin\n      bus.ACC_bus = '1;\n      bus.load_MDR = '1;\n      end\n    s5: begin\n      bus.CS = '1;\n      end\n    s6: begin\n      bus.CS = '1;\n      bus.R_NW = '1;\n      end\n    s7: begin\n      bus.MDR_bus = '1;\n      bus.load_ACC = '1;\n      end\n    s8: begin\n      bus.MDR_bus = '1;\n      bus.ALU_ACC = '1;\n      bus.load_ACC = '1;\n      if (bus.op == ADD)\n        bus.ALU_add = '1;\n      else if (bus.op == SUB)\n        bus.ALU_sub = '1;\n      end\n    s9: begin\n      bus.MDR_bus = '1;\n      bus.load_PC = '1;\n      end\n    s10: ;\nendcase\nend\nendmodule<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Como puede observarse es una m\u00e1quina Mealy de 11 estados<\/p>\n\n\n\n<h1 class=\"wp-block-heading\">Procedimiento de verificaci\u00f3n<\/h1>\n\n\n\n<p class=\"wp-block-paragraph\">Supongamos que tenemos un programa preparado para comprobar todas las instrucciones desarrolladas. En nuestro caso es un programa para generar n\u00fameros fibonacci.<\/p>\n\n\n\n<div class=\"wp-block-urvanov-syntax-highlighter-code-block\"><pre class=\"lang:c decode:true \">10110010   \/\/load A,[18];   Carga en el acumulador el n\u00famero i-\u00e9simo.\n01010011   \/\/add A,[19];    S\u00famale el (i+1)-\u00e9simo.\n11010100\t\/\/store [20],A;\t Guardalo en la siguiente posici\u00f3n.\n10100000   \/\/load A,[0];    Coje la primera instrucci\u00f3n.\n01010010   \/\/add A,[18];    S\u00famale 1, (Fib(0)=1). De este modo aumenta en uno la direcci\u00f3n.\n11000000   \/\/store [0],A;   Guarda la nueva instrucci\u00f3n.\n10100001\t\/\/load A,[1];    idem...\n01010010\t\/\/add A,[18];\n11000001\t\/\/store [1],A; \n10100010\t\/\/load A,[2];    idem...\n01010010\t\/\/add A,[18];\n11000010\t\/\/store [2],A;  \n10101111\t\/\/load A,[15];    idem...\n01110010\t\/\/sub A,[18];\n11001111\t\/\/store [15],A;\n00001011        \/\/cantidad de numeros fibonacci\n11110001\t\/\/jump 0;\t\t Ejecuta las nuevas instrucciones.\n00000000 \n00000001   \/\/Fib(0)\n00000001   \/\/Fib(1)<\/pre><\/div>\n\n\n\n<p class=\"wp-block-paragraph\">Vamos a explicar con el siguiente v\u00eddeo c\u00f3mo verificar el funcionamiento del microprocesador desarrollado bajo una plataforma FPGA remota.<\/p>\n\n\n\n<iframe loading=\"lazy\" allowfullscreen=\"\" src=\"https:\/\/media.upv.es\/player\/embed.html?id=9ada65f0-25b3-11eb-9296-05fcb72d19f3\" style=\"border:0px #FFFFFF none;\" name=\"Paella Player\" scrolling=\"no\" frameborder=\"0\" marginheight=\"0px\" marginwidth=\"0px\" width=\"640\" height=\"360\"> <\/iframe>\n","protected":false},"excerpt":{"rendered":"<p>Con este ejemplo queremos mostrar algunas caracter\u00edsticas que puedan ser \u00fatiles en el dise\u00f1o de sistemas m\u00e1s complejos; pero la arquitectura de este microprocesador (Multi-Cycle Processor) tiene poco que ver con las solicitadas en la tarea 3 fase 2 (single cycle processor) y 3 (pipeline processor) : Realizaci\u00f3n de un interfaz para modelar un bus triestado de interconexi\u00f3n de los diferentes elementos de un microprocesador. El bus triestado incomoda bastante a una FPGA y solo las c\u00e9lulas I\/O de las FPGA tienen capacidad para implementarlo. El c\u00f3digo es sintetizable en nuestra FPGA Cyclone V Determinaci\u00f3n del funcionamiento del microprocesador mediante una especificaci\u00f3n ASM (con 11 estados) Es un Multi-Cycle Processor ( se requieren 6 ciclos para completar cada instrucci\u00f3n) sin posibilidad de comenzar una nueva instrucci\u00f3n hasta que ha finalizado la anterior, en contraposici\u00f3n a los denominados \u00abpipeline processors\u00bb como el que vais a dise\u00f1ar en la fase 3 Realizaci\u00f3n de un control cableado (FSM) en lugar de un control microprogramado Implementaci\u00f3n de una memoria RAM en la que se almacena el programa y los datos. La estructura del microprocesador que vamos a dise\u00f1ar es la de la siguiente figura Veamos como ser\u00eda el c\u00f3digo del interfaz y del top de la jerarqu\u00eda. Interfaz El interfaz lo voy a utilizar tanto para la distribuci\u00f3n de los datos (mediante un bus triestado denomindo sysbus) como para la distribuci\u00f3n de las se\u00f1ales de control que ir\u00e1n desde el control path a cada unos de los elementos del data-path (PC,IR, ALU y RAM) y para la recepci\u00f3n de las se\u00f1ales de estado desde el control-path procedentes del data-path. siendo el \u00abpackage\u00bb importado el siguiente Como puede observarse nuestro microprocesador es de 8 bits y tenemos tan solo 3 bits para codificar instrucciones. Vamos a definir \u00fanicamente 5 instrucciones. Top de la jerarqu\u00eda Ahora la descripci\u00f3n del top de la jerarqu\u00eda se ve altamente simplificada. Es sin duda una de las cosas que se pretend\u00eda con el uso de la construcci\u00f3n \u00abinterface\u00bb Elementos del data-path Veamos los elementos del data path PC ALU Este modulo implementa m\u00e1s bien un registro A(o ACC) y un sumador\/restador conectados en modo acumulaci\u00f3n, de forma que se puedan hacer operaciones de sumas y restas sin problemas. IR RAM Este \u00faltimo componente si que tiene algunas caracter\u00edsticas que conviene resaltar: Tenemos una memoria \u00absingle port\u00bb de lectura s\u00edncrona Tenemos dos registros de apoyo, uno (mdr) que registra el dato de entrada y otro (mar) que registra la direcci\u00f3n. Control-path El control path podemos observarlo en el siguiente fichero Como puede observarse es una m\u00e1quina Mealy de 11 estados Procedimiento de verificaci\u00f3n Supongamos que tenemos un programa preparado para comprobar todas las instrucciones desarrolladas. En nuestro caso es un programa para generar n\u00fameros fibonacci. Vamos a explicar con el siguiente v\u00eddeo c\u00f3mo verificar el funcionamiento del microprocesador desarrollado bajo una plataforma FPGA remota.<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_crdt_document":"","ub_ctt_via":"","footnotes":""},"categories":[27,41,5,29],"tags":[25,26,28,23,24],"class_list":["post-559","post","type-post","status-publish","format-standard","hentry","category-diseno","category-jerarquia-diseno","category-verificacion","category-verificacion-fisica","tag-asm","tag-diseno","tag-fsm","tag-interface","tag-ram"],"featured_image_src":null,"author_info":{"display_name":"ralfgad","author_link":"https:\/\/dsd.webs.upv.es\/?author=2"},"_links":{"self":[{"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/posts\/559","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=559"}],"version-history":[{"count":16,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/posts\/559\/revisions"}],"predecessor-version":[{"id":724,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=\/wp\/v2\/posts\/559\/revisions\/724"}],"wp:attachment":[{"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=559"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=559"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dsd.webs.upv.es\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=559"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}