SystemC入门学习-第5章 同步逻辑建模

news2024/11/22 15:10:39

本章重点学习同步逻辑中的触发器,锁存器的一些建模规范:

  • 触发器建模
  • 带异步置位/复位
  • 带同步置位/复位
  • 锁存器建模

5.1 触发器建模

        触发器建模的关键是敏感列表的规范。SC_MODULE的规范写法中出现过sensitive 参数列表是事件敏感, 对触发器建模来讲,SC_MODULE的结构不变,只需要将事件敏感修改为沿敏感,写法如下, 这样的沿可用于指定bool或者sc_logic类型的信号或者端口。就sc_logic类型而言,非0到0的跳变被认为是负跳变沿,非1到1的跳变被认为是正跳变沿。

//规定用正跳变沿
sensitive_pos

//规定用负跳变沿
sensitive_neg

        下面是一个D触发器模型, 敏感列表包含了指定于端口clk的沿敏感sensitive_pos, 表明只有在端口clk的正跳变沿时刻,数据输入d才得以传送到输出q。

//file basic_ff.h
#include "systemc.h"

SC_MODULE(basic_ff){
    sc_in <bool> d, clk;
    sc_out <bool> q;

    void prc_basic_ff();
    
    SC_CTOR(basic_ff){
        SC_METHOD(prc_basic_ff);
        sensitive_pos << clk;
    }

};

//file basic_ff.cpp
#include "basic_ff.h"

void basic_ff::prc_basic_ff(){
    q = d;
}

        下面是一个包含多位端口的触发器示例,为prc_gang_ffs指定了负跳变沿敏感,所以这是一个由负跳变沿触发的触发器。

#include "systemc.h"

const int WIDTH =4;

SC_MODULE(gang_ffs){
    sc_in <sc_uint<WIDTH> > current_state;
    sc_in <bool> clock;
    sc_out <sc_uint<WIDTH> > next_state;

    void prc_gang_ffs();
    
    SC_CTOR(gang_ffs){
        SC_METHOD(prc_gang_ffs);
        sensitive_neg << clock;
    }

};

void gang_ffs::prc_gang_ffs(){
    next_state = current_state;
}

5.2 多进程

        一个模块可以具有多个SC_METHOD进程。每个进程可以模拟组合逻辑(使用事件敏感),也可以模拟同步逻辑(使用沿敏感)。进程之间的通信联系必须使用信号。

        一个进程不能既有沿敏感,又有事件敏感,并且在沿敏感的规范中只可以使用一个bool型的信号或者端口。

        下面是一个流水线的序列检测器。这个例子中,触发器用于生成信号。当输入数据流检测到‘101’序列时,检测器的输出为1。综合后的逻辑如下图。

#include "systemc.h"

SC_MODULE(seq_det){
    sc_in <bool> clk, data;
    sc_out <bool> seq_found;

    void prc_seq_det();//同步逻辑进程
    void prc_output();//组合逻辑进程

    sc_signal <bool> first, second, third;

    SC_CTOR(seq_det){
        SC_METHOD(prc_seq_det);
        sensitive_pos <<clk;

        SC_METHOD(prc_output);
        sensitive << first << second << third;

    }

};

void seq_det::prc_seq_det(){
    first = data;
    second = first; 
    third = second;
}

void seq_det::prc_output(){
    seq_found = first & !second & third;
}

        需要注意到是,信号和端口赋值的∆延迟。对信号和端口的赋值不是立即发生的,而是总发生在一个∆延迟之后。进程之间是可以同步执行的,即当时钟正跳变沿到来时候,进程prc_seq_det被调用,first被赋值,但是second = first, third = second没有执行时候,first的变化导致了进程prc_output的执行,所以此刻second是上个时刻的值,third是上上个时刻的值,所以如果序列中出现了101,就能被检测出来了。

5.3 带异步置位和清零端的触发器

        带异步置位和清零端的触发器编写时,清零输入的正或负跳变沿被指定为沿敏感列表的一部分。即若异步清零为低电平有效,则指定使用负跳变沿;若高电平有效,则使用正跳变沿。下面是一个带异步清零端的增/减计数器。

#include "systemc.h"

const int COUNT_SIZE = 4;
SC_MODULE(count4){
    sc_in <bool> mclk, clear, updown;
    sc_out <sc_uint <COUNT_SIZE> > data_out;

    void sync_block();

    SC_CTOR(count4){
        SC_METHOD(sync_block);
        sensitive_pos << mclk;
        sensitive_neg << clear;
    }

};

void count4::sync_block(){
    if(!clear)  //符合异步条件
        data_out = 0;
    else          //不符合,使用时钟的正跳变沿,即mclk
        if(updown)
            data_out = data_out.read() + 1;
        else
            data_out = data_out.read() - 1;
}

        下面是一个包含异步置位和清零位的触发器建模。置位和清零的输入沿必须指定为敏感列表的一部分。

#include "systemc.h"

const int STATE_BITS = 4;

SC_MODULE(async_states){
    sc_in <bool> clk, reset, set;
    sc_in <sc_uint <STATE_BITS> > current_state;
    sc_out<sc_uint <STATE_BITS> > next_state;

    void prc_async_state();

    SC_CTOR(async_states){
        SC_METHOD(prc_async_state);
        sensitive_neg << clk <<reset;
        sensitive_pos <<set;
    }

};

void async_states::prc_async_state(){
    if (!reset)   //第一个异步条件
        next_state = 0;
    else if(set)  //第二个异步条件
        next_state = 5;
    else          //(隐含的)负跳变沿
        next_state = current_state;
}

        通常情况下,一个进程可以有多个被指定为其敏感列表的跳变沿。并且使用一条这样形式的if语句来描述该进程的行为,在该形式的语句中首先检查的不是时钟条件,而在最后那个else分支中才隐含了时钟条件。若指定使用负跳变沿敏感列表,则还需要使用非时钟条件的逻辑“非”;否则就要使用非时钟条件的正值。如下是这种条件语句的样板程序。

SC_METHOD(my_process);
sensitive_pos << a << b << clk;
sensitive_net << d << e << f;

void my_module::my_process(){
    if(a)
        <异步行为>
    else if (b)
        <异步行为>
    else if (!d) //因为指定了负跳变沿,所以使用逻辑“非”
        <异步行为>
    else if (!f)
        <异步行为>
    else        //时钟的正跳变沿
        <按时钟节拍的行为>
}

5.4 带同步置位和清零端的触发器

        在未带同步置位和清零端得触发器建模时,在敏感列表中只需指定一个时钟跳变沿即可。其置位和清零条件被清晰明确地编写在SC_METHOD进程的代码里。

        如下是一个带低电平有效同步置位端的计数器。(prc_counter代码,书上写了未出现过的变量名:preset,不知道是写错了还是自己哪里没理解清)

#include "systemc.h"

const int COUNT_BITS = 4;

SC_MODULE(sync_count4){
    sc_in <bool> mclk, clear, updown;
    sc_in <sc_uint<COUNT_BITS> > data_in;
    sc_out<sc_uint<COUNT_BITS> > data_out;

    void  prc_counter();
    
    SC_CTOR(sync_count4){
        SC_METHOD(prc_counter);
        sensitive_pos << mclk;
    }
};

void sync_count4::prc_counter(){
    if(!preset)
        data_out = data_in;
    else
        if(updown)
            data_out = data_out.read()+1;
        else
            data_out = data_out.read()-1;
}

同步逻辑如下图:

5.5 多时钟和多相位时钟

        在一个模块中,可以编写任意多个SC_METHOD进程,每个这样的进程都可以是同步或组合的进程。当出现多个同步进程时,可以在不同进程中使用不同的时钟来为设计的逻辑建模。

        下面示例,进程prc_vt15ck在时钟vt15ck的负跳变沿触发,而进程prc_ds1ck则在时钟dslck的正跳变沿触发。

#include "systemc.h"

SC_MODULE(mult_clks){
    sc_in <bool> vt15ck, addclk, adn, resetn, subclr, subn, ds1ck;
    sc_out <bool> ds1_add, ds1_sub;

    void prc_vt15ck();
    void prc_ds1ck();
    sc_signal <bool> add_state, sub_state;

    SC_CTOR(mult_clks){
        SC_METHOD(prc_vt15ck);
        sensitive_neg << vt15ck;
        SC_METHOD(prc_ds1ck);
        sensitive_pos << ds1ck;
    }

};

void mult_clks::prc_vt15ck(){
    add_state = !(addclk | (adn | resetn));
    sub_state = subclr ^ (subn & resetn);
}

void mult_clks::prc_ds1ck(){
    ds1_add = add_state;
    ds1_sub = sub_state;
}

        如下是综合后生成的逻辑。信号add_state和信号sub_state在时钟vt15ck的负跳变沿时刻被赋值,并且它们的值在另外一个时钟ds1ck的正跳变沿时刻被赋予ds1_add和ds1_sub。在RTL建模时,通常规定不允许使用不同时钟沿对同一个信号或端口赋值

        

        在设计模块中可以使用同一个时钟的不同相位。下面举例说明。进程prc_rising由时钟zclk的正跳变沿触发,进程prc_falling则由时钟zclk的负跳变沿触发。一个进程的输出是另一个进程的输入,用信号d在进程之间通信实现。

#include "systemc.h"

SC_MODULE(multiphase)
{
    sc_in <bool> zclk, a, b, c;
    sc_out <bool> e;

    void prc_rising();
    void prc_falling();

    sc_signal <bool> d;

    SC_CTOR(multiphase){
        SC_METHOD(prc_rising);
        sensitive_pos << zclk;

        SC_METHOD(prc_falling);
        sensitive_neg << zclk;
    }

};

void multiphase::prc_rising(){
    e = d & c;
}

void multiphase::prc_falling(){
    d = a & b;
}

5.6 锁存器建模

        如果没有对进程的所有路径赋值,则在该进程综合后的逻辑中有可能为信号或端口生成锁存器。条件语句如if , switch,是可能在进程内生成多条执行路径的两条语句。

        if语句生成锁存器的例子1:

        当clk为0时候,输出端口z没有被赋值。因此根据该模型的定义,综合后将为端口z生成一个锁存器。

#include "systemc.h"

SC_MODULE(latched_alu){
    sc_in <bool> clk, a,b;
    sc_out <bool> z;

    void prc_alu();

    SC_CTOR(latched_alu){
        SC_METHOD(prc_alu);
        sensitive_pos << clk << a << b;
    }

};

void latched_alu::prc_alu(){
    if(clk)
        z = !( a | b);

}

        switch语句生成锁存器的一个例子2:

#include "systemc.h"

enum states{s0, s1, s2, s3};
const int Z_SIZE = 2;

SC_MODULE(state_update){
    sc_in <states> current_state;
    sc_out <sc_uint<Z_SIZE> > z;

    void prc_state_update();

    SC_CTOR(state_update){
        SC_METHOD(prc_state_update);
        sensitive << current_state;
    }

};

void state_update::prc_state_update(){
    switch(current_state)
    {
        case s0:
        case s3: z=0; break;
        case s1: z = 3; break;
    }

}

避免生成锁存器

        在大多数情况下,生成锁存器是不需要的。所以避免生成锁存器的关键是:若信号或端口在条件语句中被赋值,则必须确认条件语句的所有可能分支中,该信号或端口都被赋予一个值

也就是,代码覆盖所有的条件分支,或者给端口或信号赋初值。

比如上面示例2,给prc_state_update函数修改如下:

//修改方案1
void state_update::prc_state_update(){
    switch(current_state)
    {
        case s0:
        case s3: z = 0; break;
        case s1: z = 3; break;
        default: z = 1; break;
    }

}

//修改方案2
void state_update::prc_state_update(){
    z = 1; 
    switch(current_state)
    {
        case s0:
        case s3: z = 0; break;
        case s1: z = 3; break;
    }

}

         另一个完整示例:

        下面示例的prc_compute1, prc_compute是生成锁存器和不生成锁存器的写法,以及其综合后的逻辑图对比:

#include "systemc.h"
const int BITS = 2;
enum grade_type { fail, pass, excellent};

SC_MODULE(compute){
    sc_in <sc_uint<BITS> >marks;
    sc_out <grade_type> grade;

    void prc_compute();

    SC_CTOR(compute){
        SC_METHOD(prc_compute);
        sensitive << marks;
    }

};

void compute::prc_compute(){
    if(marks.read() < 5)
        grade = fail;
    else if (marks.read()<7)
        grade = pass;
    else
        grade = excellent;

}

void compute::prc_compute1(){
    if(marks.read() < 5)
        grade = fail;
    else if (marks.read()<7)
        grade = pass;

}

 

5.7 小结

  • 同步逻辑建模使用跳变沿敏感的SC_METHOD进程
  • 一个模块可以包含任意多个进程,每个进程可以是表示组合逻辑的进程,或者是表示同步逻辑的进程
  • 若在一个对时钟跳变沿敏感的进程中对信号或者端口进行赋值,则综合后生成的逻辑为触发器
  • 同步逻辑中的异步置位和复位可以使用特定形式的if语句建模
  • 必须在if语句或开关语句的所有分支中对信号或端口赋值,否则综合后将生成锁存器
  • 若在if语句或开关语句前对信号或端口进行初始化,或者确保在条件语句的所有分支中都对其进行赋值,则综合后可以避免生成锁存器。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1092388.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

操作系统学习笔记4-死锁问题

文章目录 1、死锁逻辑图2、死锁三胞胎3、死锁的原因及必要条件4、死锁处理策略之死锁预防5、死锁处理策略之死锁避免&#xff08;银行家算法&#xff09;6、死锁处理策略之死锁检测与解除 1、死锁逻辑图 2、死锁三胞胎 3、死锁的原因及必要条件 4、死锁处理策略之死锁预防 5、死…

查找组成一个偶数最接近的两个素数

一、题目 二、代码 #include <iostream> using namespace std; bool isPrime(int num)//判断素数 {if (num < 1)return false;if (num 2)return true;if (num % 2 0)return false;for (int i 3; i < num; i){if (num % i 0){return false;}}return true; } in…

win11下的VS2022+QT6+VTK9.2+PCL1.13.1联合开发环境配置及踩坑记录

准备工作&#xff1a; 安装VS2022&#xff1a;这个比较简单&#xff0c;网上随便找个教程就行 安装QT并为VS2022添加QT Creater插件&#xff1a;VS2022配置Qt6_vs2022 qt6-CSDN博客 安装PCL&#xff1a;vs2022配置pcl1.13.1_pcl配置-CSDN博客 安装PCL过程中本身也会安装VTK&…

小程序入门及案例展示

目录 一、小程序简介 1.1 为什么要使用小程序 1.2 小程序可以干什么 二、前期准备 2.1 申请账号 2.2 开发工具下载与安装 三、电商案例演示 四、入门案例 4.1 项目结构解析 4.2 基础操作及语法 4.3 模拟器 4.4 案例演示 4.4.1 新建页面 4.4.2 头部样式设置 4.4.…

Marin说PCB之CoilcraftBourns POC 电感的性能对比

十一小长假本来是一件美好事情。可是天有不测风云&#xff0c;小编我却有祸兮来了。本来是公司的硬件同事强哥要回以色列了&#xff0c;最近他们国家那边都在打仗&#xff0c;强哥本着舍身为国的精神回国抗战去了。小编我就想着在他回国之前搞了篮球比赛送别一下他呢&#xff0…

小程序入门——详细教程

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 生活的理想&#xff0c;为了不断更新自己 ! 1.微信小程序 入门 1.1什么是小程序&#xff1f; 2017年度百度百科十大热词之一 微信小程…

BUUCTF pwn1_sctf_2016 1

代码分析 查看文件信息然后进行反汇编 关键信息 32位栈不可执行 IDA反汇编 说实话&#xff0c;这个应该是C编写的程序&#xff0c;C基础还是不行&#xff0c;我硬是没看懂这个代码 我查了一下字符串 这里的get_flag是函数&#xff0c;另一个应该就是执行的一个命令了 到IDA…

【LeetCode刷题(数据结构)】:翻转二叉树

方法一&#xff1a;递归 思路与算法 这是一道很经典的二叉树问题。显然&#xff0c;我们从根节点开始&#xff0c;递归地对树进行遍历&#xff0c;并从叶子节点先开始翻转。如果当前遍历到的节点 root\textit{root}root 的左右两棵子树都已经翻转&#xff0c;那么我们只需要交…

【入门】.Net Core 6 WebApi 项目搭建

一、创建项目 1.1.创建新项目&#xff1a;打开开发工具>创建新项目>搜索API>选择C#语言的ASP.NET Core Web API 1.2.配置新项目&#xff1a;**自定义项目信息以及存储路径 1.3.其他信息&#xff1a;这里框架必须选择.NET 6.0,其他配置默认勾选即可&#xff0c;也可以根…

SystemVerilog Assertions应用指南 第一章(1.24章节 “or”运算符)

二进制运算符“or”可以用来逻辑地组合两个序列。只要其中一个序列成功,整个属性就成功。序列s29a和s29b是两个独立的序列。属性p29将两者用“or运算符组合起来。当其中任一序列成功时,属性就成功。 sequence s29a;(posedge clk) a##[1:2] b; endsequencesequence s29b;(posed…

Hadoop3教程(六):HDFS中的DataNode

文章目录 &#xff08;63&#xff09;DataNode工作机制&#xff08;64&#xff09;数据完整性&#xff08;65&#xff09;掉线时限参数设置参考文献 &#xff08;63&#xff09;DataNode工作机制 DataNode内部存储了一个又一个Block&#xff0c;每个block由数据和数据元数据组…

2024年计算机专业Java选题推荐✅(最新、最全、最容易通过的选择)

文章目录 前言选题和具体实现详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#x…

USDR脱锚事件:稳定币碰上房地产,双重buff想不崩都难!

10月11日&#xff0c;一种名为Real USD&#xff08;USDR&#xff09;的稳定币脱锚&#xff0c;在几个小时内迅速从1美元跌至0.5美元&#xff0c;而这无疑是一场典型的挤兑&#xff0c;主要由该稳定币的高流动性债务与其低流动性抵押物之间存在期限错配所致。 USDR是一种流通量为…

链表oj (7.29)

203. 移除链表元素 - 力扣&#xff08;LeetCode&#xff09; 思路1&#xff1a;使用结构体指针 cur 遍历链表&#xff0c;遇到值为 val 时删除&#xff0c;删除之前需要判断是头删还是正常的删除&#xff0c;头删需要改变头指针&#xff1b; 正常的删除需要 cur(待删除节点&am…

爬虫 | 基础模块了解

文章目录 &#x1f4da;http协议&#x1f4da;requests模块&#x1f4da;re模块&#x1f407; re.I 或 re.IGNORECASE&#x1f407;re.M或 re.MULTILINE&#x1f407;re.S 或 re.DOTALL&#x1f407; re.A 或 re.ASCII&#x1f407; re.X 或 re.VERBOSE&#x1f407;特殊字符类…

嵌入式学习笔记(55)LCD简介

12.1.1什么是LCD (1)Liquid Crystal Display&#xff0c;俗称液晶显示 (2)液晶是一种材料&#xff0c;液晶这种材料具有一种特点&#xff1a;可以在电信号的驱动下液晶分子进行旋转&#xff0c;旋转时会影响透光性&#xff0c;因此我们可以在整个液晶面板后面用白光照&#x…

SystemVerilog Assertions应用指南 第一章(1.25章节 “first_match”运算符)

任何时候使用了逻辑运算符(如“and”和“or”)的序列中指定了时间窗,就有可能出现同一个检验具有多个匹配的情况。“ first match”构造可以确保只用第一次序列匹配,而丢弃其他的匹配。当多个序列被组合在一起,其中只需时间窗内的第一次匹配来检验属性剩余的部分时,“ first ma…

2023年09月 C/C++(七级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C编程&#xff08;1~8级&#xff09;全部真题・点这里 Python编程&#xff08;1~6级&#xff09;全部真题・点这里 第1题&#xff1a;红与黑 有一间长方形的房子&#xff0c;地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上&#xff0c;只能向相邻的黑色…

闲鱼的商品结构化是如何演进的

闲鱼商品结构化和淘宝/天猫最大的区别在于闲鱼卖家都是个人用户&#xff0c;无论是专业程度还是行动力远不及淘宝卖家。为了不阻碍商品发布&#xff0c;闲鱼一直倡导轻发布&#xff0c;理想状况用户拍完照片输入一段描述即可完成发布。但是这和商品结构化相悖&#xff1a;卖家输…

基于php+thinkphp+vue的校园二手交易网站

运行环境 开发语言&#xff1a;PHP 数据库:MYSQL数据库 应用服务:apache服务器 使用框架:ThinkPHPvue 开发工具:VScode/Dreamweaver/PhpStorm等均可 项目简介 随着社会的发展&#xff0c;社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发…