<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Linux on Laning's Blog</title><link>https://blog.laning.org/categories/linux/</link><description>Recent content in Linux on Laning's Blog</description><generator>Hugo</generator><language>zh-CN</language><lastBuildDate>Thu, 10 Apr 2025 15:34:47 +0800</lastBuildDate><atom:link href="https://blog.laning.org/categories/linux/index.xml" rel="self" type="application/rss+xml"/><item><title>异步函数async和await</title><link>https://blog.laning.org/posts/wp-0446/</link><pubDate>Thu, 10 Apr 2025 15:34:47 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0446/</guid><description>&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;最近在回头看&lt;a href="https://github.com/laningya/nfd/blob/main/worker.js"&gt;nfd项目&lt;/a&gt; 的源码，看到了使用async和await的js代码，因此想了解一下代码运行的机制。&lt;/p&gt;
&lt;h2 id="一个例子"&gt;一个例子&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;function SicBo() {
return new Promise((resolve, reject) =&amp;gt; {
console.log(&amp;#34;开始摇&amp;#34;)
setTimeout(() =&amp;gt; {
let n = parseInt(Math.random() * 6 + 1, 10)
resolve(n)
}, 1000)
})
}
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="上述代码的执行过程如下"&gt;上述代码的执行过程如下：&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;立即执行 &lt;code&gt;console.log(&amp;quot;开始摇&amp;quot;)&lt;/code&gt;&lt;/strong&gt; —— ✅ 马上输出。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;启动一个“1秒后执行的任务”&lt;/strong&gt; —— 通过 &lt;code&gt;setTimeout(...)&lt;/code&gt; 注册了一个回调，1 秒后执行。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;返回一个 Promise 对象&lt;/strong&gt;，这个 Promise 会在 1 秒后变成“完成状态”并给出点数。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="如果直接调用这个函数"&gt;如果直接调用这个函数：&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;function test() {
const result = SicBo()
console.log(&amp;#39;骰子结果:&amp;#39;, result)
}
test()
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;调用输出如下：&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;开始摇
骰子结果: Promise { &amp;lt;pending&amp;gt; }
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;显然并不是我们想要的结果&lt;/p&gt;
&lt;h3 id="异步函数的一般调用"&gt;异步函数的一般调用：&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;SicBo().then(result =&amp;gt; {
console.log(&amp;#39;骰子结果:&amp;#39;, result)
})
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这种写法最大的弊端是会产生回调地狱，即调用多个异步函数产生嵌套，导致代码可读性变差。&lt;/p&gt;</description></item><item><title>TG机器人通知IP地址</title><link>https://blog.laning.org/posts/wp-0442/</link><pubDate>Wed, 09 Apr 2025 18:38:01 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0442/</guid><description>&lt;h2 id="背景"&gt;背景&lt;/h2&gt;
&lt;p&gt;公网IPv4政策的收紧，包括不限于不能使用DDNS服务解析到未备案域名，因此使用TG机器人API服务，定时检测IP地址，若IP变化则自动更新&lt;/p&gt;
&lt;h2 id="项目地址"&gt;项目地址&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://raw.githubusercontent.com/laningya/Raspberry-Pi/refs/heads/master/shell/telegram-ip-bot.sh"&gt;Raspberry-Pi/shell/telegram-ip-bot.sh at master · laningya/Raspberry-Pi · GitHub&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="部署过程"&gt;部署过程&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;获取ChatID&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;API_TOKEN=&amp;#34;YOUR_BOT_TOKEN&amp;#34;
curl -s &amp;#34;https://api.telegram.org/bot$API_TOKEN/getUpdates&amp;#34; | jq &amp;#39;.result[0].message.chat.id&amp;#39;
&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;脚本填入Bot的API Token，以及自行判断需要设置代理&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;添加crontab定时任务&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;*/30 * * * * /bin/bash /root/telegram-ip-bot.sh &amp;gt; /dev/null 2&amp;gt;&amp;amp;1 &amp;amp;
&lt;/code&gt;&lt;/pre&gt;&lt;h2 id="参考文档"&gt;参考文档&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://core.telegram.org/bots/api"&gt;Telegram Bot API&lt;/a&gt;&lt;/p&gt;</description></item><item><title>Emby反代及HTTPS配置教程</title><link>https://blog.laning.org/posts/wp-0433/</link><pubDate>Sat, 01 Mar 2025 12:18:00 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0433/</guid><description>&lt;h2 id="nginx配置"&gt;Nginx配置&lt;/h2&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;server {
listen 443 ssl;
server_name your.domain.com;
# Security / XSS Mitigation Headers
add_header X-Frame-Options &amp;#34;SAMEORIGIN&amp;#34;;
add_header X-XSS-Protection &amp;#34;1; mode=block&amp;#34;;
add_header X-Content-Type-Options &amp;#34;nosniff&amp;#34;;
# ssl的设置
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
ssl_session_timeout 5m;
# 禁止ip访问
if ($host ~ ^\d+\.\d+\.\d+\.\d+$) {
return 404;
}
# 防止爬虫获取header，直接访问/就返回502，其他的路径才行，app观看不影响，不用这个
location = / {
return 502;
}
location / {
resolver 1.1.1.1 ipv6=off;
if ($host != $server_name) {
return 403;
}
proxy_pass https://www.emby.com;
# ssl pass相关的设置
proxy_ssl_name www.emby.com;
proxy_ssl_server_name on;
proxy_set_header Host www.emby.com;
set $magpiecdn &amp;#34;$scheme://$server_name:$server_port&amp;#34;;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Protocol $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header MagpieCDN $magpiecdn;
proxy_buffering off;
}
location /***cdn {
resolver 1.1.1.1 ipv6=off;
proxy_pass https://$arg_load.emby.com;
# ssl pass相关的设置
proxy_ssl_name $arg_load.emby.com;
proxy_ssl_server_name on;
proxy_set_header Host $arg_load.emby.com;
proxy_buffering on;
proxy_max_temp_file_size 50m;
}
}
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;说明：&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>通过LangBot将大模型接入到Telergram</title><link>https://blog.laning.org/posts/wp-0430/</link><pubDate>Fri, 14 Feb 2025 13:05:18 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0430/</guid><description>&lt;h2 id="项目地址"&gt;项目地址&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/RockChinQ/LangBot"&gt;GitHub - RockChinQ/LangBot: 😎丰富生态、🧩支持扩展、🦄多模态 - 大模型原生即时通信机器人平台 | 适配 QQ / 微信（企业微信、个人微信）/ 飞书 / 钉钉 / Discord / Telegram 等消息平台 | 支持 ChatGPT、DeepSeek、Dify、Claude、Gemini、xAI Grok、Ollama、LM Studio、阿里云百炼、火山方舟、SiliconFlow、Qwen、Moonshot、ChatGLM、SillyTraven、MCP 等 LLM 的机器人 / Agent | LLM-based instant messaging bots platform, supports Discord, Telegram, WeChat, Lark, DingTalk, QQ&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="部署过程"&gt;部署过程&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Git 克隆项目：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;git clone https://github.com/RockChinQ/LangBot
cd LangBot
&lt;/code&gt;&lt;/pre&gt;&lt;ol start="2"&gt;
&lt;li&gt;启动容器：&lt;/li&gt;
&lt;/ol&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;docker compose up
&lt;/code&gt;&lt;/pre&gt;&lt;ol start="3"&gt;
&lt;li&gt;在 LangBot 中填写信息并启动&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;将Telegram Bot的API Token 填写到platform.json中。&lt;/p&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt; {
&amp;#34;adapter&amp;#34;: &amp;#34;telegram&amp;#34;,
&amp;#34;enable&amp;#34;: true,
&amp;#34;token&amp;#34;: &amp;#34;xxxxxxx&amp;#34;
},
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;填写完成后启动 LangBot，若成功配置，日志中会出现&lt;code&gt;[02-02 16:48:15.263] manager.py (68) - [INFO] : 初始化平台适配器 1: telegram&lt;/code&gt;的字样，保持 LangBot 运行。&lt;/p&gt;</description></item><item><title>数字集成电路设计实验——FIR滤波器</title><link>https://blog.laning.org/posts/wp-0246/</link><pubDate>Fri, 21 Apr 2023 14:33:00 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0246/</guid><description>&lt;h2 id="1-课程信息"&gt;1. 课程信息&lt;/h2&gt;
&lt;p&gt;■&lt;strong&gt;实验地点&lt;/strong&gt;：清水河校区KB239&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;■ **实验时间：**2021.04.16&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;■ **实验时长：**3小时（4节课）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2-实验要求"&gt;2. 实验要求&lt;/h2&gt;
&lt;p&gt;1. The fir filter input sampling rate is &lt;strong&gt;100kHz&lt;/strong&gt;, the filter passband single-sideband bandwidth is &lt;strong&gt;20kHz&lt;/strong&gt;, the out-of-band suppression is &lt;strong&gt;90dB&lt;/strong&gt;, and the in-band ripple is &lt;strong&gt;1dB&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;2. The filter coefficient needs to be &lt;strong&gt;fixed-point&lt;/strong&gt;, and the effective number of ADCs is &lt;strong&gt;24bit&lt;/strong&gt;. The filter coefficient bit width is self-defined.&lt;/p&gt;
&lt;p&gt;思考（加分项）：&lt;/p&gt;
&lt;p&gt;1. The relationship between filter passband, stopband, out-of-band rejection and filter order&lt;/p&gt;</description></item><item><title>数字集成电路设计实验——时钟</title><link>https://blog.laning.org/posts/wp-0243/</link><pubDate>Sat, 15 Apr 2023 14:30:00 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0243/</guid><description>&lt;h1 id="1-课程信息"&gt;1. 课程信息&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;实验地点&lt;/strong&gt;：清水河校区KB239&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;**实验时间：**2021.04.9&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;实验时长:&lt;/strong&gt; 3小时（4节课）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="2-实验要求"&gt;2. 实验要求&lt;/h1&gt;
&lt;p&gt;驱动板上数码管显示当前时间（包含时、分、秒）&lt;/p&gt;
&lt;p&gt;①建议定义n个按键，如用于功能切换 (tab)、校时+1(up)及确认(ok)&lt;/p&gt;
&lt;p&gt;②整点报时: 7:00~23:00间每个整点蜂鸣器响1s&lt;/p&gt;
&lt;p&gt;思考（加分项）：&lt;/p&gt;
&lt;p&gt;1. 如何添加闹钟功能？&lt;/p&gt;
&lt;p&gt;2. 如何添加定时器功能？&lt;/p&gt;
&lt;p&gt;3. 设计模N计数器的测试向量集，撰写testbench进行验证测试&lt;/p&gt;
&lt;h1 id="3-设计与实现"&gt;3. 设计与实现&lt;/h1&gt;
&lt;h2 id="31-电路功能说明"&gt;3.1 电路功能说明&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;（包括各个模块功能、关键代码分析，可以使用文字、框图、功能表、状态图等进行说明）&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="311-顶层设计"&gt;3.1.1 顶层设计&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://blog.laning.org/images/2023-04-15-%E6%95%B0%E5%AD%97%E9%9B%86%E6%88%90%E7%94%B5%E8%B7%AF%E8%AE%BE%E8%AE%A1%E5%AE%9E%E9%AA%8C%E2%80%94%E2%80%94%E6%97%B6%E9%92%9F/%E6%95%B0%E5%AD%97%E6%97%B6%E9%92%9F%E9%A1%B6%E5%B1%82%E6%A8%A1%E5%9D%97%E8%BF%9E%E6%8E%A5.png"&gt;&lt;img alt="数字时钟顶层模块连接" loading="lazy" src="https://blog.laning.org/images/2023-04-15-%E6%95%B0%E5%AD%97%E9%9B%86%E6%88%90%E7%94%B5%E8%B7%AF%E8%AE%BE%E8%AE%A1%E5%AE%9E%E9%AA%8C%E2%80%94%E2%80%94%E6%97%B6%E9%92%9F/%E6%95%B0%E5%AD%97%E6%97%B6%E9%92%9F%E9%A1%B6%E5%B1%82%E6%A8%A1%E5%9D%97%E8%BF%9E%E6%8E%A5.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="312-timing_module"&gt;3.1.2 timing_module&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://blog.laning.org/images/2023-04-15-%E6%95%B0%E5%AD%97%E9%9B%86%E6%88%90%E7%94%B5%E8%B7%AF%E8%AE%BE%E8%AE%A1%E5%AE%9E%E9%AA%8C%E2%80%94%E2%80%94%E6%97%B6%E9%92%9F/%E8%AE%A1%E6%97%B6%E6%A8%A1%E5%9D%97%E4%B8%8E%E6%A0%A1%E6%97%B6%E6%A8%A1%E5%9D%97%E7%BB%93%E6%9E%84.png"&gt;&lt;img alt="计时模块与校时模块结构" loading="lazy" src="https://blog.laning.org/images/2023-04-15-%E6%95%B0%E5%AD%97%E9%9B%86%E6%88%90%E7%94%B5%E8%B7%AF%E8%AE%BE%E8%AE%A1%E5%AE%9E%E9%AA%8C%E2%80%94%E2%80%94%E6%97%B6%E9%92%9F/%E8%AE%A1%E6%97%B6%E6%A8%A1%E5%9D%97%E4%B8%8E%E6%A0%A1%E6%97%B6%E6%A8%A1%E5%9D%97%E7%BB%93%E6%9E%84.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;接收PLL多次分频得到的1Hz时钟信号作为模块的时钟信号，设置17位数据用来存储当前时间（[5:0]表示秒，[11:6]表示分，[16:12]表示小时），当秒达到59时，则下一次操作为秒位置0，同时分位加1，分钟与小时的关系依次类推。同时当load信号使能时，即设置时间功能打开时，数据位数据将被加载进来的数据覆盖。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-verilog" data-lang="verilog"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// timing_module.v
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;`timescale&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;ns &lt;span style="color:#f92672"&gt;/&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;ps
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//////////////////////////////////////////////////////////////////////////////////
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Company: UESTC
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Engineer: Qy_Ley
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Create Date: 2021/03/14 15:06:37
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Design Name: Digital Clock for EES331
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Module Name: timing_module
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Project Name: Digital Clock
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Target Devices: EES331
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Tool Versions: Vivado 18.3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Description:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Dependencies:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Revision:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Revision 0.01 - File Created
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// Additional Comments:
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;//////////////////////////////////////////////////////////////////////////////////
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;module&lt;/span&gt; timing_module(
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;input&lt;/span&gt; i_clk_1Hz,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;input&lt;/span&gt; i_load,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;input&lt;/span&gt; i_rstn,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;input&lt;/span&gt; i_ena,
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;input&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] i_load_hms, &lt;span style="color:#75715e"&gt;// [5:0] for sec, [11:6] for min, [16:12] for hour, BCD coding
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;output&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] o_hms &lt;span style="color:#75715e"&gt;// [5:0] for sec, [11:6] for min, [16:12] for hour, BCD coding
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;);
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// wire m_co_sec, m_co_min; // Carry output from second &amp;amp; minute counter
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;reg&lt;/span&gt; ld;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;reg&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;16&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] ld_cnt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;reg&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;4&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] hour_cnt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;reg&lt;/span&gt; [&lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#f92672"&gt;:&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;] min_cnt,sec_cnt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;always&lt;/span&gt; @(&lt;span style="color:#66d9ef"&gt;posedge&lt;/span&gt; i_clk_1Hz) &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ld &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; i_load;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; ld_cnt &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; i_load_hms;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt; &lt;span style="color:#75715e"&gt;//clock cross-domain buffer
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;always&lt;/span&gt; @(&lt;span style="color:#66d9ef"&gt;posedge&lt;/span&gt; i_clk_1Hz &lt;span style="color:#66d9ef"&gt;or&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;negedge&lt;/span&gt; i_rstn) &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(&lt;span style="color:#f92672"&gt;!&lt;/span&gt;i_rstn) &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hour_cnt &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; min_cnt &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sec_cnt &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(ld) &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {hour_cnt, min_cnt, sec_cnt} &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; ld_cnt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(i_ena) &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(sec_cnt &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;&amp;#39;d59&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sec_cnt &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(min_cnt &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;6&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;&amp;#39;d59&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; min_cnt &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;if&lt;/span&gt;(hour_cnt &lt;span style="color:#f92672"&gt;==&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;5&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;&amp;#39;d23&lt;/span&gt;) &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hour_cnt &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;0&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; hour_cnt &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; hour_cnt&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; min_cnt &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; min_cnt&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;else&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;begin&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; sec_cnt &lt;span style="color:#f92672"&gt;&amp;lt;=&lt;/span&gt; sec_cnt&lt;span style="color:#f92672"&gt;+&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#75715e"&gt;/* Complete the counter for second, minute, hour */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;assign&lt;/span&gt; o_hms &lt;span style="color:#f92672"&gt;=&lt;/span&gt; {hour_cnt, min_cnt, sec_cnt};
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;endmodule&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="313-control_module"&gt;3.1.3 control_module&lt;/h2&gt;
&lt;p&gt;为系统控制的模块，采用有限状态机的描述方式，如图：&lt;/p&gt;</description></item><item><title>数字集成电路设计实验——流水灯</title><link>https://blog.laning.org/posts/wp-0173/</link><pubDate>Mon, 27 Mar 2023 00:56:00 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0173/</guid><description>&lt;h1 id="1-课程信息"&gt;1. 课程信息&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;实验地点&lt;/strong&gt;：******&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;**实验时间：**2021.03.25&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;实验时长:&lt;/strong&gt; 3小时（4节课）&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1 id="2-实验要求"&gt;2. 实验要求&lt;/h1&gt;
&lt;p&gt;驱动板上LED1 ~LED8按如下2个模式循环闪烁：&lt;/p&gt;
&lt;p&gt;① 每个灯亮1s灭1s，从右至左依次闪烁，共8次&lt;/p&gt;
&lt;p&gt;② 每个灯亮1s灭0.5s，从左至右间隔闪烁，共4次&lt;/p&gt;
&lt;p&gt;思考（加分项）：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;如何使用按键控制流水灯的闪烁时间？&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如：按一次亮1s，再按一次变为亮0.5s。&lt;/p&gt;
&lt;p&gt;2. 如何使用按键控制流水模式？&lt;/p&gt;
&lt;p&gt;如：按一次8个灯依次闪烁，再按一次LED2/4/6/8间隔闪烁&lt;/p&gt;
&lt;h1 id="3-设计与实现"&gt;3. 设计与实现&lt;/h1&gt;
&lt;h2 id="31-实验步骤"&gt;3.1 实验步骤&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;在Vivado中创建工程，并添加.v文件&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;阅读实验提供的源码文件并完善部分代码&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;添加testbeach文件，做仿真分析&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;添加.xdc文件（将模块引脚与开发板引脚绑定），并下板验证&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="32-电路功能说明"&gt;3.2 电路功能说明&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;（包括各个模块功能、关键代码分析，可以使用文字、框图、功能表、状态图等进行说明）&lt;/em&gt;&lt;/p&gt;
&lt;h3 id="321-关键代码分析"&gt;3.2.1 关键代码分析&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;计数器模块
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
counter1 &amp;lt;= 32&amp;#39;d0;
else if(!led_control)//led_control==0为状态1
if (counter1 &amp;lt; 32&amp;#39;d200_000_000)//系统时钟100M，计数器计200M次即2s
counter1 &amp;lt;= counter1 + 1&amp;#39;b1;
else
counter1 &amp;lt;= 32&amp;#39;d0;
else
counter1 &amp;lt;= 32&amp;#39;d0; //状态2时，counter1置零不计数
end
//通过led_control信号来控制计数器2秒或1.5秒,并分别记为counter1和counter2
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;模式控制模块
always @ (posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
cnt&amp;lt;=32&amp;#39;d0;
else if(cnt&amp;lt;32&amp;#39;d2200_000_000)
cnt&amp;lt;=cnt+1;
else
cnt&amp;lt;=0;
end
//cnt计数器来记录一轮循环，cnt&amp;lt;1600_000_000,即小于16秒为左移，cnt&amp;gt;1600_000_000时为右移。
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;led移动
always @(posedge sys_clk or negedge sys_rst_n) begin
if(!sys_rst_n)
led1&amp;lt;=8&amp;#39;b00000001;
else if (!led_control) begin
if (counter1 == 32&amp;#39;d200_000_000)
led1 &amp;lt;= led1&amp;lt;&amp;lt;1; //左移1位
else
led1 &amp;lt;= led1;
end
else led1 &amp;lt;= 8&amp;#39;b00000001;//状态2时led1就在led2基础上左移，状态转换时即可无缝衔接
end
always @(posedge sys_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
led &amp;lt;= 8&amp;#39;b00000001;
else case (led_control)
0 : if(counter1 &amp;lt; 32&amp;#39;d100_000_000) led = led1; else led = 8&amp;#39;b0; //进入状态1时，先让灯亮1s，再将移位寄存器led1的值赋值给led
1 : if(counter2 &amp;lt; 32&amp;#39;d100_000_000) led = led2; else led = 8&amp;#39;b0; //进入状态2时，先让灯亮1s，再将移位寄存器led2的值赋值给led
default : led &amp;lt;= led;
endcase
end
//分别用led1和led2来表示两种状态下的led状态，led_control为0时，当达到2秒时，led1进行左移。通过counter1的值判断是否达到1秒，未达到时，将led1的值赋给led，否则led置为8’b0。led_control为1同理
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="322-系统级表示"&gt;3.2.2 系统级表示&lt;/h3&gt;
&lt;p&gt;&lt;img alt="流水灯系统功能框图" loading="lazy" src="https://blog.laning.org/images/2023-03-27-%E6%95%B0%E5%AD%97%E9%9B%86%E6%88%90%E7%94%B5%E8%B7%AF%E8%AE%BE%E8%AE%A1%E5%AE%9E%E9%AA%8C%E2%80%94%E2%80%94%E6%B5%81%E6%B0%B4%E7%81%AF/%E6%B5%81%E6%B0%B4%E7%81%AF%E7%B3%BB%E7%BB%9F%E5%8A%9F%E8%83%BD%E6%A1%86%E5%9B%BE.jpg"&gt;&lt;/p&gt;</description></item><item><title>GPU在并行信息处理中的应用</title><link>https://blog.laning.org/posts/wp-0116/</link><pubDate>Mon, 19 Dec 2022 16:36:26 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0116/</guid><description>&lt;p&gt;摘要&lt;/p&gt;
&lt;p&gt;随着前端数据采集设备精度的不断提高，对信息处理系统的实时性、准确性提出更高的要求。而从日趋完善的计算机体系结构中，半导体工艺难以取得重大突破的情况下，想要获取更高的计算性能（信息处理能力），我们就必须探索另外一条道路——并行处理。GPU在应用于图像处理领用，其CUDA平台的支持，对于浮点运算的高效，因而作为并行信息处理的技术被广泛应用。&lt;/p&gt;
&lt;p&gt;关键词&lt;/p&gt;
&lt;p&gt;GPU，CUDA ，并行信息处理&lt;/p&gt;
&lt;h3 id="1-并行处理技术"&gt;1. 并行处理技术&lt;/h3&gt;
&lt;h4 id="11-并行处理技术介绍"&gt;1.1 并行处理技术介绍&lt;/h4&gt;
&lt;p&gt;并行处理或并行计算是指利用多台计算机或处理器同时执行运算任务，从而减少解决问题所需要的时间。一般可分为时间并行计算和空间并行计算。&lt;/p&gt;
&lt;p&gt;时间上的并行计算叫做流水线处理，即多个处理器按照处理时间的先后顺序执行计算；空间上的并行是指多个处理器同时执行计算，各处理器在时间上相互独立。并行处理技术主要研究空间上的并行，即通过总线方式将多个计算机或处理器并联，从而获得更快的处理速度。&lt;/p&gt;
&lt;p&gt;并行计算根据规模不同，分为一下几个层次。如图所示，最底层是单核指令级并行（ILP），即单个处理器，但可同时执行多条指令；其上为多核并行，即单芯片拥有多个处理器核心；再往上是多处理器并行，即通过多个芯片之间分工协作做到并行处理；最上层为集群或分布式并行，通过网络互联实现超大规模并行运算，可参考大型数据中心。&lt;/p&gt;
&lt;p&gt;&lt;img alt="并行计算层次结构" loading="lazy" src="https://blog.laning.org/images/2022-12-19-GPU%E5%9C%A8%E5%B9%B6%E8%A1%8C%E4%BF%A1%E6%81%AF%E5%A4%84%E7%90%86%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8/%E5%B9%B6%E8%A1%8C%E8%AE%A1%E7%AE%97%E5%B1%82%E6%AC%A1%E7%BB%93%E6%9E%84.png"&gt;&lt;/p&gt;
&lt;h4 id="12-flynn计算机体系分类"&gt;1.2 Flynn计算机体系分类&lt;/h4&gt;
&lt;p&gt;1966年，Flynn根据指令流和数据流的多倍性对计算机体系结构进行了分类。分为单指令流单数据流模式（SISD），单指令流多数据流模式（SIMD），多指令流单数据流模式（MISD），多指令流多数据流模式（MIMD）。其中SIMD和MIMD属于并行处理器。&lt;/p&gt;
&lt;p&gt;SIMD和MIMD处理器结构示意图如图所示。SIMD只有一个控制单元，这个控制单元控制多个计算处理单元，这些处理单元共享存储器或信号进行通信。MIMD处理器拥有多个控制单元，每个控制单元控制自己的计算单元，通过共享存储器或信号进行通信。&lt;/p&gt;
&lt;p&gt;&lt;img alt="SIMD与MIMD处理器结构对比" loading="lazy" src="https://blog.laning.org/images/2022-12-19-GPU%E5%9C%A8%E5%B9%B6%E8%A1%8C%E4%BF%A1%E6%81%AF%E5%A4%84%E7%90%86%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8/SIMD%E4%B8%8EMIMD%E5%A4%84%E7%90%86%E5%99%A8%E7%BB%93%E6%9E%84%E5%AF%B9%E6%AF%94.png"&gt;&lt;/p&gt;
&lt;h3 id="2cuda-gpu并行架构"&gt;2.CUDA GPU并行架构&lt;/h3&gt;
&lt;p&gt;CUDA是设备计算统一框架的简称（Compute Unified Device Architecture）。其目的是为了用C语言再GPU上进行编程，而无需关注图形API和GPU编程的知识。它可以运行和访问GPU设备的指令和存储空间，从而可以非常快速入门并且从GPU的并行计算中获利。再此之前，GPGPU编程需要针对特定的处理器，而不是标准的API，不能在不同GPU之间进行移植。在CUDA并行架构中，GPU被当作CPU的协处理器来运作，一些数据并行独立且计算密集的函数适合放入GPU中运行。&lt;/p&gt;
&lt;p&gt;&lt;img alt="CUDA软件架构与GPU计算层次" loading="lazy" src="https://blog.laning.org/images/2022-12-19-GPU%E5%9C%A8%E5%B9%B6%E8%A1%8C%E4%BF%A1%E6%81%AF%E5%A4%84%E7%90%86%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8/CUDA%E8%BD%AF%E4%BB%B6%E6%9E%B6%E6%9E%84%E4%B8%8EGPU%E8%AE%A1%E7%AE%97%E5%B1%82%E6%AC%A1.png"&gt;&lt;/p&gt;
&lt;p&gt;图为CUDA并行架构框图。底层为CUDA的组成部件，其包括：支持CUDA并行计算的GPU、支持CUDA的操作系统内核、用户模式驱动、PTX并行计算指令集。&lt;/p&gt;
&lt;p&gt;在软件层次，CUDA提供了完备的软件开发环境，包括编译器、调试器、性能测评工具及基础库。并且支持C语言编程，从而可以支持其他高级语言，比如Java和Python。CUDA提供了两种编程接口：设备级编程接口和语言集成编程接口。&lt;/p&gt;
&lt;h3 id="3-cuda-硬件原理"&gt;3. CUDA 硬件原理&lt;/h3&gt;
&lt;p&gt;CUDA 硬件基础结构由一组多线程流处理器（SM，Multitreaded Stream Multiprocessors）的单元组成。如图所示，SM中又有多个SP（Stream Processors）负责具体运算。多线程流处理器SM被设计成拥有可以同时执行上百个线程的能力。为了获得同时执行这么多线程的能力，CUDA从SIMD结构上发展出单指令流多线程（SIMT, Single Instruction Multiple Thread）结构。&lt;/p&gt;
&lt;p&gt;&lt;img alt="GPU流多处理器SM与SP结构" loading="lazy" src="https://blog.laning.org/images/2022-12-19-GPU%E5%9C%A8%E5%B9%B6%E8%A1%8C%E4%BF%A1%E6%81%AF%E5%A4%84%E7%90%86%E4%B8%AD%E7%9A%84%E5%BA%94%E7%94%A8/GPU%E6%B5%81%E5%A4%9A%E5%A4%84%E7%90%86%E5%99%A8SM%E4%B8%8ESP%E7%BB%93%E6%9E%84.png"&gt;&lt;/p&gt;
&lt;p&gt;SM多线程处理器负责创建、调度和执行线程，这些线程以32个为一组，成为一个Warp。组成同一个Warp的单独线程从同一个程序地址执行。但是他们拥有单独的指令地址计数器和独立的存储器。所以他们可以互不干扰的运行各自的指令及分支。&lt;/p&gt;
&lt;p&gt;当多线程处理器执行一个或多个线程块时，它把他们分为独立的Warp，之后由Warp调度器进行调度。线程块中的线程根据线程号线性的分组为Warp，即前32个线程号的线程为第一个Warp，接下来32个线程号为第二个Warp，以此类推。一个Warp内的线程每次执行一条指令，所以如果Warp里的32个线程在执行时执行相同的指令路径可以使效率最大化。如果一个Warp中的线程在执行过程中产生了分支，则Warp顺序执行完每个分支，直到所有分支都执行完毕后会和到同一个指令开始执行。不同的Warp各自独立运行，在一个Warp内产生的分支不影响其他的Warp。对于一个特定的线程块，它只能在一个多线程处理器（SM）中执行。但是一个多线程处理器可以执行多个线程块。&lt;/p&gt;</description></item><item><title>FPGA工程应用开发综合实验报告二</title><link>https://blog.laning.org/posts/wp-0148/</link><pubDate>Mon, 19 Dec 2022 00:31:00 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0148/</guid><description>&lt;p&gt;&lt;strong&gt;基于FPGA的BPSK信号产生器设计&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2022年12月19日&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;摘 要&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;本次基于FPGA的计时器设计，在熟悉Quartus基本操作、Verilog编程语言的基本规则、SignalTap的基本应用，在前两次PN码序列产生器和DDS设计的基础上，通过分模块设计后进行连接的方式，完成基于FPGA的BPSK信号产生器设计。&lt;/p&gt;
&lt;p&gt;本次设计分为PLL分频模块、自动复位模块、PN码生成模块、DDS模块以及IP核实现方式的NCO模块。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;实验需求分析&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;技术指标分析&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;功能指标分析&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;PN码（Gold码）产生器模块需对传输数据进行扩频；DDS模块生成所需频率的载波信号；通过相位选择法（2选1数据选择器）来实现调制。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;性能指标分析&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;减少信息传输延迟，调制后的信号应尽量与原数据一致。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;系统方案设计&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;顶层设计&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;项目实现所要用到的时钟问题分析&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;时钟频率控制是FPGA设计的重要组成部分。通过上面功能指标分析，我们不难发现，实现BPSK的调制，我们需要三个时钟来完成我们的设计。一是我们需要一个时钟来控制我们的DDS模块来产生我们需要的频率的载波信号；二是我们需要一个时钟来控制PN码（Gold）码的产生；三是我们需要一个调制信息的时钟&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DDS的两种实现&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;我们通过调用IP核和查找表法两种方法实现DDS。调用IP的好处在于设计简单，但其中的延迟为随机确定的数，在设计未完成前，我们很难确定其值为多少，而当通过查找表来实现DDS，我们能够很好的控制这个延迟，从而提升系统的性能。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PN码序列生成器&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;将两个PN码进行异或运算（模2加法）生成Gold码。&lt;/p&gt;
&lt;p&gt;具体顶层设计文件截图：&lt;/p&gt;
&lt;p&gt;&lt;img alt="BPSK信号产生器顶层设计" loading="lazy" src="https://blog.laning.org/images/2022-12-19-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%BA%8C/BPSK%E4%BF%A1%E5%8F%B7%E4%BA%A7%E7%94%9F%E5%99%A8%E9%A1%B6%E5%B1%82%E8%AE%BE%E8%AE%A1.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="BPSK信号产生器模块连接" loading="lazy" src="https://blog.laning.org/images/2022-12-19-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%BA%8C/BPSK%E4%BF%A1%E5%8F%B7%E4%BA%A7%E7%94%9F%E5%99%A8%E6%A8%A1%E5%9D%97%E8%BF%9E%E6%8E%A5.png"&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;模块设计&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;例如：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;1）PLL分频模块&lt;/p&gt;
&lt;p&gt;由上文中对系统时钟分析可知，我们需要250MHz 、5MHz、10KHz分别作为DDS系统钟、PN码生成器码钟和产生调制信息的码钟，如图1所示：&lt;/p&gt;
&lt;p&gt;&lt;img alt="PLL多路时钟分频模块" loading="lazy" src="https://blog.laning.org/images/2022-12-19-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%BA%8C/PLL%E5%A4%9A%E8%B7%AF%E6%97%B6%E9%92%9F%E5%88%86%E9%A2%91%E6%A8%A1%E5%9D%97.png"&gt;&lt;/p&gt;
&lt;p&gt;图1 PLL模块&lt;/p&gt;
&lt;p&gt;2）自动复位模块&lt;/p&gt;
&lt;p&gt;本模块接收PLL分频后所得的250MHz时钟信号，如图2：&lt;/p&gt;
&lt;p&gt;&lt;img alt="系统自动复位模块" loading="lazy" src="https://blog.laning.org/images/2022-12-19-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%BA%8C/%E7%B3%BB%E7%BB%9F%E8%87%AA%E5%8A%A8%E5%A4%8D%E4%BD%8D%E6%A8%A1%E5%9D%97.png"&gt;&lt;/p&gt;
&lt;p&gt;图2 自动复位模块&lt;/p&gt;
&lt;p&gt;3）PN码生成器模块&lt;/p&gt;
&lt;p&gt;本模块接收250MHz的c0和5MHz的c1，如图3：&lt;/p&gt;
&lt;p&gt;&lt;img alt="PN码生成器模块" loading="lazy" src="https://blog.laning.org/images/2022-12-19-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%BA%8C/PN%E7%A0%81%E7%94%9F%E6%88%90%E5%99%A8%E6%A8%A1%E5%9D%97.png"&gt;&lt;/p&gt;
&lt;p&gt;图3 PN码生成器模块&lt;/p&gt;
&lt;p&gt;&lt;img alt="m序列移位寄存器结构" loading="lazy" src="https://blog.laning.org/images/2022-12-19-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%BA%8C/m%E5%BA%8F%E5%88%97%E7%A7%BB%E4%BD%8D%E5%AF%84%E5%AD%98%E5%99%A8%E7%BB%93%E6%9E%84.png"&gt;&lt;/p&gt;
&lt;p&gt;图5.1023位m序列产生器原理框图&lt;/p&gt;
&lt;p&gt;如图5：为1023位m序列产生器的原理图，&lt;/p&gt;
&lt;p&gt;{a&lt;sub&gt;n&lt;/sub&gt;}=c&lt;sub&gt;1&lt;/sub&gt;a&lt;sub&gt;n-1&lt;/sub&gt;+c&lt;sub&gt;2&lt;/sub&gt;a&lt;sub&gt;n-2&lt;/sub&gt;+……+c&lt;sub&gt;n&lt;/sub&gt;a&lt;sub&gt;0&lt;/sub&gt;&lt;/p&gt;
&lt;p&gt;由于m序列自相关良好但是互相关特性不好且可用于产生&lt;/p&gt;
&lt;p&gt;&lt;img alt="Gold码生成逻辑图" loading="lazy" src="https://blog.laning.org/images/2022-12-19-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%BA%8C/Gold%E7%A0%81%E7%94%9F%E6%88%90%E9%80%BB%E8%BE%91%E5%9B%BE.png"&gt;&lt;/p&gt;
&lt;p&gt;图6：Gold序列产生原理框图&lt;/p&gt;
&lt;p&gt;m序列的本原多项式较少，在一些要求地址码多的系统钟m序列很难满足要求，因而引入Gold码。产生Gold码序列可以将两个m序列的移位寄存器并联再进行模2加法，如图6为生成Gold码的逻辑图。图7为顶层文件的Gold码实现。&lt;/p&gt;
&lt;p&gt;&lt;img alt="Gold码顶层电路实现" loading="lazy" src="https://blog.laning.org/images/2022-12-19-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%BA%8C/Gold%E7%A0%81%E9%A1%B6%E5%B1%82%E7%94%B5%E8%B7%AF%E5%AE%9E%E7%8E%B0.png"&gt;&lt;/p&gt;
&lt;p&gt;图7：生成Gold码的顶层文件&lt;/p&gt;
&lt;p&gt;4）DDS模块&lt;/p&gt;
&lt;p&gt;本模块接收c0和频率控制字作为输入，32位相位信息作为输出，结构如图8所示：&lt;/p&gt;
&lt;p&gt;&lt;img alt="DDS相位累加器模块" loading="lazy" src="https://blog.laning.org/images/2022-12-19-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%BA%8C/DDS%E7%9B%B8%E4%BD%8D%E7%B4%AF%E5%8A%A0%E5%99%A8%E6%A8%A1%E5%9D%97.png"&gt;&lt;/p&gt;
&lt;p&gt;图8：DDS模块&lt;/p&gt;
&lt;p&gt;由DDS原理我们可知：K=f&lt;sub&gt;0&lt;/sub&gt;/f&lt;sub&gt;c&lt;/sub&gt;*2&lt;sup&gt;N&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;其中f&lt;sub&gt;c&lt;/sub&gt;为250MHz，f&lt;sub&gt;0&lt;/sub&gt;为25MHz，N为32，计算出K值约为429496730，输出相位信息后，通过查表的方式我们得到最终结果。&lt;/p&gt;
&lt;p&gt;IP核加二选一数据选择器实现方式，如图9所示**：**&lt;/p&gt;
&lt;p&gt;&lt;img alt="DDS波形IP核与数据选择器" loading="lazy" src="https://blog.laning.org/images/2022-12-19-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%BA%8C/DDS%E6%B3%A2%E5%BD%A2IP%E6%A0%B8%E4%B8%8E%E6%95%B0%E6%8D%AE%E9%80%89%E6%8B%A9%E5%99%A8.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;图9：IP核加二选一数据选择器实现&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;二.基于SignalTap分析重点时序&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;本次实验，我们理论上应该看到经过自己设计的DDS模块与调用IP核相比延迟更低。BPSK调制的基本流程如下：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;调制信息与通过PN码发生器进行扩频，通过扩频操作可以降低我们调制信息的峰值，减少信息被检测的概率。&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;DDS模块产生我们所需频率的载波信号，将经过扩频的调制信息通过调相的方式，0和1选择相反相位，即相差为pi的，从而实现BPSK的全过程。&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;三.反思与总结&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1.关于系统时钟c0（250MHz）难以达到&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;因为我们的FPGA的默认时钟频率为50MHz，想要达到250MHz对我们开发板有一些困难，所以我们可以适当降低c0的时钟频率，比如可以选择200MHz作为系统时钟。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2.总结反思&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;本次基于FPGA的BPSK设计实验，从了解PN码这种扩频通信的理念，到通过查找表的方式，实现直接数字频率合成技术，得到我们所需频率的载波信号，到最后通过调相的方式，将我们的信号调制到载波信号钟，从而实现BPSK。进一步熟悉了FPGA开发的整体流程以及模块化的复用思想，了解数字通信调制信息的过程。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;四.参考文献&lt;/strong&gt;&lt;/p&gt;</description></item><item><title>FPGA工程应用开发综合实验报告一</title><link>https://blog.laning.org/posts/wp-0122/</link><pubDate>Wed, 30 Nov 2022 00:28:28 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0122/</guid><description>&lt;p&gt;基于LCD的显示系统设计&lt;/p&gt;
&lt;p&gt;2022年11月30日&lt;/p&gt;
&lt;p&gt;摘 要&lt;br&gt;
本次基于FPGA的LCD显示系统设计，在熟悉Quartus基本操作、Verilog编程语言的基本规则、SignalTap的基本应用后，通过自顶向下、分模块设计后进行连接的方式，完成控制FPGA在LCD屏幕显示内容。&lt;br&gt;
本次设计分为PLL分频模块、上电复位模块、显示控制模块、显示驱动模块组成。通过分功能分模块的设计方式，便于调试，较好地完成了本次设计任务。&lt;/p&gt;
&lt;p&gt;一、 实验需求分析&lt;br&gt;
技术指标分析&lt;br&gt;
（1） 功能指标分析&lt;br&gt;
通过FPGA控制LCD，实现在LCD上显示自己姓名英文书写，对外提供良好的接口，可实现修改源代码来显示不同内容。&lt;br&gt;
（2） 性能指标分析&lt;/p&gt;
&lt;p&gt;二、 系统方案设计&lt;br&gt;
顶层设计&lt;br&gt;
图1：Cyclone IV E FPGA芯片和 LCD模块间连接示意图&lt;/p&gt;
&lt;p&gt;&lt;img alt="Cyclone-IV与LCD模块连接示意" loading="lazy" src="https://blog.laning.org/images/2022-11-30-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%B8%80/Cyclone-IV%E4%B8%8ELCD%E6%A8%A1%E5%9D%97%E8%BF%9E%E6%8E%A5%E7%A4%BA%E6%84%8F.png"&gt;&lt;/p&gt;
&lt;p&gt;表1：LCD模块引脚配置说明&lt;/p&gt;
&lt;p&gt;&lt;img alt="LCD模块引脚配置表" loading="lazy" src="https://blog.laning.org/images/2022-11-30-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%B8%80/LCD%E6%A8%A1%E5%9D%97%E5%BC%95%E8%84%9A%E9%85%8D%E7%BD%AE%E8%A1%A8.png"&gt;&lt;/p&gt;
&lt;p&gt;分析图1、表1，我们能得到FPGA与LCD模块之间是8根数据线、5根控制线，为了简化我们程序内部的逻辑，经过分析，在本次实验中，我们只对LCD进行写操作，而误差控制我们通过增大每次写数据后的延时来减小，所以LCD_RW可以始终置0；LCD_ON始终置1；LCD_BLON可始终置1或0。&lt;br&gt;
进而我们得到了下面的顶层设计&lt;/p&gt;
&lt;p&gt;&lt;img alt="LCD显示系统顶层框图" loading="lazy" src="https://blog.laning.org/images/2022-11-30-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%B8%80/LCD%E6%98%BE%E7%A4%BA%E7%B3%BB%E7%BB%9F%E9%A1%B6%E5%B1%82%E6%A1%86%E5%9B%BE.png"&gt;&lt;/p&gt;
&lt;p&gt;三、 模块设计&lt;br&gt;
例如：&lt;br&gt;
1）PLL分频模块&lt;br&gt;
由于实验板载FPGA提供50MHz晶振，通过Quartus自带的PLL模块，为了更快实现在LCD上显示所需内容，设置参数，产生50MHz的时钟，作为本次设计的系统时钟，如图1所示：&lt;/p&gt;
&lt;p&gt;&lt;img alt="PLL系统时钟模块" loading="lazy" src="https://blog.laning.org/images/2022-11-30-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%B8%80/PLL%E7%B3%BB%E7%BB%9F%E6%97%B6%E9%92%9F%E6%A8%A1%E5%9D%97.png"&gt;&lt;/p&gt;
&lt;p&gt;图1 PLL模块&lt;/p&gt;
&lt;p&gt;2）上电复位模块&lt;br&gt;
本模块接收PLL分频后所得的50MHz时钟信号，通过Cont变量进行计数计时，便于后续模块使用，框图如图2：&lt;/p&gt;
&lt;p&gt;&lt;img alt="上电复位模块" loading="lazy" src="https://blog.laning.org/images/2022-11-30-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%B8%80/%E4%B8%8A%E7%94%B5%E5%A4%8D%E4%BD%8D%E6%A8%A1%E5%9D%97.png"&gt;&lt;/p&gt;
&lt;p&gt;图2 计数器模块&lt;br&gt;
3）显示驱动模块&lt;br&gt;
本模块接收系统时钟与上电复位模块输出以及显示控制模块的输出mLCD_Done；产生mLCD_Start信号、8位数据线内容和LCD_RS信号,如图3所示：&lt;/p&gt;
&lt;p&gt;&lt;img alt="LCD显示驱动模块" loading="lazy" src="https://blog.laning.org/images/2022-11-30-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%B8%80/LCD%E6%98%BE%E7%A4%BA%E9%A9%B1%E5%8A%A8%E6%A8%A1%E5%9D%97.png"&gt;&lt;/p&gt;
&lt;p&gt;图3 显示驱动模块&lt;/p&gt;
&lt;p&gt;在此显示之前，我们需要位LCD进行初始化操作，分析图4，我们需要配置LCD的基本功能，具体代码与分析如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt="LCD初始化指令代码" loading="lazy" src="https://blog.laning.org/images/2022-11-30-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%B8%80/LCD%E5%88%9D%E5%A7%8B%E5%8C%96%E6%8C%87%E4%BB%A4%E4%BB%A3%E7%A0%81.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="LCD控制指令功能表" loading="lazy" src="https://blog.laning.org/images/2022-11-30-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%B8%80/LCD%E6%8E%A7%E5%88%B6%E6%8C%87%E4%BB%A4%E5%8A%9F%E8%83%BD%E8%A1%A8.png"&gt;&lt;/p&gt;
&lt;p&gt;图4 1602LCD控制指令&lt;br&gt;
有限状态机分析（如图5）：&lt;br&gt;
S0：写内容，将数据内容送给数据线，并自动跳转状态S1；&lt;br&gt;
S1：等待mLCD_done信号，有效时跳转到状态S2；&lt;br&gt;
S2：计数延时，为了简化程序，我们通过延迟来保证数据正确写入到LCD中，当延时结束，计数归零，并跳转到状态S3；&lt;br&gt;
S3：当S2的延时后，S3在LCD显示屏上自动向后移位，并跳转到状态S0&lt;/p&gt;
&lt;p&gt;&lt;img alt="LCD显示驱动有限状态机" loading="lazy" src="https://blog.laning.org/images/2022-11-30-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%B8%80/LCD%E6%98%BE%E7%A4%BA%E9%A9%B1%E5%8A%A8%E6%9C%89%E9%99%90%E7%8A%B6%E6%80%81%E6%9C%BA.png"&gt;&lt;/p&gt;
&lt;p&gt;图5 有限状态机示意图&lt;br&gt;
由编码表找到需要的字符对应的二进制表示，代码如下，映射表如图6：&lt;/p&gt;
&lt;p&gt;&lt;img alt="LCD显示字符编码代码" loading="lazy" src="https://blog.laning.org/images/2022-11-30-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%B8%80/LCD%E6%98%BE%E7%A4%BA%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81%E4%BB%A3%E7%A0%81.png"&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="LCD字符编码映射表" loading="lazy" src="https://blog.laning.org/images/2022-11-30-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%B8%80/LCD%E5%AD%97%E7%AC%A6%E7%BC%96%E7%A0%81%E6%98%A0%E5%B0%84%E8%A1%A8.png"&gt;&lt;/p&gt;
&lt;p&gt;图6 字符映射表&lt;br&gt;
4）显示控制模块&lt;br&gt;
本模块接收系统时钟与上电复位模块输出以及mLCD_start作为输入，输出为LCD_EN与mLCD_done信号，如图7：&lt;/p&gt;
&lt;p&gt;&lt;img alt="LCD显示控制模块" loading="lazy" src="https://blog.laning.org/images/2022-11-30-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%B8%80/LCD%E6%98%BE%E7%A4%BA%E6%8E%A7%E5%88%B6%E6%A8%A1%E5%9D%97.png"&gt;&lt;/p&gt;
&lt;p&gt;图7 显示控制模块&lt;/p&gt;
&lt;p&gt;&lt;img alt="LCD显示控制有限状态机" loading="lazy" src="https://blog.laning.org/images/2022-11-30-FPGA%E5%B7%A5%E7%A8%8B%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E7%BB%BC%E5%90%88%E5%AE%9E%E9%AA%8C%E6%8A%A5%E5%91%8A%E4%B8%80/LCD%E6%98%BE%E7%A4%BA%E6%8E%A7%E5%88%B6%E6%9C%89%E9%99%90%E7%8A%B6%E6%80%81%E6%9C%BA.png"&gt;&lt;/p&gt;</description></item><item><title>Python正则化</title><link>https://blog.laning.org/posts/wp-0102/</link><pubDate>Fri, 08 Jul 2022 10:42:23 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0102/</guid><description>&lt;h3 id="python正则化"&gt;Python正则化&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;符号&lt;/th&gt;
&lt;th&gt;解释&lt;/th&gt;
&lt;th&gt;示例&lt;/th&gt;
&lt;th&gt;说明&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;.&lt;/td&gt;
&lt;td&gt;匹配任意字符&lt;/td&gt;
&lt;td&gt;b.t&lt;/td&gt;
&lt;td&gt;可以匹配bat / but / b#t / b1t等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\w&lt;/td&gt;
&lt;td&gt;匹配字母/数字/下划线&lt;/td&gt;
&lt;td&gt;b\wt&lt;/td&gt;
&lt;td&gt;可以匹配bat / b1t / b_t等 但不能匹配b#t&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\s&lt;/td&gt;
&lt;td&gt;匹配空白字符（包括\r、\n、\t等）&lt;/td&gt;
&lt;td&gt;love\syou&lt;/td&gt;
&lt;td&gt;可以匹配love you&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\d&lt;/td&gt;
&lt;td&gt;匹配数字&lt;/td&gt;
&lt;td&gt;\d\d&lt;/td&gt;
&lt;td&gt;可以匹配01 / 23 / 99等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\b&lt;/td&gt;
&lt;td&gt;匹配单词的边界&lt;/td&gt;
&lt;td&gt;\bThe\b&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;^&lt;/td&gt;
&lt;td&gt;匹配字符串的开始&lt;/td&gt;
&lt;td&gt;^The&lt;/td&gt;
&lt;td&gt;可以匹配The开头的字符串&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$&lt;/td&gt;
&lt;td&gt;匹配字符串的结束&lt;/td&gt;
&lt;td&gt;.exe$&lt;/td&gt;
&lt;td&gt;可以匹配.exe结尾的字符串&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\W&lt;/td&gt;
&lt;td&gt;匹配非字母/数字/下划线&lt;/td&gt;
&lt;td&gt;b\Wt&lt;/td&gt;
&lt;td&gt;可以匹配b#t / b@t等 但不能匹配but / b1t / b_t等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\S&lt;/td&gt;
&lt;td&gt;匹配非空白字符&lt;/td&gt;
&lt;td&gt;love\Syou&lt;/td&gt;
&lt;td&gt;可以匹配love#you等 但不能匹配love you&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\D&lt;/td&gt;
&lt;td&gt;匹配非数字&lt;/td&gt;
&lt;td&gt;\d\D&lt;/td&gt;
&lt;td&gt;可以匹配9a / 3# / 0F等&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;\B&lt;/td&gt;
&lt;td&gt;匹配非单词边界&lt;/td&gt;
&lt;td&gt;\Bio\B&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[]&lt;/td&gt;
&lt;td&gt;匹配来自字符集的任意单一字符&lt;/td&gt;
&lt;td&gt;[aeiou]&lt;/td&gt;
&lt;td&gt;可以匹配任一元音字母字符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;[^]&lt;/td&gt;
&lt;td&gt;匹配不在字符集中的任意单一字符&lt;/td&gt;
&lt;td&gt;[^aeiou]&lt;/td&gt;
&lt;td&gt;可以匹配任一非元音字母字符&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;*&lt;/td&gt;
&lt;td&gt;匹配0次或多次&lt;/td&gt;
&lt;td&gt;\w*&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+&lt;/td&gt;
&lt;td&gt;匹配1次或多次&lt;/td&gt;
&lt;td&gt;\w+&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;?&lt;/td&gt;
&lt;td&gt;匹配0次或1次&lt;/td&gt;
&lt;td&gt;\w?&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;{N}&lt;/td&gt;
&lt;td&gt;匹配N次&lt;/td&gt;
&lt;td&gt;\w{3}&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;{M,}&lt;/td&gt;
&lt;td&gt;匹配至少M次&lt;/td&gt;
&lt;td&gt;\w{3,}&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;{M,N}&lt;/td&gt;
&lt;td&gt;匹配至少M次至多N次&lt;/td&gt;
&lt;td&gt;\w{3,6}&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;|&lt;/td&gt;
&lt;td&gt;分支&lt;/td&gt;
&lt;td&gt;foo|bar&lt;/td&gt;
&lt;td&gt;可以匹配foo或者bar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(?#)&lt;/td&gt;
&lt;td&gt;注释&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(exp)&lt;/td&gt;
&lt;td&gt;匹配exp并捕获到自动命名的组中&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(?&amp;lt;name&amp;gt;exp)&lt;/td&gt;
&lt;td&gt;匹配exp并捕获到名为name的组中&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(?:exp)&lt;/td&gt;
&lt;td&gt;匹配exp但是不捕获匹配的文本&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(?=exp)&lt;/td&gt;
&lt;td&gt;匹配exp前面的位置&lt;/td&gt;
&lt;td&gt;\b\w+(?=ing)&lt;/td&gt;
&lt;td&gt;可以匹配I&amp;rsquo;m dancing中的danc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(?&amp;lt;=exp)&lt;/td&gt;
&lt;td&gt;匹配exp后面的位置&lt;/td&gt;
&lt;td&gt;(?&amp;lt;=\bdanc)\w+\b&lt;/td&gt;
&lt;td&gt;可以匹配I love dancing and reading中的第一个ing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(?!exp)&lt;/td&gt;
&lt;td&gt;匹配后面不是exp的位置&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(?&amp;lt;!exp)&lt;/td&gt;
&lt;td&gt;匹配前面不是exp的位置&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;*?&lt;/td&gt;
&lt;td&gt;重复任意次，但尽可能少重复&lt;/td&gt;
&lt;td&gt;a.&lt;em&gt;b a.&lt;/em&gt;?b&lt;/td&gt;
&lt;td&gt;将正则表达式应用于aabab，前者会匹配整个字符串aabab，后者会匹配aab和ab两个字符串&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;+?&lt;/td&gt;
&lt;td&gt;重复1次或多次，但尽可能少重复&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;??&lt;/td&gt;
&lt;td&gt;重复0次或1次，但尽可能少重复&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;{M,N}?&lt;/td&gt;
&lt;td&gt;重复M到N次，但尽可能少重复&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;{M,}?&lt;/td&gt;
&lt;td&gt;重复M次以上，但尽可能少重复&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="python对正则表达式的支持"&gt;Python对正则表达式的支持&lt;/h3&gt;
&lt;p&gt;Python提供了re模块来支持正则表达式相关操作，下面是re模块中的核心函数。&lt;/p&gt;</description></item><item><title>Markdown学习笔记</title><link>https://blog.laning.org/posts/wp-0097/</link><pubDate>Sat, 28 May 2022 19:32:57 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0097/</guid><description>&lt;h2 id="什么是markdown"&gt;什么是Markdown？&lt;/h2&gt;
&lt;p&gt;Markdown是一种轻量标记语言，可以转换为HTML文本，Github的README.md一般遵循Markdown语法规范。&lt;/p&gt;
&lt;h2 id="typora编辑器"&gt;Typora编辑器&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Typora支持&lt;em&gt;&lt;strong&gt;跨平台&lt;/strong&gt;&lt;/em&gt;，支持Windows、MacOS、Linux&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Typora支持多种导出模式，可导出为多种PDF、Latex等&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="markdown基本语法"&gt;Markdown基本语法&lt;/h2&gt;
&lt;h3 id="标题"&gt;标题&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;# 标题名&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;#个数表示不同层级标题&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="文字"&gt;文字&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;*内容*或_内容_表示斜体文字&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;**内容**或__内容__表示加粗字体&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;***内容***或__内容___表示斜体加粗字体&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;~~内容~~表示删除线&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;u&amp;gt;内容&amp;lt;/u&amp;gt;表示下划线&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;***或---或___表示分割线&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;==内容==表示高亮&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;H~2~O 下标表示&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;面积 m^2^ 上标表示&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="表情"&gt;表情&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;:smile :china&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="列表"&gt;列表&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;*或+或-创建无序列表&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;1.+空格创建有序列表&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="表格"&gt;表格&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;name | price
:--- | :---:
chicken | 5
coco | 3
&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&amp;lsquo;:&amp;mdash;表示左对齐:&amp;mdash;:表示居中对齐&amp;rsquo;&lt;/p&gt;
&lt;h3 id="引用"&gt;引用&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;&amp;gt; 表示引用&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;支持嵌套引用如&amp;gt;&amp;gt;表示二级引用&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="代码"&gt;代码&lt;/h3&gt;
&lt;pre tabindex="0"&gt;&lt;code&gt;`内容`表示行内代码
&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex="0"&gt;&lt;code&gt;```语言类型 表示代码块
&lt;/code&gt;&lt;/pre&gt;&lt;h3 id="跳转"&gt;跳转&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;[link text](link)为外部跳转&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;[link text](#目的名称)为内部跳转&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;url&amp;gt;表示超链接&lt;/code&gt;&lt;/p&gt;
&lt;h3 id="图片"&gt;图片&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;![link text](link)&lt;/code&gt;&lt;/p&gt;</description></item><item><title>通信协议原理实验</title><link>https://blog.laning.org/posts/wp-0075/</link><pubDate>Sun, 03 Apr 2022 12:45:55 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0075/</guid><description>UESTC计算机通信网P类实验一</description></item><item><title>hello world!</title><link>https://blog.laning.org/posts/wp-0052/</link><pubDate>Tue, 30 Nov 2021 23:27:56 +0800</pubDate><guid>https://blog.laning.org/posts/wp-0052/</guid><description>&lt;pre tabindex="0"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;
void main()
{
printf(&amp;#34;hello world\n&amp;#34;);
return;
}
&lt;/code&gt;&lt;/pre&gt;</description></item></channel></rss>