【芯片前端】保持代码手感——交通灯

简介: 【芯片前端】保持代码手感——交通灯

长时间做方案,还是通过一些练习来保持代码手感。这次的题目是交通灯,经典的状态机题目,但是我不爱写状态机所以还是按自己的思路来组织下。


题目

要求实现一个交通红绿灯,具有红黄绿三个小指示灯和一个行人按钮,正常情况下,机动车道指示灯按照60时钟周期绿灯,5个时钟周期黄灯,10个时钟周期红灯循环。当行人按钮按下,如果剩余绿灯时间大于10个时钟,则缩短为10个时钟,小于10个时钟则保持不变。


注:机动车道的指示灯和人行道指示灯应该是配对的,当机动车道的灯为绿或者黄时,人行道的灯为红;当机动车道的灯为红时,人行道的灯为绿,为简便起见,只考虑机动车道的指示灯。

module triffic_light
    (
    input rst_n, //异位复位信号,低电平有效
        input clk, //时钟信号
        input pass_request,
    output [7:0]clock,
        output red,
    output yellow,
    output green
    );
end


解题思路

写RTL无非就是基于时序写逻辑,所以我还是先把时序单元也就是打拍寄存器做出来:

module dffre#(
  parameter WIDTH = 1
)(
  input         clk,
  input         rst_n,
  input  [WIDTH -1:0] d,
  input       en,
  output [WIDTH -1:0] q
);
reg [WIDTH -1:0]q;
always @(posedge clk or negedge rst_n)begin
  if(~rst_n)  q <= {WIDTH{1'b0}};
  else if(en) q <= d;
end
endmodule
module dffse#(
  parameter WIDTH = 1,
  parameter SET   = {WIDTH{1'b1}}
)(
  input         clk,
  input         rst_n,
  input  [WIDTH -1:0] d,
  input       en,
  output [WIDTH -1:0] q
);
reg [WIDTH -1:0]q;
always @(posedge clk or negedge rst_n)begin
  if(~rst_n)  q <= SET;
  else if(en) q <= d;
end
endmodule


分别做了两种寄存器,一种是复位归零一种是复位置位的;


接下来思考下,这三个灯其实就是寄存器的输出结果,对于绿灯而言,他的复位值应该是1(假设复位后路灯亮),在clock信号跳变为0时 && (当前为绿灯 或 当前为红灯)时,会发生信号的跳变,当前为绿灯则下一时刻绿灯变为0,当前为红灯则下一时刻绿灯变为1:

wire green_en;
wire green_d;
assign green_en = (red | green) & (cnt_q == 8'b0);
assign green_d  = ~green;
dffse #(.WIDTH(1), .SET(1'b1)) u_green(
  .clk  (clk),
  .rst_n(rst_n),
  .d    (green_d),
  .en   (green_en),
  .q    (green)
);

对于黄灯而言,在clock信号跳变为0时 && (当前为绿灯 或 当前为黄灯)时,会发生信号的跳变,当前为绿灯则下一时刻黄灯变为1,当前为黄灯则下一时刻黄灯变为0:

wire yellow_en;
wire yellow_d;
assign yellow_en = (green | yellow) & (cnt_q == 8'b0);
assign yellow_d  = ~yellow;
dffse #(.WIDTH(1), .SET(1'b0)) u_yellow(
  .clk  (clk),
  .rst_n(rst_n),
  .d    (yellow_d),
  .en   (yellow_en),
  .q    (yellow)
);


对于红灯而言,在clock信号跳变为0时 && (当前为红灯 或 当前为黄灯)时,会发生信号的跳变,当前为红灯则下一时刻黄灯变为0,当前为黄灯则下一时刻黄灯变为1:

wire red_en;
wire red_d;
assign red_en = (red | yellow) & (cnt_q == 8'b0);
assign red_d  = ~red;
dffse #(.WIDTH(1), .SET(1'b0)) u_red(
  .clk  (clk),
  .rst_n(rst_n),
  .d    (red_d),
  .en   (red_en),
  .q    (red)
);


可以看到,三个信号灯的逻辑可以说是高度一致的,区别只在于绿灯的复位值为1,一上来咱们先开绿灯。


那么接下来就是clock的逻辑了,clock的逻辑可以分成两种情况考虑:跳变和正常递减。对于跳变的情况,其实就下面这几种,注释里写的很清楚了:

wire     cnt_en;
wire         cnt_rerun_en;
wire [8 -1:0]cnt_d;
wire [8 -1:0]cnt_rerun_d;
wire [8 -1:0]cnt_q;
wire bypass = green & pass_request & (cnt_q>=10);
assign cnt_rerun_en = (cnt_q == 8'b0) | (green & bypass);
assign cnt_rerun_d  =  {8{red}}    & 8'd59 //red -> green
             | {8{yellow}} & 8'd9  //yello -> red
             | {8{green & !bypass}}  & 8'd4  //green -> yellow
             | {8{bypass}} & 8'd9; //green -> green


那么接下来就容易了,把正常递减和跳变组合在一起:

assign cnt_d = cnt_rerun_en ? cnt_rerun_d : cnt_q - 8'd1;
assign clock = cnt_q;
dffse #(.WIDTH(8), .SET(8'd59)) u_cnt(
  .clk  (clk),
  .rst_n(rst_n),
  .d    (cnt_d),
  .en   (1'b1),
  .q    (cnt_q)
);


全部代码完成!


波形验证




相关文章
|
人工智能 自然语言处理 前端开发
DeepSite:基于DeepSeek的开源AI前端开发神器,一键生成游戏/网页代码
DeepSite是基于DeepSeek-V3模型的在线开发工具,无需配置环境即可通过自然语言描述快速生成游戏、网页和应用代码,并支持实时预览效果,显著降低开发门槛。
1986 93
DeepSite:基于DeepSeek的开源AI前端开发神器,一键生成游戏/网页代码
|
缓存 前端开发 JavaScript
利用代码分割优化前端性能:策略与实践
在现代Web开发中,代码分割是提升页面加载性能的有效手段。本文介绍代码分割的概念、重要性及其实现策略,包括动态导入、路由分割等方法,并探讨在React、Vue、Angular等前端框架中的具体应用。
|
自然语言处理 前端开发 IDE
用通义灵码全新智能体+MCP实现从设计稿到前端代码,个人免费用
通义灵码全新升级,发布国内首个支持“自主决策+工具链闭环”的编程智能体,面向个人免费!新增功能包括智能体模式、混合推理模型Qwen3支持、全面集成MCP中文社区(涵盖2400+服务)及长期记忆能力。用户可通过IDE插件使用,兼容主流开发环境如JetBrains、VS Code和Visual Studio。教程展示如何将MasterGo设计稿转化为前端代码,简化开发流程。探索链接:[通义灵码官网](https://lingma.aliyun.com/)。
|
缓存 监控 前端开发
探索前端性能优化:关键策略与代码实例
本文深入探讨前端性能优化的关键策略,结合实际代码示例,帮助开发者提升网页加载速度和用户体验,涵盖资源压缩、懒加载、缓存机制等技术。
|
Web App开发 缓存 监控
前端性能优化实战:从代码到部署的全面策略
前端性能优化实战:从代码到部署的全面策略
435 1
|
Web App开发 前端开发 JavaScript
前端性能优化实战:从代码到部署的全面指南
前端性能优化实战:从代码到部署的全面指南
400 1
|
前端开发 JavaScript
前端界的革命:掌握这些新技术,让你的代码简洁到让人惊叹!
前端技术的快速发展带来了许多令人惊叹的新特性。ES6及其后续版本引入了箭头函数、模板字符串等简洁语法,极大减少了代码冗余。React通过虚拟DOM和组件化思想,提高了代码的可维护性和效率。Webpack等构建工具通过模块化和代码分割,优化了应用性能和加载速度。这些新技术正引领前端开发的革命,使代码更加简洁、高效、可维护。
245 2
|
前端开发 JavaScript 测试技术
前端工程师的必修课:如何写出优雅、可维护的代码?
前端工程作为数字世界的门面,编写优雅、可维护的代码至关重要。本文从命名规范、模块化设计、注释与文档、遵循最佳实践四个方面,提供了提升代码质量的方法。通过清晰的命名、合理的模块划分、详细的注释和持续的学习,前端工程师可以写出高效且易于维护的代码,为项目的成功打下坚实基础。
266 2
|
缓存 监控 前端开发
前端性能优化:从代码到部署的全面策略
前端性能优化:从代码到部署的全面策略

热门文章

最新文章

  • 1
    前端如何存储数据:Cookie、LocalStorage 与 SessionStorage 全面解析
    1163
  • 2
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(九):强势分析Animation动画各类参数;从播放时间、播放方式、播放次数、播放方向、播放状态等多个方面,完全了解CSS3 Animation
    512
  • 3
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(八):学习transition过渡属性;本文学习property模拟、duration过渡时间指定、delay时间延迟 等多个参数
    397
  • 4
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(七):学习ransform属性;本文学习 rotate旋转、scale缩放、skew扭曲、tanslate移动、matrix矩阵 多个参数
    389
  • 5
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(六):全方面分析css的Flex布局,从纵、横两个坐标开始进行居中、两端等元素分布模式;刨析元素间隔、排序模式等
    505
  • 6
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(五):背景属性;float浮动和position定位;详细分析相对、绝对、固定三种定位方式;使用浮动并清除浮动副作用
    677
  • 7
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(四):元素盒子模型;详细分析边框属性、盒子外边距
    1191
  • 8
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(三):元素继承关系、层叠样式规则、字体属性、文本属性;针对字体和文本作样式修改
    271
  • 9
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(二):CSS伪类:UI伪类、结构化伪类;通过伪类获得子元素的第n个元素;创建一个伪元素展示在页面中;获得最后一个元素;处理聚焦元素的样式
    992
  • 10
    【CSS】前端三大件之一,如何学好?从基本用法开始吧!(一):CSS发展史;CSS样式表的引入;CSS选择器使用,附带案例介绍
    463