引言

computer(计算机),顾名思义,就是用来compute(计算)的。计算机体系结构在上世纪五六十年代的时候,主要就是研究如何设计运算部件,就是想办法用最少的元器件(那时元器件很贵),最快的速度,完成加减乘除。。。。。。等等这些运算。后来发现运算已经足够快了,快到已经无法提供足够的运算指令和运算的操作数了,人们才开始研究如何给运算部件提供足够的指令和数据,这就产生了cache啊,分支预测啊,流水线啊,等等技术。

本小节,我们就分析一下or1200的运算部件。

1,基础

在上世纪50年代中期以前,计算机(computer),就相当于计算器(calculator)。后来由冯诺依曼在1945年6月30号,对EDVAC计算机分析总结时,提出了采用二进制运算和在计算机中加入存储部件。后来人们把这种结构的计算机就叫冯诺依曼体系结构,运算方式也由原来的十进制改成二进制。由于冯诺依曼是普林斯顿大学的第一批终身教授,人们把冯诺依曼体系结构也叫普林斯顿体系结构。而那份分析报告,就是著名的101报告。关于101报告,其名称是First Draft of a Report on the EDVAC,内容我已上传,请参考:

http://download.csdn.net/detail/rill_zhen/5850885

从EDVAC计算机开始,运算采用二进制,于是就引入了不同的数据表示形式:原码,反码,补码。

原码:

数值前面增加了一位符号位(即最高位为符号位):正数该位为0,负数该位为1(0有两种表示:+0和-0),其余位表示数值的大小。

反码:

正数的反码与其原码相同;负数的反码是对其原码逐位取反,但符号位除外。

补码:

正数的补码,与原码相同。负数的补码,负数的补码等于其绝对值的原码各位取反,然后整个数加1的数值。

2,加法器

1>整体介绍

学过数字电路设计的人可能都知道,加法器是CPU一切运算的基础。

加法器的基本单元是:半加器(half adder),全加器(full adder)。

有这些基本单元可组成很多种不同形式的加法器:行波进位加法器,先行进位加法器,跳跃进位加法器,选择进位加法器,递增进位加法器等。其中先行进位加法器使用最广泛。

关于加法器的概念,真值表,卡诺图,逻辑表达式,表达式的化简,逻辑图,大部分介绍数字电路设计的书里都会有介绍,这里不再赘述,下面我们直接说明这些加法器的RTL描述。

如果您数电基础不是很好,请参考我之前写的一篇文章:http://blog.csdn.net/rill_zhen/article/details/7826689

2>半加器

两个1位二进制数相加,就叫半加。可以进行半加运算的器件,就是半加器。

道理简单,也容易理解,那么我们如何用verilog HDL描述一个半加器呢?如下所示:是一个1-bit的半加器

  1. module ha(sum,c_out,x,y); //half adder
  2. input x,y;
  3. output sum,c_out;
  4. assign {c_out,sum}=x+y;
  5. endmodule // ha

3>全加器

上面说了半加,两个加数都是1-bit,实际情况下,两个加数肯定不止1-bit。两个同位的加数(加数a,加数b)和来自低位的进位(进位c),这三部分相加的运算就叫全加,实现全加运算的电路。就是全加器。

道理也比较简单,那么我们如何用verilog HDL描述一个全加器呢?如下所示:,是一个1-bit的全加器

  1. module fa(sum,c_out,c_in,x,y); //full adder
  2. input x,y,c_in;
  3. output sum,c_out;
  4. assign {c_out,sum}=x+y+c_in;
  5. endmodule

有了半加器和全加器,我们就可以组成各种各样的加法器了。

4>减法器

一般CPU中没有专门的减法器,这是因为用补码表示的数的减法可以转换成加法,如下所示:

[A]补 - [B]补 = [A - B]补 = [A]补 + [ - B]补

所以要想进行减法运算,只要将被减数按位取反,在做加法运算即可。

3,乘法器

1>整体介绍

最老的计算机中的CPU内部是没有乘法器的,如果想要进行乘法运算,先由软件把乘法运算变换成加法运算,然后再交给CPU进行处理,来完成乘法运算。可想而知,那时的CPU的性能是如此之低,后来随着对运算速度的要求,需要硬件实现乘法器。

如何实现乘法器呢?我们最容易想到的就是把乘法变成多次加法运算,最终实现乘法。

比如,我们想计算123x456,怎么算呢?

很简单,我们把123加456次就可以了。电路简单可靠。没错,是简单可靠,但是不同的数相乘需要的时间也不同,如果我们要计算0xffff_ffff * 0xffff_ffff,每次加法需要1个cycle的话,那就得需要0xffff_ffff个cycle啊。显然不可行,怎么办呢?现在的乘法器,只需要一个cycle就能计算完毕,到底是怎么实现的呢?冰冻三尺非一日之寒,不是突然就做到的,有一个很长的过程。但是在这个过程中有两个里程碑式的进展不得不提,第一,booth算法,第二,wallace tree。

2>booth算法

booth算法是booth两口子在1950年提出来的,最开始是1-bit的booth算法,后来这对夫妻又通力合作,把2-bitbooth算法也弄出来了,现在测CPU中大量使用2-bit的booth算法。

booth算法的核心作用就是将两个多位数的乘积,变成多个部分乘积的相加,关于booth细节,我把这两口子当年写的文章也上传了,如果有兴趣,可参考:

http://download.csdn.net/detail/rill_zhen/5851245

关于booth算法的细节,可参考相关的文献,这里不再赘述。但是booth算法的verilogHDL的实现,则必须要说,如下所示,下面是4位数相乘的booth算法的实现:

  1. module booth_encoder(mr,md,x,z);
  2. input[3:0] mr,md;
  3. output [3:0] x,z;
  4. //reg [3:0] mr,md;
  5. reg [3:0] x,z;
  6. reg [1:0] i;
  7. always@(mr or md)
  8. begin
  9.  
  10. x[0]=md[0];
  11. z[0]=md[0];
  12. x[1]=md[1]&~md[0];
  13. z[1]=md[1]^md[0];
  14. x[2]=md[2]&~md[1];
  15. z[2]=md[2]^md[1];
  16. x[3]=md[3]&~md[2];
  17. z[3]=md[3]^md[2];
  18. end
  19. endmodule // booth_encoder

3>wallace tree

乘法运算,经过booth算法处理,变成了多个数的相加,这显然还是不能满足性能要求,于是wallace这个兄弟出现了。

wallace是澳大利亚人,全名叫charis wallace,wallace 树是他在1964年提出的,之所以叫华莱士树就是因为采用wallace算法的电路外形像一棵树。华莱士树的核心思想是将多个数的相加变成两个数的相加。这样,乘法运算就大功告成了,两个数的乘法运算经booth夫妇和wallace三个人的努力变成了两个数的相加,实现了只需要一个cycle就能完成乘法运算。关于华莱士树,请参考:http://en.wikipedia.org/wiki/Wallace_tree  ,这里不再赘述,那么如何用verilog HDL实现华莱士树呢,如下所示,下面是4-bit数相乘(注,经booth处理之后为8-bit)的华莱士树实现:

  1. module wallace(r0,r1,r2,r3,result);
  2. input[7:0] r0,r1,r2,r3;
  3. output [7:0] result;
  4. wire [7:0] result;
  5.  
  6. wire w1,w2,w3,w4,w5,w6,w7,w8,w9,w10,w11,w12,w13,w14,w15,w16,w17,w18,w19;
  7. wire o1,o2,o3,o4,o5,o6,o7,o8,o9,o10,o11;
  8. wire tmp;
  9. //level 1
  10. ha ha1(o1,w1,r1[2],r2[2]);
  11. fa fa2(o2,w2,r2[3],r3[3],r1[3]);
  12. fa fa3(o3,w3,r1[4],r2[4],r3[4]);
  13. fa fa4(o4,w4,r1[5],r2[5],r3[5]);
  14. fa fa5(o5,w5,r1[6],r2[6],r3[6]);
  15. fa fa17(o10,w16,r0[7],r1[7],r2[7]);
  16.  
  17. //level 2
  18. ha ha6(o6,w6,o2,r0[3]);
  19. fa fa7(o7,w7,w2,o3,r0[4]);
  20. fa fa8(o8,w8,w3,o4,r0[5]);
  21. fa fa9(o9,w9,w4,o5,r0[6]);
  22. fa fa18(o11,w17,w5,o10,r3[7]);
  23.  
  24. //fast CL A
  25. not not1(w19,r0[0]);
  26. not not2(result[0],w19);
  27.  
  28. ha ha10(result[1],w10,r0[1],r1[1]);
  29. fa fa11(result[2],w11,w10,r0[2],o1);
  30. fa fa12(result[3],w12,w11,w1,o6);
  31. fa fa13(result[4],w13,w12,w6,o7);
  32. fa fa14(result[5],w14,w13,w7,o8);
  33. fa fa15(result[6],w15,w14,w8,o9);
  34. fa fa16(result[7],w18,w15,w9,o11);
  35. endmodule

4,乘法器的verilog HDL实现与仿真

1>模块划分

经过前面的努力,我们是时候做一个完整的测试了。booth算法和wallace树到底灵不灵,管不管用呢?下面我们就以两个4-bit数的相乘来测试一下。

我们将整个工程分为下面几个模块:

a,半加器:ha

b,全加器:fa

c,部分积模块:partial

d,booth算法模块:booth_encoder

e,wallace树模块:wallace

f,总模块:mul_test1

g,测试激励:tb

2>电路实现

下面是4-bit乘法器的电路图,可以看出,整个乘法器只用了18个加法器(15个全加器,3个半加器)。

3>RTL实现

共七个模块,由于代码都比较简单,就没必要每个模块弄一个文件,所以,我们分成两个文件:multiply.v和tb.v。第一个文件放工作模块,第二个文件放testbench。

文件如下:

multiply.v:

  1. /*
  2. *
  3. * rill_zhen created 2013-08-01
  4. * rillzhen@gmail.com
  5. *
  6. */
  7.  
  8. module ha(sum,c_out,x,y); //half adder
  9. input x,y;
  10. output sum,c_out;
  11. assign {c_out,sum}=x+y;
  12. endmodule // ha
  13.  
  14. module fa(sum,c_out,c_in,x,y); //full adder
  15. input x,y,c_in;
  16. output sum,c_out;
  17. assign {c_out,sum}=x+y+c_in;
  18. endmodule
  19.  
  20. module partial(x,z,r0,r1,r2,r3,md,mr);
  21. input[3:0] x,z;
  22. input[3:0] mr,md;
  23. output [7:0] r0,r1,r2,r3;
  24. reg [7:0] r0,r1,r2,r3;
  25. reg [3:0] comp;
  26. reg [7:0] tmp;
  27.  
  28. always@(x or z or mr or md)
  29. begin
  30. comp=~mr+1;
  31. tmp=comp<<1;
  32. //r0
  33. if (~(x[0]|z[0]))
  34. r0=0;
  35. else if (~x[0]&z[0])
  36. begin
  37. if(mr[3]) r0=mr|8'b11110000;
  38. else r0=mr;
  39. end
  40. else if (x[0]&z[0])
  41. begin
  42. if(comp[3]) r0=comp|8'b11110000;
  43. else r0=comp;
  44. end
  45. //r1
  46. if (~(x[1]|z[1]))
  47. r1=0;
  48. else if (~x[1]&z[1])
  49. begin
  50. if(mr[3]) r1=(mr|8'b11110000)<<1;
  51. else r1=mr<<1;
  52. end
  53. else if (x[1]&z[1])
  54. begin
  55. if(comp[3]) r1=(comp|8'b11110000)<<1;
  56. else r1=comp<<1;
  57. end
  58. //r2
  59. if (~(x[2]|z[2]))
  60. r2=0;
  61. else if (~x[2]&z[2])
  62. begin
  63. if(mr[3]==1) r2=(mr|8'b11110000)<<2;
  64. else r2=mr<<2;
  65. end
  66. else if (x[2]&z[2])
  67. begin
  68. if(comp[3]) r2=(comp|8'b11110000)<<2;
  69. else r2=comp<<2;
  70. end
  71.  
  72. //r3
  73. if (~(x[3]|z[3]))
  74. r3=0;
  75. else if (~x[3]&z[3])
  76. begin
  77. if(mr[3]) r3=(mr|8'b11110000)<<3;
  78. else r3=mr<<3;
  79. end
  80. else if (x[3]&z[3])
  81. begin
  82. if(comp[3]) r3=(comp|8'b11110000)<<3;
  83. else r3=comp<<3;
  84. end
  85. end
  86. endmodule// Verilog HDL for "ee103", "partial_generator" "functional"
  87.  
  88. module booth_encoder(mr,md,x,z);
  89. input[3:0] mr,md;
  90. output [3:0] x,z;
  91. //reg [3:0] mr,md;
  92. reg [3:0] x,z;
  93. reg [1:0] i;
  94. always@(mr or md)
  95. begin
  96.  
  97. x[0]=md[0];
  98. z[0]=md[0];
  99. x[1]=md[1]&~md[0];
  100. z[1]=md[1]^md[0];
  101. x[2]=md[2]&~md[1];
  102. z[2]=md[2]^md[1];
  103. x[3]=md[3]&~md[2];
  104. z[3]=md[3]^md[2];
  105. end
  106. endmodule // booth_encoder
  107. // Verilog HDL for "ee103", "wallace" "functional"
  108.  
  109. module wallace(r0,r1,r2,r3,result);
  110. input[7:0] r0,r1,r2,r3;
  111. output [7:0] result;
  112. wire [7:0] result;
  113.  
  114. wire w1,w2,w3,w4,w5,w6,w7,w8,w9,w10,w11,w12,w13,w14,w15,w16,w17,w18,w19;
  115. wire o1,o2,o3,o4,o5,o6,o7,o8,o9,o10,o11;
  116. wire tmp;
  117. //level 1
  118. ha ha1(o1,w1,r1[2],r2[2]);
  119. fa fa2(o2,w2,r2[3],r3[3],r1[3]);
  120. fa fa3(o3,w3,r1[4],r2[4],r3[4]);
  121. fa fa4(o4,w4,r1[5],r2[5],r3[5]);
  122. fa fa5(o5,w5,r1[6],r2[6],r3[6]);
  123. fa fa17(o10,w16,r0[7],r1[7],r2[7]);
  124.  
  125. //level 2
  126. ha ha6(o6,w6,o2,r0[3]);
  127. fa fa7(o7,w7,w2,o3,r0[4]);
  128. fa fa8(o8,w8,w3,o4,r0[5]);
  129. fa fa9(o9,w9,w4,o5,r0[6]);
  130. fa fa18(o11,w17,w5,o10,r3[7]);
  131.  
  132. //fast CL A
  133. not not1(w19,r0[0]);
  134. not not2(result[0],w19);
  135.  
  136. ha ha10(result[1],w10,r0[1],r1[1]);
  137. fa fa11(result[2],w11,w10,r0[2],o1);
  138. fa fa12(result[3],w12,w11,w1,o6);
  139. fa fa13(result[4],w13,w12,w6,o7);
  140. fa fa14(result[5],w14,w13,w7,o8);
  141. fa fa15(result[6],w15,w14,w8,o9);
  142. fa fa16(result[7],w18,w15,w9,o11);
  143. endmodule
  144.  
  145. //`timescale 1ns/10ps
  146. module mul_test1(result,mr,md);
  147. input[3:0] mr,md;
  148. output [7:0] result;
  149. wire [3:0] x,z;
  150. wire [7:0] r0,r1,r2,r3;
  151. booth_encoder booth(mr,md,x,z);
  152. partial pp(x,z,r0,r1,r2,r3,md,mr);
  153. wallace tree(r0,r1,r2,r3,result);
  154. //$monitor("mr=%b,md=%b,result=%d",mr,md,result);
  155. endmodule

tb.v:

  1. /*
  2. *
  3. * rill created 01/08/2013
  4. *
  5. */
  6. `timescale 1ns / 1ns
  7. module tb;
  8.  
  9. reg [3:0] mr = 0;
  10. reg [3:0] md = 0;
  11. wire [7:0] result;
  12.  
  13. integer loop1 = 0;
  14. integer loop2 = 0;
  15.  
  16. mul_test1 mul_test10
  17. (
  18. .result (result),
  19. .mr (mr),
  20. .md (md)
  21. );
  22.  
  23. initial
  24. begin
  25. #0
  26. mr = 4'd0;
  27. md = 4'd0;
  28.  
  29. #10
  30.  
  31. for (loop1=0;loop1<=4'b1111;loop1=loop1+1)
  32. begin
  33. for (loop2=0;loop2<=4'b1111;loop2=loop2+1)
  34. begin
  35. #10
  36. mr = loop1;
  37. md = loop2;
  38. $display("sn:0x%x-->mr:0x%x,md:0x%x,result=0x%x",loop1*loop2,mr,md,result);
  39. end
  40. end
  41.  
  42. #100 $stop;
  43. end
  44.  
  45. endmodule
  46.  
  47. /************* EOF *************/

4>仿真

用modelsim对这个工程进行仿真,波形如下所示,从中我们可以看出,乘法运算是正确的。0x3 * 0x7 = 0x15。

5,除法器

除法器的verilog HDL实现,我在很早以前就曾写过一篇相关的文章,请参考:http://blog.csdn.net/rill_zhen/article/details/7961937

6,or1200的运算部件实现分析

前面我们了解了加法器,乘法器,除法器的实现,在来分析or1200的实现就容易一点了。

1>整体分析

or1200的运算模块统一由ALU单元管理,如果是简单的运算(或,异或,移位,位扩展)等有ALU自己计算输出结果,如果是乘除运算,有单独的mult_mac模块计算完成后,将结果送给ALU,然后ALU统一将结果输出到下一级流水线。

由于or1200只有一个运算单元(向量机是多个),所以要把所有要进行运算的模块选择其中的一个,所以就需要一个mux,就是operandmux模块,对应or1200_openrandmuxes.v文件。

多路选择器的核心代码如下所示:

  1. //
  2. // Operand A register
  3. //
  4. always @(posedge clk or `OR1200_RST_EVENT rst) begin
  5. if (rst == `OR1200_RST_VALUE) begin
  6. operand_a <= 32'd0;
  7. saved_a <= 1'b0;
  8. end else if (!ex_freeze && id_freeze && !saved_a) begin
  9. operand_a <= muxed_a;
  10. saved_a <= 1'b1;
  11. end else if (!ex_freeze && !saved_a) begin
  12. operand_a <= muxed_a;
  13. end else if (!ex_freeze && !id_freeze)
  14. saved_a <= 1'b0;
  15. end
  16.  
  17. //
  18. // Operand B register
  19. //
  20. always @(posedge clk or `OR1200_RST_EVENT rst) begin
  21. if (rst == `OR1200_RST_VALUE) begin
  22. operand_b <= 32'd0;
  23. saved_b <= 1'b0;
  24. end else if (!ex_freeze && id_freeze && !saved_b) begin
  25. operand_b <= muxed_b;
  26. saved_b <= 1'b1;
  27. end else if (!ex_freeze && !saved_b) begin
  28. operand_b <= muxed_b;
  29. end else if (!ex_freeze && !id_freeze)
  30. saved_b <= 1'b0;
  31. end
  32.  
  33. //
  34. // Forwarding logic for operand A register
  35. //
  36. always @(ex_forw or wb_forw or rf_dataa or sel_a) begin
  37. `ifdef OR1200_ADDITIONAL_SYNOPSYS_DIRECTIVES
  38. casez (sel_a) // synopsys parallel_case infer_mux
  39. `else
  40. casez (sel_a) // synopsys parallel_case
  41. `endif
  42. `OR1200_SEL_EX_FORW:
  43. muxed_a = ex_forw;
  44. `OR1200_SEL_WB_FORW:
  45. muxed_a = wb_forw;
  46. default:
  47. muxed_a = rf_dataa;
  48. endcase
  49. end
  50.  
  51. //
  52. // Forwarding logic for operand B register
  53. //
  54. always @(simm or ex_forw or wb_forw or rf_datab or sel_b) begin
  55. `ifdef OR1200_ADDITIONAL_SYNOPSYS_DIRECTIVES
  56. casez (sel_b) // synopsys parallel_case infer_mux
  57. `else
  58. casez (sel_b) // synopsys parallel_case
  59. `endif
  60. `OR1200_SEL_IMM:
  61. muxed_b = simm;
  62. `OR1200_SEL_EX_FORW:
  63. muxed_b = ex_forw;
  64. `OR1200_SEL_WB_FORW:
  65. muxed_b = wb_forw;
  66. default:
  67. muxed_b = rf_datab;
  68. endcase
  69. end

2>ALU模块代码分析

1》整体分析

下面是ALU模块的核心代码:

  1. //
  2. // Central part of the ALU
  3. //
  4. always @(alu_op or alu_op2 or a or b or result_sum or result_and or macrc_op
  5. or shifted_rotated or mult_mac_result or flag or result_cust5 or carry
  6. `ifdef OR1200_IMPL_ALU_EXT
  7. or extended
  8. `endif
  9. ) begin
  10. `ifdef OR1200_CASE_DEFAULT
  11. casez (alu_op) // synopsys parallel_case
  12. `else
  13. casez (alu_op) // synopsys full_case parallel_case
  14. `endif
  15. `ifdef OR1200_IMPL_ALU_FFL1
  16. `OR1200_ALUOP_FFL1: begin
  17. `ifdef OR1200_CASE_DEFAULT
  18. casez (alu_op2) // synopsys parallel_case
  19. `else
  20. casez (alu_op2) // synopsys full_case parallel_case
  21. `endif
  22. 0: begin // FF1
  23. result = a[0] ? 1 : a[1] ? 2 : a[2] ? 3 : a[3] ? 4 : a[4] ? 5 : a[5] ? 6 : a[6] ? 7 : a[7] ? 8 : a[8] ? 9 : a[9] ? 10 : a[10] ? 11 : a[11] ? 12 : a[12] ? 13 : a[13] ? 14 : a[14] ? 15 : a[15] ? 16 : a[16] ? 17 : a[17] ? 18 : a[18] ? 19 : a[19] ? 20 : a[20] ? 21 : a[21] ? 22 : a[22] ? 23 : a[23] ? 24 : a[24] ? 25 : a[25] ? 26 : a[26] ? 27 : a[27] ? 28 : a[28] ? 29 : a[29] ? 30 : a[30] ? 31 : a[31] ? 32 : 0;
  24. end
  25. default: begin // FL1
  26. result = a[31] ? 32 : a[30] ? 31 : a[29] ? 30 : a[28] ? 29 : a[27] ? 28 : a[26] ? 27 : a[25] ? 26 : a[24] ? 25 : a[23] ? 24 : a[22] ? 23 : a[21] ? 22 : a[20] ? 21 : a[19] ? 20 : a[18] ? 19 : a[17] ? 18 : a[16] ? 17 : a[15] ? 16 : a[14] ? 15 : a[13] ? 14 : a[12] ? 13 : a[11] ? 12 : a[10] ? 11 : a[9] ? 10 : a[8] ? 9 : a[7] ? 8 : a[6] ? 7 : a[5] ? 6 : a[4] ? 5 : a[3] ? 4 : a[2] ? 3 : a[1] ? 2 : a[0] ? 1 : 0 ;
  27. end
  28. endcase // casez (alu_op2)
  29. end // case: `OR1200_ALUOP_FFL1
  30. `endif // `ifdef OR1200_IMPL_ALU_FFL1
  31. `ifdef OR1200_IMPL_ALU_CUST5
  32.  
  33. `OR1200_ALUOP_CUST5 : begin
  34. result = result_cust5;
  35. end
  36. `endif
  37. `OR1200_ALUOP_SHROT : begin
  38. result = shifted_rotated;
  39. end
  40. `ifdef OR1200_IMPL_ADDC
  41. `OR1200_ALUOP_ADDC,
  42. `endif
  43. `ifdef OR1200_IMPL_SUB
  44. `OR1200_ALUOP_SUB,
  45. `endif
  46. `OR1200_ALUOP_ADD : begin
  47. result = result_sum;
  48. end
  49. `OR1200_ALUOP_XOR : begin
  50. result = a ^ b;
  51. end
  52. `OR1200_ALUOP_OR : begin
  53. result = a | b;
  54. end
  55. `ifdef OR1200_IMPL_ALU_EXT
  56. `OR1200_ALUOP_EXTHB : begin
  57. result = extended;
  58. end
  59. `OR1200_ALUOP_EXTW : begin
  60. result = extended;
  61. end
  62. `endif
  63. `OR1200_ALUOP_MOVHI : begin
  64. if (macrc_op) begin
  65. result = mult_mac_result;
  66. end
  67. else begin
  68. result = b << 16;
  69. end
  70. end
  71. `ifdef OR1200_MULT_IMPLEMENTED
  72. `ifdef OR1200_DIV_IMPLEMENTED
  73. `OR1200_ALUOP_DIV,
  74. `OR1200_ALUOP_DIVU,
  75. `endif
  76. `OR1200_ALUOP_MUL,
  77. `OR1200_ALUOP_MULU : begin
  78. result = mult_mac_result;
  79. end
  80. `endif
  81. `OR1200_ALUOP_CMOV: begin
  82. result = flag ? a : b;
  83. end
  84.  
  85. `ifdef OR1200_CASE_DEFAULT
  86. default: begin
  87. `else
  88. `OR1200_ALUOP_COMP, `OR1200_ALUOP_AND: begin
  89. `endif
  90. result=result_and;
  91. end
  92. endcase
  93. end

2》各种运算的具体实现

从上面代码中我们可以看出or1200的异或,或运算都是直接使用的运算符,寻找第一个为1的位。

or1200的加法实现:

  1. assign {cy_sum, result_sum} = (a + b_mux) + carry_in;
  2. // Numbers either both +ve and bit 31 of result set
  3. assign ov_sum = ((!a[width-1] & !b_mux[width-1]) & result_sum[width-1]) |
  4. // or both -ve and bit 31 of result clear
  5. ((a[width-1] & b_mux[width-1]) & !result_sum[width-1]);

or1200的与运算实现:

  1. assign result_and = a & b;

or1200的位扩展运算实现:

  1. always @(alu_op or alu_op2 or a) begin
  2. casez (alu_op2)
  3. `OR1200_EXTHBOP_HS : extended = {{16{a[15]}},a[15:0]};
  4. `OR1200_EXTHBOP_BS : extended = {{24{a[7]}},a[7:0]};
  5. `OR1200_EXTHBOP_HZ : extended = {16'd0,a[15:0]};
  6. `OR1200_EXTHBOP_BZ : extended = {24'd0,a[7:0]};
  7. default: extended = a; // Used for l.extw instructions
  8. endcase // casez (alu_op2)
  9. end

or1200的循环移位运算实现:

  1. //
  2. // Shifts and rotation
  3. //
  4. always @(alu_op2 or a or b) begin
  5. case (alu_op2) // synopsys parallel_case
  6. `OR1200_SHROTOP_SLL :
  7. shifted_rotated = (a << b[4:0]);
  8. `OR1200_SHROTOP_SRL :
  9. shifted_rotated = (a >> b[4:0]);
  10.  
  11. `ifdef OR1200_IMPL_ALU_ROTATE
  12. `OR1200_SHROTOP_ROR :
  13. shifted_rotated = (a << (6'd32-{1'b0,b[4:0]})) |
  14. (a >> b[4:0]);
  15. `endif
  16. default:
  17. shifted_rotated = ({32{a[31]}} <<
  18. (6'd32-{1'b0, b[4:0]})) |
  19. a >> b[4:0];
  20. endcase
  21. end

or1200的位清零和置一实现:

  1. // Examples for move byte, set bit and clear bit
  2. //
  3. always @(cust5_op or cust5_limm or a or b) begin
  4. casez (cust5_op) // synopsys parallel_case
  5. 5'h1 : begin
  6. casez (cust5_limm[1:0])
  7. 2'h0: result_cust5 = {a[31:8], b[7:0]};
  8. 2'h1: result_cust5 = {a[31:16], b[7:0], a[7:0]};
  9. 2'h2: result_cust5 = {a[31:24], b[7:0], a[15:0]};
  10. 2'h3: result_cust5 = {b[7:0], a[23:0]};
  11. endcase
  12. end
  13. 5'h2 :
  14. result_cust5 = a | (1 << cust5_limm);
  15. 5'h3 :
  16. result_cust5 = a & (32'hffffffff ^ (1 << cust5_limm));
  17. //
  18. // *** Put here new l.cust5 custom instructions ***
  19. //
  20. default: begin
  21. result_cust5 = a;
  22. end
  23. endcase
  24. end // always @ (cust5_op or cust5_limm or a or b)

or1200的乘除运算实现:

上面说过,or1200的乘除运算有专门的模块来实现,叫or1200_mult_mac,对应or1200_mult_mac.v文件。

需要说明的是,这个模块提供了两种实现方式一种是前面我们介绍的利用booth算法,wallace树实现的,另外一种就是直接用的verilog的运算符‘*’和‘/’。

具体采用哪一个,通过编译开关OR1200_ASIC_MULTP2_32X32来控制,这个变量在or1200_define.v中有定义,如下所示,从中可以看出目前ORPSoC采用的是用运算符实现的。

  1. //
  2. // Select between ASIC optimized and generic multiplier
  3. //
  4. //`define OR1200_ASIC_MULTP2_32X32
  5. `define OR1200_GENERIC_MULTP2_32X32

r1200_mult_mac.v中根据定义,选择是采用booth算法还是使用运算符。

  1. //
  2. // Instantiation of the multiplier
  3. //
  4. `ifdef OR1200_ASIC_MULTP2_32X32
  5. or1200_amultp2_32x32 or1200_amultp2_32x32(
  6. .X(x),
  7. .Y(y),
  8. .RST(rst),
  9. .CLK(clk),
  10. .P(mul_prod)
  11. );
  12. `else // OR1200_ASIC_MULTP2_32X32
  13. or1200_gmultp2_32x32 or1200_gmultp2_32x32(
  14. .X(x),
  15. .Y(y),
  16. .RST(rst),
  17. .CLK(clk),
  18. .P(mul_prod)
  19. );
  20. `endif // OR1200_ASIC_MULTP2_32X32

采用booth,wallace算法的实现对应的文件是:or1200_amultp2_32x32.v,代码全是开关级建模,一般人是看不懂的,但是我们已将了解了具体的算法,所以看不懂没关系。

采用运算符的话,就简单多了,直接写个符号,然后交给综合器生成对应的电路,对应文件是:or1200_gmultp2_32x32.v,代码如下:

  1. `ifdef OR1200_GENERIC_MULTP2_32X32
  2.  
  3. `define OR1200_W 32
  4. `define OR1200_WW 64
  5.  
  6. module or1200_gmultp2_32x32 ( X, Y, CLK, RST, P );
  7.  
  8. input [`OR1200_W-1:0] X;
  9. input [`OR1200_W-1:0] Y;
  10. input CLK;
  11. input RST;
  12. output [`OR1200_WW-1:0] P;
  13.  
  14. reg [`OR1200_WW-1:0] p0;
  15. reg [`OR1200_WW-1:0] p1;
  16. integer xi;
  17. integer yi;
  18.  
  19. //
  20. // Conversion unsigned to signed
  21. //
  22. always @(X)
  23. xi = X;
  24.  
  25. //
  26. // Conversion unsigned to signed
  27. //
  28. always @(Y)
  29. yi = Y;
  30.  
  31. //
  32. // First multiply stage
  33. //
  34. always @(posedge CLK or `OR1200_RST_EVENT RST)
  35. if (RST == `OR1200_RST_VALUE)
  36. p0 <= `OR1200_WW'b0;
  37. else
  38. p0 <= xi * yi;
  39.  
  40. //
  41. // Second multiply stage
  42. //
  43. always @(posedge CLK or `OR1200_RST_EVENT RST)
  44. if (RST == `OR1200_RST_VALUE)
  45. p1 <= `OR1200_WW'b0;
  46. else
  47. p1 <= p0;
  48.  
  49. assign P = p1;
  50.  
  51. endmodule
  52.  
  53. `endif

7,小结

本小节我们了解了加法器,乘法器,除法器的一般实现算法,还用一个4-bit的乘法器做了仿真验证,最后对or1200的具体实现进行了分析。

OpenRisc-42-or1200的ALU模块分析的更多相关文章

  1. OpenRisc-43-or1200的IF模块分析

    引言 “喂饱饥饿的CPU”,是计算机体系结构设计者时刻要考虑的问题.要解决这个问题,方法大体可分为两部分,第一就是利用principle of locality而引进的cache技术,缩短取指时间,第 ...

  2. OpenRisc-47-or1200的WB模块分析

    引言 “善妖善老,善始善终”,说的是无论什么事情要从有头有尾,别三分钟热度. 对于or1200的流水线来说,MA阶段是最后一个阶段,也是整条流水线的收尾阶段,负责战场的清扫工作.比如,把运算指令的运算 ...

  3. OpenRisc-41-or1200的cache模块分析

    引言 为CPU提供足够的,稳定的指令流和数据流是计算机体系结构设计中两个永恒的话题.为了给CPU提供指令流,需要设计分支预测机构,为了给CPU提供数据流,就需要设计cache了.其实,无论是insn还 ...

  4. OpenRisc-45-or1200的ID模块分析

    引言 之前,我们分析了or1200流水线的整体结构,也分析了流水线中IF级,EX级,本小节我们来分析ID(insn decode)级的一些细节. 1,基础 or1200的pipeline的ID阶段包含 ...

  5. OpenRisc-40-or1200的MMU模块分析

    引言 MMU(memory management unit),无论对于computer architecture designer还是OS designer,都是至关重要的部分,设计和使用的好坏,对性 ...

  6. OpenRisc-48-or1200的SPRS模块分析

    引言 之前,我们在分析or1200的WB模块时(http://blog.csdn.net/rill_zhen/article/details/10220619),介绍了OpenRISC的GPRS(ge ...

  7. nginx事件模块分析(一)

    nginx ngx_events_module模块分析 ngx_events_module模块是核心模块之一,它是其它所有事件模块的代理模块.nginx在启动时只与events模块打交道,而由even ...

  8. 游戏模块分析总结(2)之UI、操作篇

    转自:http://www.gameres.com/309812.html 游戏模块分析总结(2)之UI.操作篇 发布者: wuye | 发布时间: 2014-12-12 15:03| 评论数: 0 ...

  9. css扁平化博客学习总结(一)模块分析

    一.模块分析 1.每开发一个项目之前,首先要对项目进行一个大致规划,它到底要做什么功能,它有什么具体需求. 2.所以需要进行模块化分析,把这些东西具象化,把一个问题模块化,对需求有一个宏观的了解. 3 ...

随机推荐

  1. EF+WCF怎样更新数据?

    public virtual void Update(T entity) { T current = this.Where(m => m.Id.Equals(entity.Id)) .Singl ...

  2. Linux(Fedora)下NodeJs升级最新版本(制定版本)

    Linux(Fedora)下NodeJs升级最新版本(制定版本) 首先安装n模块: npm install -g n 升级node.js到最新稳定版 n stable 升级node.js到制定版本 n ...

  3. Faces.JavaServer Pages(JSP)

    zhengly.cn atitit.Servlet2.5 Servlet 3.0 新特性 jsp2.0 jsp2.1 jsp2.2新特性 1.1. Servlet和JSP规范版本对应关系:1 1.2. ...

  4. 帝国cms 列表页分页样式修改美化【2】

    上一篇(帝国cms 列表页分页样式修改美化[1])中我们已经对分页说了一个大概,下面我们就自己动手弄一个分页把: 第一步:进入帝国cms后台,点击系统设置->系统参数设置->信息设置:里面 ...

  5. execute、executeUpdate、executeQuery三者的区别及返回值

    一.boolean execute(String sql)允许执行查询语句.更新语句.DDL语句.返回值为true时,表示执行的是查询语句,可以通过getResultSet方法获取结果:返回值为fal ...

  6. ubuntu14.04下 Android虚拟机 genymotion 的下载和安装

    官网:https://www.genymotion.com/ Install Guide https://www.genymotion.com/#!/developers/user-guide#ins ...

  7. 结合rpyc使用python实现动态升级的方法

    动态升级,就是程序不退出的情况下,将其代码更新的策略.假设集群含有多个机器,然后每个机器部署一套程序,当升级的时候就要去所有的上面部署一把. (1)有个包装程序专门负责接口并检查是否需要更新,当需要更 ...

  8. 简单学C——第二天

                 控制结构(-) 相信大家对流程图肯定很熟悉.下面我将介绍的正是关于此方面的,c语言中,控制结构大体分为选择结构和循环结构. 一.选择结构:     先贴出一般用于选择结构的语 ...

  9. html5 中的 css样式单 的 两种调用方式的区别

    在 html5 中 使用 css 样式单的方式 有4种: 1.链接外部样式文件:将样式文件 彻底与 html 文档分离,样式文件需要额外引入,这种情况下 一批样式 可以控制多份文档.对于好多文件都共有 ...

  10. scrollview 例子2

    代码: #import "RootViewController.h" @implementation RootViewController @synthesize scrollVi ...