DDR2 SDRAM(五)初始化
因为DDR2本质上只是更高级的一种SRAM,底层操作原理和SRAM是一样的,所以很多基础的东西就不再赘述了。
一、原理
在初始化之前,DDR2芯片需要先上电,芯片有多个需要提供的电压,其大小和顺序也有要求,这部分算是物理层的,在此不作研究。
在上电稳定之后,还需要等待时钟稳定才能进行操作。
时钟稳定后,开始第一轮对LMR的操作,配置四个(E)MRS,实现激活DLL和DLL复位的功能。
随后进行至少两次自动刷新,再开始第二轮对LMR的操作,配置四个(E)MRS,实现停止DLL复位和退出OCD的功能。
稳定后即完成了初始化,DDR2可以正常工作。
二、模块框图和接口

三、时序图

注意,这些延迟的具体值和数据速率(Data Rate)密切相关,即和串口时钟频率相关,在这里假设串口时钟频率为400MHz(即下图中的-25),那么一个周期就是T=2.5ns,延迟周期数将使用2.5ns计算。

假设容量为8Meg*16*4banks(512Gb),因此dq位宽为16,ba位宽为2,行addr位宽为13,列addr位宽为10。
根据芯片手册的时序图,舍弃部分无用的信号,增添具体信号值,查阅手册得到准确的延时(延时部分内容太多,涉及到的都放在本文末尾),画出更清晰的时序图如下。

其中第三条之后的虚线为系统时钟sys_clk的上升沿,用于输出值的改变;输给DDR2的接口时钟clk&clk_n应当比sys_clk延迟半个周期,用于采样。
这里又遇到了如何生成sys_clk和clk&clk_n的问题,放在后文详述。(又挖坑了)
其中addr总线的具体值描述如下。
EMR(2):不用考虑高温自刷新的问题,全为0即可。
EMR(3):保留,全为0。
EMR_1:此处需要打开DLL功能,所以A0为0;还有两个参数需要关注,A3~A5和A7~A9。前者是关于AL的长度(详见DDR2 SDRAM(二)信号和时序-CSDN博客),后者是OCD校准,在这里为了简化,都设为0。另外,也去掉一些不必要的信号和接口,所以A10为1(关闭dqs_n),A11为0(关闭rdqs)。此处ODT必须禁用。
MR_1:此处需要将DLL复位,所以A8为1,其余全为0。注意复位后要至少200个周期才能读。
MR_2:此处需要停止DLL复位,所以A8为0;A0~A2是突发长度,设为011(8);A4~A6是CAS延迟,根据上文的假设,设为110(6);A9~A11是自动预充电的写恢复时间,本次设计中不打算加入此功能,只需要知道这个时间是tWR,可以通过查表得到,此处为了方便直接设为101(6)。
EMR_2:想要退出OCD校准,要先在此处设置DLL default,即A7~A9都为1。ODT就设为75Ω好了,所以A6为0,A2为1。
EMR_3:此处需要退出OCD校准,A7~A9都为0。
注意:为了提高代码的灵活性,以上提到的参数都应该使用parameter定义。
四、状态机
- 复位撤销后,开始计数,计数到80000时拉高cke并将init_amd设置为NOP。
- 计数到80000+160时,拉高A10选中所有bank,并将init_amd设置为PREC,等待tRPA。
- 将init_amd设置为LM,BA设为10,init_addr设为13’b0,等待tMRD。
- 将init_amd设置为LM,BA设为11,init_addr设为13’b0,等待tMRD。
- 将init_amd设置为LM,BA设为01,init_addr[10]设为1,其余为0,等待tMRD。
- 将init_amd设置为LM,BA设为00,init_addr[8]设为1,其余为0,等待tMRD。
- 拉高A10选中所有bank,并将init_amd设置为PREC,等待tRPA。
- 将init_amd设置为REF,等待tRFC。
- 将init_amd设置为REF,等待tRFC。
- 将init_amd设置为LM,BA设为00,init_addr[2:0]为011,init_addr[6:4]为110,init_addr[11:9]为101,其余为0,等待tMRD。
- 将init_amd设置为LM,BA设为01,init_addr[9:7]为111,init_addr[10]为1,init_addr[2]为1,其余为0,等待tMRD。
- 将init_amd设置为LM,BA设为01,init_addr[10]设为1,init_addr[2]为1,其余为0,等待tMRD。
- 初始化完成。
五、代码实现
/***************************************************************************************
作者:not_lubao
2024-11-1
×××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××××*/// DDR2初始化模块,初始化步骤:上电--延时200us--拉高cke--延时400ns--预充电--寄存器配置--刷新n次--寄存器配置--完成module ddr2_init(
input sys_clk , //系统时钟信号100MHz
input rstn , //系统复位信号output cke , //时钟使能
output [1:0] init_ba , //Bank
output [3:0] init_cmd , //命令
output [12:0] init_addr , //地址
output init_end //初始化结束标志
);/***********************参数************************/
//状态机
parameter IDLE = 6'd0 ,WAIT_IDLE = 6'd1 ,CLK_EN = 6'd2 ,WAIT_CKE = 6'd3 ,P_CHAR = 6'd4 ,WAIT_PREC = 6'd5 ,LM_EMR2 = 6'd6 ,LM_EMR3 = 6'd7 ,LM_EMR_1 = 6'd8 ,LM_MR_1 = 6'd9 ,LM_MR_2 = 6'd10 ,LM_EMR_2 = 6'd11 ,LM_EMR_3 = 6'd12 ,WAIT_LM = 6'd13 ,AUTO_REF = 6'd14 ,WAIT_REF = 6'd15 ,WAIT_DLL_RST = 6'd16 ,END = 6'd17 ;//等待时间 比实际要求最小值多一个周期
parameter T_INIT = 17'd80000 , //上电后等待T_CKE = 17'd160 , //拉高cke后等待T_tRPA = 17'd6 , //充电后等待T_tMRD = 17'd1 , //配置寄存器后等待T_tRFC = 17'd42 , //刷新后等待T_DLL_RST = 17'd110 ; //拉高cke后等待(大于99)//指令
parameter LM = 4'b0000 ,REF = 4'b0001 ,PREC = 4'b0010 ,ACT = 4'b0011 ,WR = 4'b0100 ,RD = 4'b0101 ,NOP = 4'b0111 ;//自刷新次数
parameter REF_TIME = 4'd2 ;//模式寄存器的值
parameter EMR2 = 13'b0 , //不用考虑高温自刷新的问题,全为0EMR3 = 13'b0 , //保留EMR_1 = 13'b0_0010_0000_0000 , //[0]为0(打开DLL功能);[5:3](AL长度)和[9:7](OCD校准)都为0;[10]为1(关闭dqs_n),[11]为0(关闭rdqs);{[6],[2]}为01(ODT=75Ω)MR_1 = 13'b0_0000_1000_0000 , //[8]为1(DLL复位),其余全为0MR_2 = 13'b0_0101_0011_0011 , //[8]为0(停止DLL复位);[2:0]为011(突发长度8);[6:4]为110(CAS延迟6);[11:9]为101(自动预充电的写恢复时间6)EMR_2 = 13'b0_0011_1100_0010 , //[9:7]为111(OCD default);{[6],[2]}为01(ODT=75Ω)EMR_3 = 13'b0_0010_0000_0010 ; //[9:7]为000(退出OCD校准)/* 模式寄存器的具体值受芯片型号影响,以下仅做参考
MR[2:0] : 突发长度 4(010)或8(011)[3] : 突发类型 0(顺序)或1(插入)[6:4] : CAS延迟 010(2)到111(7),一般大于3[7] : 测试模式 0(正常工作)或1(测试)[8] : DLL复位 0(无效)或1(有效)[11:9] : 带自动预充电的写恢复时间 010(2)到111(7),一般大于2[12] : 活跃低功耗模式的退出时间 0(快退出 tXARD)或1(慢退出 tXARDS)EMR[0] : DLL功能 0(开启)或1(关闭)[1] : D.I.C 输出驱动阻抗 0(满强度)或1(降低强度){[6],[2]} : Rtt 00(无效)或01(75Ω)或10(150Ω)或11(50Ω)[5:3] : AL 额外延时 000(0)到110(6),111为保留[9:7] : OCD校准 000(退出)或001(驱动1)或010(驱动0)或100(调整)或111(default)[10] : 差分DQS 0(启用)或1(禁用)[11] : RDQS 0(禁用)或1(启用)[12] : Qoff输出控制 0(启用)或1(禁用),包括DQ/DQS/RDQS
*//***********************寄存器************************/
reg [5:0] r_state, r_next_state ;
reg [16:0] r_latency_T ; //延时长度寄存器
reg [16:0] r_cnt_wait ; //计时计数器值
reg [3:0] r_ref_cnt ; //刷新次数计数
reg [7:0] r_cke_cnt ; //CKE拉高时间计数器reg r_cke ;
reg [1:0] r_init_ba ;
reg [3:0] r_init_cmd ;
reg [12:0] r_init_addr ;
reg r_init_end ;/***********************时序逻辑************************/
always@(posedge sys_clk or negedge rstn) begin //计时器模块if(!rstn)r_cnt_wait <= 17'd0;else if(r_cnt_wait == r_latency_T) //计满自动清零r_cnt_wait <= 17'd0;elser_cnt_wait <= r_cnt_wait +17'd1;
endalways@(posedge sys_clk or negedge rstn) begin //刷新次数计数器if(!rstn)r_ref_cnt <= 4'd0;else if((r_ref_cnt == REF_TIME) && (r_cnt_wait == T_tRFC)) //达到设定刷新次数且本次刷新后等待时间tRFC结束r_ref_cnt <= 4'd0;else if(r_next_state == AUTO_REF) //下一个状态是刷新r_ref_cnt <= r_ref_cnt + 4'd1;elser_ref_cnt <= r_ref_cnt;
end/*各个state持续时间的设定
在切换状态的一瞬间,计数器执行清零操作,目标计数值被重新赋值,这样就实现了延时参数的传递
那样就可以只使用一个计数器*/
always@(posedge sys_clk or negedge rstn) begin if(!rstn)r_latency_T <= 10'd0;elsecase(r_next_state)IDLE : r_latency_T <= 10'd0 ;WAIT_IDLE : r_latency_T <= T_INIT ;CLK_EN : r_latency_T <= 10'd0 ; WAIT_CKE : r_latency_T <= T_CKE ;P_CHAR : r_latency_T <= 10'd0 ;WAIT_PREC : r_latency_T <= T_tRPA ;LM : r_latency_T <= 10'd0 ;WAIT_LM : r_latency_T <= T_tMRD ;AUTO_REF : r_latency_T <= 10'd0 ;WAIT_REF : r_latency_T <= T_tRFC ;WAIT_DLL_RST : r_latency_T <= T_DLL_RST ;END : r_latency_T <= 10'd0 ;default : r_latency_T <= 10'd0 ;endcase
end/***********************组合逻辑************************/
assign cke = r_cke ;
assign init_cmd = r_init_cmd ;
assign init_addr = r_init_addr ;
assign init_ba = r_init_ba ;
assign init_end = r_init_end ;/***********************状态机************************/
always@(posedge sys_clk or negedge rstn) begin//状态转移if(!rstn)r_state <= IDLE;elser_state <= r_next_state;
endalways@(*) begin //状态转移判断模块,根据计时时间判断是否已经持续相应时间长度if(!rstn)r_next_state = IDLE;elsecase(r_state)IDLE :r_next_state = WAIT_IDLE;WAIT_IDLE :if(r_cnt_wait == r_latency_T)r_next_state = CLK_EN;elser_next_state = r_state;CLK_EN :r_next_state = WAIT_CKE;WAIT_CKE :if(r_cnt_wait == r_latency_T)r_next_state = P_CHAR;elser_next_state = r_state;P_CHAR :r_next_state = WAIT_PREC;WAIT_PREC :if(r_cnt_wait == r_latency_T)r_next_state = LM_EMR2;elser_next_state = r_state;LM_EMR2 :r_next_state = WAIT_LM;WAIT_LM :if(r_cnt_wait == r_latency_T)r_next_state = LM_EMR3;elser_next_state = r_state;LM_EMR3 :r_next_state = WAIT_LM;WAIT_LM :if(r_cnt_wait == r_latency_T)r_next_state = LM_EMR_1;elser_next_state = r_state;LM_EMR_1 :r_next_state = WAIT_LM;WAIT_LM :if(r_cnt_wait == r_latency_T)r_next_state = LM_MR_1;elser_next_state = r_state;LM_MR_1 :r_next_state = WAIT_LM;WAIT_LM :if(r_cnt_wait == r_latency_T)r_next_state = P_CHAR;elser_next_state = r_state;P_CHAR :r_next_state = WAIT_PREC;WAIT_PREC :if(r_cnt_wait == r_latency_T)r_next_state = AUTO_REF;elser_next_state = r_state;AUTO_REF :r_next_state = WAIT_REF;WAIT_REF : if((r_ref_cnt == REF_TIME) && (r_cnt_wait == r_latency_T)) //达到设定刷新次数且本次刷新后等待时间tRC结束r_next_state = LM_MR_2;else if(r_cnt_wait == r_latency_T)r_next_state = AUTO_REF;elser_next_state = r_state;LM_MR_2 :r_next_state = WAIT_LM;WAIT_LM :if(r_cnt_wait == r_latency_T)r_next_state = LM_EMR_2;elser_next_state = r_state;LM_EMR_2 :r_next_state = WAIT_LM;WAIT_LM :if(r_cnt_wait == r_latency_T)r_next_state = LM_EMR_3;elser_next_state = r_state;LM_EMR_3 :r_next_state = WAIT_LM;WAIT_LM :if(r_cnt_wait == r_latency_T)r_next_state = WAIT_DLL_RST;elser_next_state = r_state;WAIT_DLL_RST :if(r_cnt_wait == r_latency_T)r_next_state = END;elser_next_state = r_state;END : r_next_state = END;default : r_next_state = IDLE;endcase
endalways@(posedge sys_clk or negedge rstn) begin //输出模块,三段式状态机if(!rstn) beginr_init_cmd <= NOP ;r_init_ba <= 2'b11 ;r_init_addr <= 13'h1fff ;r_init_end <= 1'b0 ;end else case(r_state)IDLE,WAIT_IDLE,WAIT_CKE,WAIT_PREC,WAIT_LM,WAIT_REF,WAIT_DLL_RST : beginr_init_cmd <= NOP ;r_init_ba <= 2'b11 ;r_init_addr <= 13'h1fff ;endCLK_EN : beginr_cke <= 1'b1 ;endP_CHAR : beginr_init_cmd <= PREC ;r_init_ba <= 2'b11 ;r_init_addr <= 13'h1fff ;endLM_EMR2 : beginr_init_cmd <= LM ;r_init_ba <= 2'b10 ;r_init_addr <= EMR2 ;endLM_EMR3 : beginr_init_cmd <= LM ;r_init_ba <= 2'b11 ;r_init_addr <= EMR3 ;endLM_EMR_1 : beginr_init_cmd <= LM ;r_init_ba <= 2'b01 ;r_init_addr <= EMR_1 ;endLM_MR_1 : beginr_init_cmd <= LM ;r_init_ba <= 2'b00 ;r_init_addr <= MR_1 ;endLM_MR_2 : beginr_init_cmd <= LM ;r_init_ba <= 2'b00 ;r_init_addr <= MR_2 ;endLM_EMR_2 : beginr_init_cmd <= LM ;r_init_ba <= 2'b01 ;r_init_addr <= EMR_2 ;endLM_EMR_3 : beginr_init_cmd <= LM ;r_init_ba <= 2'b01 ;r_init_addr <= EMR_3 ;endAUTO_REF : beginr_init_cmd <= REF ;r_init_ba <= 2'b11 ;r_init_addr <= 13'h1fff ;endEND : beginr_init_cmd <= NOP ;r_init_ba <= 2'b11 ;r_init_addr <= 13'h1fff ;r_init_end <= 1'b1 ;enddefault : beginr_init_cmd <= NOP ;r_init_ba <= 2'b11 ;r_init_addr <= 13'h1fff ;endendcase
endendmodule
注:本模块和后续模块不再进行单独仿真,可能会有bug,最终仿真完成会统一修改,然后删掉这句话。
附:延时查找表



相关文章:
DDR2 SDRAM(五)初始化
因为DDR2本质上只是更高级的一种SRAM,底层操作原理和SRAM是一样的,所以很多基础的东西就不再赘述了。 一、原理 在初始化之前,DDR2芯片需要先上电,芯片有多个需要提供的电压,其大小和顺序也有要求,这部分…...
Python工具箱系列(五十七)
图像分割与人脸识别 众所周知图像是由若干有意义的像素组成的,图像分割作为计算机视觉的基础,对具有现有目标和较精确边界的图像进行分割,实现在图像像素级别上的分类任务。图像分割可分为语义分割和实例分割两类,区别如下&#x…...
数据智能驱动金融策略优化:民锋智能分析技术的应用
在现代金融市场中,数据分析与智能化技术的结合为投资策略带来了全新机遇。民锋以智能分析技术为核心,帮助投资者在复杂的市场环境中做出高效决策。本文将深入探讨民锋智能分析技术如何驱动策略优化,为投资者带来更加智能化的支持。 #### 一、…...
1009:带余除法
【题目描述】 给定被除数和除数,求整数商及余数。此题中请使用默认的整除和取余运算,无需对结果进行任何特殊处理。 【输入】 一行,包含两个整数,依次为被除数和除数(除数非零),中间用一个空格隔…...
Jmeter实际应用
环境准备 JDK1.8Jmeter 5.6.3 下载地址Jmeter 插件 下载地址 放到lib/ext下 常用命令 # 启动 sh jmeter# 集群模式下启动节点,不启动用不了集群 sh jmeter-server#生成ssl需要的证书, 这里会要求输入个密码,是要在jmeter中用的 keytool -import -ali…...
C++基础(11.AVL树的实现)
目录 AVL的概念: AVL树的实现: AVL树的结构: AVL树的插⼊: 平衡因⼦更新: 旋转: AVL树的其他功能: AVL树平衡检测: 测试代码*2: 源代码: KV结构: 源代码: AVL…...
c# 抽象方法 虚函数 使用场景
在C#中,抽象方法(abstract method)和虚函数(virtual method)都是用于实现多态性(polymorphism)的重要特性,但它们在使用上有一些关键的区别和各自的用途。 抽象方法(Abs…...
大数据安全方案 验证
一、背景 文档用于记录配置 Kerberos 和 Ranger 后,对 HDFS、Hive 认证和鉴权的功能测试。 二、Kerberos 验证 2.1、验证功能 1,HDFS 认证 2.1.1、访问 HDFS Kerberos 验证前,访问 HDFS 失败。 Kerberos 验证后,访问 HDFS 成…...
电脑软件:推荐一款免费且实用的电脑开关机小工具
目录 一、软件简介 二、软件功能 三、软件特点 四、使用说明 五、软件下载 今天给大家推荐一款免费且实用的电脑开关机小工具KShutdown,有需要的朋友可以下载试一下! 一、软件简介 KShutdown是一款精巧且实用的定时自动关机小工具,对于…...
php反序列化靶场随笔分析
项目地址:github.com/mcc0624/php_ser_Class 推荐使用docker部署:https://hub.docker.com/r/mcc0624/ser/tags 前面讲了以下php基础,我们直接从class6开始实验 class6 访问页面,传一个序列化的字符串,php代码将其反…...
动态规划 - 编辑距离
115. 不同的子序列 困难 给你两个字符串 s 和 t ,统计并返回在 s 的 子序列 中 t 出现的个数,结果需要对 10^9 7 取模。 算法思想:利用动态规划,分s[i - 1] 与 t[j - 1]相等,s[i - 1] 与 t[j - 1] 不相等两种情况具…...
力扣——113. 路径总和
113. 路径总和 II 给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。 叶子节点 是指没有子节点的节点。 示例 1: 输入:root [5,4,8,11,null,13,4,7,2,null,null,5,1], t…...
C02S04-Ubuntu基本使用
一、Ubuntu初始配置 1. 使用root用户 Ubuntu系统默认只能使用普通用户,要想使用root用户,需要先设置root用户密码。 进入终端,配置root用户密码。按照提示输入密码。 sudo passwd root配置完成后,执行下面的密码,切换…...
C语言 | Leetcode C语言题解之第525题连续数组
题目: 题解: struct HashTable {int key, val;UT_hash_handle hh; };int findMaxLength(int* nums, int numsSize) {int maxLength 0;struct HashTable* hashTable NULL;struct HashTable* tmp malloc(sizeof(struct HashTable));tmp->key 0, tm…...
Qml-Transition的使用
Qml-Transition的使用 Transition的概述 Transition:定义了当状态发生改变时应用的动画属性animations : list:(Transition)过渡的动画属性enabled : bool:状态发生变化时,是否使能此过渡(Transition)动画…...
Notepad++检索包含多个关键字的行
Notepad检索包含多个关键字的行 在Notepad中,你可以使用正则表达式来检索包含多个关键字的行。以下是具体步骤: 打开Notepad,打开要搜索的文件。 点击菜单栏上的“搜索”选项,然后选择“查找”。 在弹出的查找对话框中…...
C语言:水仙花树,要求三位以上的N位整数每位的N次方等于数本身,全部输出出来
#include <stdio.h> int main() { int n; scanf("%d",&n);//这里是说明多少n位整数 int first1; int i1; while(i<n){//此while循环可以得到n位数的最小位,例如3位的100. first*10; i; } ifirst; whil…...
金融贷款口子超市V2源码 Thinkphp开发的贷款和超市平台源码(亲测源码含安装视频教程)
金融贷款口子超市V2源码 Thinkphp开发的贷款和超市平台源码 源码下载:https://download.csdn.net/download/m0_66047725/89938268 更多资源下载:关注我。...
redis的三种客户端
在 Redis 中,常用的 Java 客户端有三种:Jedis、Lettuce 和 Redisson。它们各有特点,适用于不同的场景。以下是它们的详细介绍,以及如何在 Spring Boot 中集成 Redis。 一、Redis 三种常用客户端详解 1.1 Jedis Jedis 是 Redis 官…...
边缘计算【智能+安全检测】系列教程--agx orin解决RTC时间问题
因为是离线运行,首要问题是时间不准确,就在主板上加装了纽扣电池,但是会有一系列问题,比如无法将RTC时间回写到系统时间,或者无法将系统时间写到RTC中等等一些列问题。为解决这些问题,一劳永逸的方式&#…...
网络编程(Modbus进阶)
思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...
深度学习在微纳光子学中的应用
深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向: 逆向设计 通过神经网络快速预测微纳结构的光学响应,替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…...
conda相比python好处
Conda 作为 Python 的环境和包管理工具,相比原生 Python 生态(如 pip 虚拟环境)有许多独特优势,尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处: 一、一站式环境管理:…...
Linux链表操作全解析
Linux C语言链表深度解析与实战技巧 一、链表基础概念与内核链表优势1.1 为什么使用链表?1.2 Linux 内核链表与用户态链表的区别 二、内核链表结构与宏解析常用宏/函数 三、内核链表的优点四、用户态链表示例五、双向循环链表在内核中的实现优势5.1 插入效率5.2 安全…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
shell脚本--常见案例
1、自动备份文件或目录 2、批量重命名文件 3、查找并删除指定名称的文件: 4、批量删除文件 5、查找并替换文件内容 6、批量创建文件 7、创建文件夹并移动文件 8、在文件夹中查找文件...
iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版分享
平时用 iPhone 的时候,难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵,或者买了二手 iPhone 却被原来的 iCloud 账号锁住,这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...
LeetCode - 394. 字符串解码
题目 394. 字符串解码 - 力扣(LeetCode) 思路 使用两个栈:一个存储重复次数,一个存储字符串 遍历输入字符串: 数字处理:遇到数字时,累积计算重复次数左括号处理:保存当前状态&a…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
