利用Perl脚本实现的一个简单汇编器

该脚本针对MIPS指令集,支持如下10条指令(可扩展):

add、sub、and、or、slt、lw、sw、addi、beq、j

测试程序如下:

main: addi $2, $0, 5
addi $3, $0, 12
addi $7, $3, -9
or $4, $7, $2
and $5, $3, $4
add $5, $5, $4
beq $5, $7, end
slt $4, $3, $4
beq $4, $0, around
addi $5, $0, 0
around: slt $4, $7, $2
add $7, $4, $5
sub $7, $7, $2
sw $7, 68($3)
lw $2, 80($0)
j end
addi $2, $0, 1
end: sw $2, 84($0)

转换后的机器码如下(十六进制):

20020005
2003000c
2067fff7
00e22025
00642824
00a42820
10a7000a
0064202a
10800001
20050000
00e2202a
00853820
00e23822
ac670044
8c020050
08000011
20020001
ac020054

附Perl脚本:assembler.rar

#!/usr/bin/perl

open FileIN,"$ARGV[0]";

chomp($_=$ARGV[0]);

/(.*)\.asm/;

open FileOUT,">$1.o";

$instr_addr=0;

while($line=<FileIN&gt ;) {

  $_=$line;

  next if(!/[a-zA-Z0-9,\$]+/);

  chomp($_);

  if(/(.*)[ \t]*:.*/){

    $label_addr{$1}=$instr_addr;

  }

  $instr_addr+=4;

}

open FileIN,"$ARGV[0]";

$instr_addr=0;

while($line=<FileIN&gt ;) {

  $_=$line;

  next if(!/[a-zA-Z0-9,\$]+/);

  chomp($_);

  if(/.* :( .*)/){

    $_=$1;

  }

  #for instructions like "XX XX, XX, XX"

  if(/[ \t]*([a-zA-Z]*)[ \t]*(.*)[ \t]*,[ \t]*(.*)[ \t]*,[ \t]*(.*)[ \t]*/) {

    $p1=$1; $p2=$2 ;$p3=$3; $p4=$4;

    $instr_code="";

    if($p1 eq "add") {

      $op=0;

      $p2=~/\$([0-9]*)/; $rd=$1;

      $p3=~/\$([0-9]*)/; $rs=$1;

      $p4=~/\$([0-9]*)/; $rt=$1;

      $instr_code=$op*2**26+$rs*2**21+$rt*2**16+$rd*2**11+32;

      $out_code=&dec2hex($instr_code);

      print FileOUT "$out_code\n";

    }

    if($p1 eq "sub") {

      $op=0;

      $p2=~/\$([0-9]*)/; $rd=$1;

      $p3=~/\$([0-9]*)/; $rs=$1;

      $p4=~/\$([0-9]*)/; $rt=$1;

      $instr_code=$op*2**26+$rs*2**21+$rt*2**16+$rd*2**11+34;

      $out_code=&dec2hex($instr_code);

      print FileOUT "$out_code\n";

    }

    if($p1 eq "and") {

      $op=0;

      $p2=~/\$([0-9]*)/; $rd=$1;

      $p3=~/\$([0-9]*)/; $rs=$1;

      $p4=~/\$([0-9]*)/; $rt=$1;

      $instr_code=$op*2**26+$rs*2**21+$rt*2**16+$rd*2**11+36;

      $out_code=&dec2hex($instr_code);

      print FileOUT "$out_code\n";

    }

    if($p1 eq "or") {

      $op=0;

      $p2=~/\$([0-9]*)/; $rd=$1;

      $p3=~/\$([0-9]*)/; $rs=$1;

      $p4=~/\$([0-9]*)/; $rt=$1;

      $instr_code=$op*2**26+$rs*2**21+$rt*2**16+$rd*2**11+37;

      $out_code=&dec2hex($instr_code);

      print FileOUT "$out_code\n";

    }

    if($p1 eq "slt") {

      $op=0;

      $p2=~/\$([0-9]*)/; $rd=$1;

      $p3=~/\$([0-9]*)/; $rs=$1;

      $p4=~/\$([0-9]*)/; $rt=$1;

      $instr_code=$op*2**26+$rs*2**21+$rt*2**16+$rd*2**11+42;

      $out_code=&dec2hex($instr_code);

      print FileOUT "$out_code\n";

    }

    if($p1 eq "addi") {

      $op=8;

      $p2=~/\$([0-9]*)/; $rt=$1;

      $p3=~/\$([0-9]*)/; $rs=$1;

      $addr=$p4;

      if($addr ge 0) {

        $instr_code=$op*2**26+$rs*2**21+$rt*2**16+$addr;

      } else {

        $instr_code=$op*2**26+$rs*2**21+($rt+1)*2**16+$addr;

      }

      $out_code=&dec2hex($instr_code);

      print FileOUT "$out_code\n";

    }

    if($p1 eq "beq") {

      $op=4;

      $p2=~/\$([0-9]*)/; $rs=$1;

      $p3=~/\$([0-9]*)/; $rt=$1;

      $addr=($label_addr{$p4}-$instr_addr-4)/4;

      if($addr ge 0) {

        $instr_code=$op*2**26+$rs*2**21+$rt*2**16+$addr;

      } else {

        $instr_code=$op*2**26+$rs*2**21+($rt+1)*2**16+$addr;

      }

      $out_code=&dec2hex($instr_code);

      print FileOUT "$out_code\n";

    }

  }

  #for instructions like "XX XX, XX(XX)"

  if(/[ \t]*([a-zA-Z]*)[ \t]*(.*)[ \t]*,[ \t]*([0-9]*)\((.*)\)[ \t]*/) {

    $p1=$1; $p2=$2; $p3=$3; $p4=$4;

    if($p1 eq "lw") {

      $op=35;

      $p2=~/\$([0-9]*)/; $rt=$1;

      $p4=~/\$([0-9]*)/; $rs=$1;

      $addr=$p3;

      if($addr ge 0) {

        $instr_code=$op*2**26+$rs*2**21+$rt*2**16+$addr;

      } else {

        $instr_code=$op*2**26+$rs*2**21+($rt+1)*2**16+$addr;

      }

      $out_code=&dec2hex($instr_code);

      print FileOUT "$out_code\n";

    }

    if($p1 eq "sw") {

      $op=43;

      $p2=~/\$([0-9]*)/; $rt=$1;

      $p4=~/\$([0-9]*)/; $rs=$1;

      $addr=$p3;

      if($addr ge 0) {

        $instr_code=$op*2**26+$rs*2**21+$rt*2**16+$addr;

      } else {

        $instr_code=$op*2**26+$rs*2**21+($rt+1)*2**16+$addr;

      }

      $out_code=&dec2hex($instr_code);

      print FileOUT "$out_code\n";

    }

  }

  #for instructions like "XX XX"

  if(/[ \t]*([a-zA-Z]*)[ \t]*(.*)[ \t]*/) {

    $p1=$1; $p2=$2;

    if($p1 eq "j") {

      $op=2;

      $addr=$label_addr{$p2}/4;

      $instr_code=$op*2**26+$addr;

      $out_code=&dec2hex($instr_code);

      print FileOUT "$out_code\n";

    }

  }

 

  $instr_addr+=4;

}

close FileIN;

close FileOUT;

 

sub dec2hex {

  $tmp=sprintf "%x",$_[0];

  $length=length($tmp);

  if($length != 8) {

    $i=8-$length;

    while($i) {

      $tmp="0$tmp";

      $i-=1;

    }

    sprintf "$tmp";

  } else {

    sprintf "%x",$_[0];

  }

}

Posted in 学术相关 | 2 Comments

利用状态机实现时钟产生电路(分频)的Verilog代码示例

利用状态机实现时钟产生电路(分频)的Verilog代码示例


module clk_gen (clk,reset,clk1,clk2,clk4,fetch,alu_clk);

    input clk,reset;

    output clk1,clk2,clk4,fetch,alu_clk;

    wire clk,reset;

    reg clk2,clk4,fetch,alu_clk;

    reg[7:0] state;

    parameter S1 = 8'b00000001,

       S2 = 8'b00000010,

       S3 = 8'b00000100,

       S4 = 8'b00001000,

       S5 = 8'b00010000,

       S6 = 8'b00100000,

       S7 = 8'b01000000,

       S8 = 8'b10000000,

       idle = 8'b00000000;

 

    assign clk1 = ~clk;

 

    always @(negedge clk)

       if(reset)

           begin

           clk2 <= 0;

           clk4 <= 1;

           fetch <= 0;

           alu_clk <= 0;

           state <= idle;

           end

       else

           begin

           case(state)

           S1:

              begin

              clk2 <= ~clk2;

              alu_clk <= ~alu_clk;

              state <= S2;

              end

           S2:

              begin

              clk2 <= ~clk2;

              clk4 <= ~clk4;

              alu_clk <= ~alu_clk;

              state <= S3;

              end

           S3:

              begin

              clk2 <= ~clk2;

              state <= S4;

              end

           S4:

              begin

              clk2 <= ~clk2;

              clk4 <= ~clk4;

              fetch <= ~fetch;

              state <= S5;

              end

           S5:

              begin

              clk2 <= ~clk2;

              state <= S6;

              end

           S6:

              begin

              clk2 <= ~clk2;

              clk4 <= ~clk4;

              state <= S7;

              end

           S7:

              begin

              clk2 <= ~clk2;

              state <= S8;

              end

           S8:

              begin

              clk2 <= ~clk2;

              clk4 <= ~clk4;

              fetch <= ~fetch;

              state <= S1;

              end

           idle: state <= S1;

           default: state <= idle;        

           endcase

           end

endmodule

Posted in 学术相关 | Leave a comment

五级流水线RISC处理器结构图

five-stage pipelined processor with full hazard handling

 支持分支转移和无条件跳转指令,支持冒险检测和数据旁路。

(点击放大)

pipeline diagram

Posted in 学术相关 | 3 Comments

SystemC学习笔记(7):基本通道

如前面介绍的,并发过程之间的通讯可以使用事件和模块成员数据。但是这两种方法的使用需要十分仔细。SystemC提供一种“握手(handshake)”变量来实现过程间的通讯,称作通道(channel)。通道有primitive和hierarchical两种。Primitive Channel是一种没有包含层次和过程的通道。所有的primitive channel都是从sc_prim_channel基类继承而来。下面介绍最简单的三种primitive channel:sc_mutex、sc_semaphore、sc_fifo。

一、sc_mutex:

Mutex是互斥(mutual exclusion)的简称。Mutex在Elaboration阶段被创建,之后任何要使用该资源的过程都必须lock这个mutex以防止其他过程使用该共享资源。当该资源不再被使用时,过程需要unlock这个mutex。

SystemC通过sc_mutex通道来实现mutex。sc_mutex包含许多访问函数,包括阻塞和非阻塞两种风格。阻塞风格的函数只能在SC_THREAD过程中使用。sc_mutex的语法如下:

sc_mutex NAME;

NAME.lock(); // To lock the mutex NAME (wait until unlocked if in use)
NAME.trylock(); // Non-blocking, returns true if success, else false
NAME.unlock(); // To free a previously locked mutex

在实际的电子设计中,可以用sc_mutex来模拟共享总线的仲裁。当仲裁器设计好后再替换该sc_mutex。

二、sc_semaphore:

和mutex不同,有些资源能够有多个复制或者使用者。SystemC用sc_semaphore来模拟这种资源。其实sc_mutex可以看作是是有一个复制的sc_semaphore。sc_semaphore的语法如下:

sc_semaphore NAME(COUNT);

NAME.wait(); // To lock the mutex NAME (wait until unlocked if in use)
NAME.trylock(); // Non-blocking, returns true if success, else false
NAME.get_value(); // Returns number of available semaphores
NAME.post(); // To free a previously locked mutex

用sc_semaphore模拟多端口存储器的例子如下:

class mutiport_RAM {
  sc_semaphore read_ports(3);
  sc_semaphore write_ports(2);
  ...
  void read(int addr, int& data) {
    read_ports.wait();
    // perform read
    read_ports.post();
  }
  void write(int addr, int data) {
    write_ports.wait();
    // perform write
    write_ports.unlock();
  }
}

三、sc_fifo:

FIFO是用来管理数据流的最常用的数据结构。SystemC提供sc_fifo来实现FIFO。sc_fifo<>在默认情况下的深度是16,另外还需要指定元素的数据类型。sc_fifo的语法如下:

sc_fifo<ELEMENT_TYPENAME> NAME(SIZE);

NAME.write(VALUE);
NAME.read(REFERENCE);
...=NAME.read();
if(NAME.nb_read(REFERENCE)) { // Non-blocking, true if success
  ...
}
if(NAME.num_available()==0)
  wait(NAME.data_written_event());
if(NAME.num_free()==0)
  next_trigger(NAME.data_read_event());

对于复杂数据类型的元素,将指针传给sc_fifo将会更加高效。

Posted in SystemC, 学术相关 | Leave a comment

SystemC学习笔记(6):并发-过程和事件

现实系统中很多活动都是同时发生的。SystemC用过程(Process)来模拟并发性。了解SystemC仿真器如何处理并发性,能使设计者写出高效的仿真模型。SystemC提供两种主要的过程类型:SC_THREAD和SC_METHOD。另外还有第三种,SC_CTHREAD,是SC_THREAD的变型。SystemC官方的Language Reference Manual不推荐在一般情况下使用SC_CTHREAD。

一、事件sc_event:

事件(Event)是SystemC这种事件驱动的仿真器的关键之处。事件就是在某个特定时间点发生的事情。一个时间没有取值,也没有持续时间。事件本身没有并不做任何可以被观察到的事情,它只是激发对它敏感的过程,从而表现出作用。SystemC中的过程通过动态或者静态敏感表来等待一个事件的发生。声明一个事件的语法如下:

sc_event name;

二、过程SC_THREAD:

过程SC_THREAD被且只被仿真器启动一次。SC_THREAD一旦被启动就完全控制仿真过程,直到其自己将控制返回给仿真器。SC_THREAD有两种返回控制给仿真器的方法,一种是简单退出(如return),这意味着永远结束该过程。因此,常常在SC_THREAD中使用含有wait语句的无限循环。

另一种返回控制的方法是使用wait来挂起过程。有时候wait并不是被直接使用的,比如sc_fifo的阻塞读和写在FIFO分别为空或满的时候将隐式的激活wait。

三、SC_THREAD::wait()的动态敏感表(dynamic sensitivity):

SC_THREAD依靠wait来挂起自身。当wait被执行时,当前SC_THREAD过程的状态将被保存,同时仿真内核得到控制权,接着启动另一个准备好的过程。当被挂起的过程重新被启动时,它将从wait后的语句开始执行。wait的语法如下:

wait(time);
wait(event);
wait(event1 | event2);  //  any of these events
wait(event1 & event2);  //  all of these events
wait(timeout, event1 | event2);  //  any of these events with timeout
wait(timeout, event1 & event2);  //  all events with timeout
wait();  //  static sensitivity

带有timeout的wait将timeout值设为最大的等待时间,超过这个时间即使事件没有发生,过程同样也会被重新启动。我们可以在timeout的wait后面用布尔函数time_out()来检测到底是不是timeout使得过程返回,例如:

...
sc_event ack_event, bus_error_event;
...
wait(t_MAX_DELAY, ack_event | bus_error_event);
if(time_out()) break;  //  test for timeout
...

四、启动事件-.notify():

事件通过notify()来显式的发生。notify()有以下两种语法风格,由于C++是面向对象的语言,因此建议使用前一种语法风格:

// Object-oriented style  (preferred)
event_name.notify();  //immediate notification
event_name.notify(SC_ZERO_TIME);  //delayed notification
event_name.notify(time);  //timed notification

// Functional-call style
notify(event_name);  //immediate notification
notify(event_name, SC_ZERO_TIME);  //delayed notification
notify(event_name, time);  //timed notification

上面最难理解的是.notify()和.notify(SC_ZERO_TIME)两种的区别。.notify()会立即使等待该事件的过程转为等待被执行。而.notify(SC_ZERO_TIME)会在当前等待被执行的所有过程完成后,才将等待该事件的过程转为等待被执行(所谓的下一个delta-cycle)。

对于.notify(time)来说,如果有多个notification,那么只有时间最近的那个是有效的。我们可以用.cancel()来取消所有notification。

五、过程SC_METHOD:

SC_METHOD与SC_THREAD的主要不同,是SC_METHOD不能在其内部被挂起,即不能直接或间接的使用wait(),否则会报runtime error的错误。SC_METHOD一旦运行便会运行到底,然后返回。仿真引擎根据动态敏感表不断的调用SC_METHOD。某种程度上,SC_METHOD很像Verilog中的always块。注册SC_METHOD过程的语法如下:

SC_METHOD(process_name);  //Located inside constructor

SC_METHOD中的变量在其每次被调用时都要被声明和初始化。这和SC_THREAD中变量是永远存在的不一样。如果希望保存SC_METHOD中的值,那么就需要使用SC_MODULE中定义的局部变量。

六、SC_METHOD::next_trigger()的动态敏感表:

SC_METHOD过程通过next_trigger()来处理动态敏感表。next_trigger()和wait()有着同样的语法。next_trigger不会阻碍当前SC_METHOD的执行,它会改变下一次调用该SC_METHOD的敏感表。如果没有静态敏感表,那么SC_METHOD的所有执行分支都应当有next_trigger,否则可能导致该SC_METHOD不再被调用。

七、过程的静态敏感表(Static Sensitivity):

前面说的动态敏感表示在仿真阶段的建立的,并且可以在仿真中被改变。静态敏感表是在仿真开始前建立的,在仿真过程中不能被改变。静态敏感表的申明有两种语法:

sensitive<<event[<<event]...;  // streaming style
sensitive(event [, event]...);  //  functional style

同样建议选择类似于C++流的第一种语法风格。静态敏感表的申明必须紧跟在其过程的注册语句后面。

八、dont_initialize:

SystemC的仿真引擎将在开始时初始化执行所有的过程,然后有时候某些过程不需要在一开始就执行。可以在静态敏感表后面加上dont_initialize()来阻止初始化执行。

九、sc_event_queue:

正如前面讲的,sc_event只能被安排一次,如果多个notification只有时间最近的那个会被执行。sc_event_queue使得一个事件能够被安排多次,甚至是在同一个时间点。sc_event_queue的语法和sc_event类似。

Posted in SystemC, 学术相关 | Leave a comment

SystemC学习笔记(5):时间概念

理解SystemC中的时间概念,对于弄清仿真行为有着很大的帮助。

一、sc_time:

SystemC提供称为sc_time的数据来行来衡量时间。时间由长度(magnitude)和单位(unit)表达,语法如下:

sc_time name;  //no initialization
sc_time name(magnitude, unit);

时间单位有以下几种:SC_SEC、SC_MS、SC_US、SC_NS、SC_PS、SC_FS。SystemC允许对sc_time对象进行加、减以及比例缩放等操作。一个特殊的常量SC_ZERO_TIME可以用来表示sc_time(0, SC_SEC)。

二、sc_start():

sc_start()在SystemC中用于启动仿真阶段。可以给sc_start()提供一个时间参数用来指定最大仿真时间,如:

sc_start(60.0, SC_SEC);

三、sc_time_stamp()和显示时间:

在SystemC中可以通过sc_time_stamp()来获得仿真当前时间,例如:

cout<<sc_time_stamp()<<endl;

四、wait(sc_time):

wati()被用在SC_THREAD过程中完成延迟功能。当遇到wait(),SC_THREAD过程被阻止执行,并且在指定的时间返回继续执行,如下面的例子:

void simple_process_ex::my_thread_process(void)  {
  wait(10, SC_NS);
  cout<<"Now at "<<sc_time_stamp()<<endl;
  sc_time t_DELAY(2, SC_MS);
  t_DELAY*=2;
  cout<<"Delaying "<<t_DELAY<<endl;
  wait(t_DELAY);
  cout<<"Now at "<<sc_time_stamp()<<endl;
}

上面例子的运行结果为:

Now at 10 ns
Delaying 4 ms
Now at 4000010 ns

Posted in SystemC, 学术相关 | Leave a comment

SystemC学习笔记(4):模块

模块是 SystemC程序的基础。SystemC程序由各种模块组合而成。

一、SystemC程序的起始点(Start Point):

所有程序都有一个起始点。在C/C++中,这个起始点叫做main,例如:

int main(int argc, char* argv[]) {
  BODY_OF_PROGRAM
  return 0;
}

在SystemC中,这个起始点被叫做sc_main。例如:

int sc_main(int argc, char* argv[]) {
  ElABORATION
  sc_start();  // <-- Simulatioin begins & ends in this function!
  [POST-PROCESSING]
  return 0;
}

在sc_main中包括三个阶段:Elaboration、Simulation和Post-processing。Elaboration阶段描述系统的结构和相互连接关系,包括时钟、设计模块和通道的例化等;Simulation阶段完成整个仿真行为;Post-processing阶段是可选的,取决于设计者是否需要在完成仿真后还要进行其他处理。

二、设计的基本单元-模块(SC_MODULE):

复杂系统都是由许多功能模块组成的,这些模块可大可小,也可以代表硬件、软件或者物理实体。在SystemC中用SC_MODULE来表示这些模块。SC_MODULE的语法如下:

#include <systemc.h>
SC_MODULE(module_name)  {
  MODULE_BODY
};

在systemc.h头文件中,SC_MODULE实际上一个C++宏:

#define SC_MODULE(module_name) \
              struct module_name: public sc_module

MODULE_BODY可以包括以下元素:端口、成员通道的例化、成员数据的例化、成员模块的例化、构造函数、析构函数、成员过程等。在这些元素中,只有构造函数是必须的。

三、SC_MODULE的构造函数-SC_CTOR:

SC_MODULE的构造函数SC_CTOR主要完成以下任务:初始化和分配子设计、连接子设计、注册过程、提供静态敏感表(Static Sensitivity)、其他用户定义的设置。SC_CTOR的语法如下:

SC_CTOR(module_name)
Initialization  //  OPTIONAL
{
  Subdesign_Allocation
  Subdesign_Connectivity
  Process_Registration
  Miscellaneous_Setup
}

四、执行的基本单元-过程(Process):

过程是SystemC的基本执行单元。过程是SC_MODULE的成员函数,其语法如下:

void PROCESS_NAME(void);

SystemC过程没有参数,也没有返回值。在定义完过程后,便需要将该过程注册。最简单的过程是SC_THREAD,它和软件概念上的thread很相似。SC_THREAD只被调用一次便结束,这和Verilog中的initial块很类似。

五、注册最简单的过程-SC_THREAD:

过程的注册是在构造函数SC_CTOR中进行的。注册SC_THREAD过程的语法如下:

SC_THREAD(process_name);  //Must be INSIDE constructor

下面是一个简单的例子:

SC_MODULE(simple_process_ex)  {
  SC_CTOR(simple_process_ex)  {
    SC_THREAD(my_thread_process);
  }
  void my_thread_process(void);
};

六、完成一个简单的设计:

现在我们可以用上面的模块及过程来写一个简单的sc_main设计:

int sc_main(int argc, char* argv[])  {
  simple_process_ex my_instance("my_instance");
  sc_start();
  return 0;
}

在例化my_instance的时候用了"my_instance"做参数,这么做的目的是为了将例化模块的名字存储在其内部,以便在debug时调用sc_module的成员函数name()获取当前例化模块的名称。

七、另一种构造函数-SC_HAS_PROCESS:

如果你希望将例化模块名称以外的参数传给构造函数,或者希望将构造函数的实现放到另一个cpp文件中,那么你就要使用另一种构造函数SC_HAS_PROCESS,其语法如下:

//FILE: module_name.h
SC_MODULE(module_name)  {
  SC_HAS_PROCESS(module_name);
  module_name(sc_module_name instname[, other_args...])
   :sc_module(instname)[, other_initializers]  {
    CONSTRUCTOR_BODY
  }
}

Posted in SystemC, 学术相关 | 1 Comment

SystemC学习笔记(3):数据类型

做为C++的类库,SystemC支持所有的C++内建数据类型,包括int、long int、short int、unsigned int、unsigned long int、unsigned short int、double、float、char、bool,以及C++的string类型。除此之外,SystemC还有自己独有的数据类型。

一、算数数据类型(Arithmetic Data Types):

1、sc_int和sc_uint:对应于C++内建的int和unsigned int,不同点是可以指定数据的位宽(1到64位),使用格式为:

    sc_int<length> name

由于仿真SystemC的数据类型会比仿真C++的数据类型慢,所以在非必要的情况下尽量使用C++内建的数据类型。

2、sc_bigint和sc_biguint:和上面两种数据类型类似,可支持大于64位的数据。

二、布尔及多值数据类型(Boolean and Multi-Value Data Types):

1、sc_bit和sc_bv:用于表示0、1及其序列的数据类型(sc_bv用于表示长度大于1的0、1序列),使用格式为:

    sc_bit name

    sc_bit<bitwidth> name

在SystemC中,SC_LOGIC_1和SC_LOGIC_0是分别表示1和0的数据常量。sc_bit和sc_bv支持与(&)、或(|)、异或(^)操作,以及位选择([])和范围选择操作(range())。

2、sc_logic和sc_lv:和上面两种数据类型类似,不过可以表示1、0、X、Z四种逻辑(SC_LOGIC_X和SC_LOGIC_Z分别表示不确定状态和高阻态)。

三、定点数据类型(Fixed-Point Data Types):

SystemC提供sc_fixed、sc_ufixed、sc_fix、sc_ufix以及它们的_fast后缀变种,来表示定点数据类型。要使用这些数据类型,必须在头文件包含语句#incluede <systemc.h>前面加上#define SC_INCLUDE_FX。它们的使用格式为:

    sc_fixed<WL, IWL> name

WL表示字长度、IWL表示整数字长度,例如:(i:整数位;f:分数位;s:符号位)

    sc_fixed<5, 5>表示    iiiii.

    sc_fixed<5, 3>表示    iii.ff

    sc_fixed<5, 0>表示    .fffff

    sc_fixed<5, 7>表示    iiiii.00

    sc_fixed<5, -2>表示 .ssfffff

fix和fixed的区别是fixed的定点数据类型在编译后便不能再改变。_fast后缀的类型在仿真时更快,因为它们的精度被限制为53位。

四、SystemC数据类型的操作符:

SystemC数据类型提供所有常见的操作符,包括比较操作(==、!=、>、>=、<、<=),算数操作(+、-、*、/、++、--、%),按位操作(~、&、|、^)以及赋值操作(=、&=、|=、^=、*=、/=、%=、+=、-=、<<=、>>=)。

五、注意:

在任何情况下,尽量使用C++内建数据类型以提高仿真速度。

Posted in SystemC, 学术相关 | Leave a comment

Digital Circuit Design Trends - 数字电路设计发展趋势

Digital_Circuit_Design_Trends.pdf 

Mark Horowitz, Fellow, IEEE, Donald Stark, Member, IEEE, and Elad Alon, Member, IEEE

IEEE JOURNAL OF SOLID-STATE CIRCUITS, VOL. 43, NO. 4, APRIL 2008, pp: 757 - 761

Special thanks to Yue Lu, a Berkeley EECS guy, for providing this significant paper.

Posted in 学术相关 | Leave a comment

SystemC学习笔记(2):SystemC的安装与使用

SystemC的安装与使用 

一、SystemC的安装:

    本文对SystemC安装的介绍是针对Red Hat Enterprise Linux 4 AS平台的。SystemC的安装需要GNU C++ Compiler和GNU Make,请先确认你安装了这两个组件。

1、从www.systemc.org上下载systemc-2.2.0.tgz(需要先注册一个免费帐号),解压后进入解压出来的文件夹 systemc-2.2.0。创建一个临时文件夹,比如

> mkdir objdir

2、进入该临时文件夹

> cd objdir

3、在.bashrc中添加环境变量,如下

> export CXX = g++

4、执行configure文件

> ./configure

    如果希望指定安装路径,则执行下面命令

> ./configure --prefix=/usr/local/systemc-2.2.0

5、编译文件包

> gmake

6、安装文件包

> gmake install

    这样SystemC就安装好了。

二、SystemC的使用:

    SystemC的使用和C++差不多,例如如果你使用的g++编译链接的话,需要指定头文件和库文件的路径,如下

> g++ my_systemc.cpp -I $my_path/systemc-2.2.0/include -L $my_path/systemc-2.2.0/lib-linux -lsystemc -o my_systemc

    要运行程序,则执行

> ./my_systemc

Posted in SystemC, 学术相关 | 3 Comments