Step to memory 012 同步存储器中的时钟偏差

https://www.bit-tech.net/reviews/tech/memory/the_secrets_of_pc_memory_part_3/7

同步存储器中的时钟偏差

当越来越多的电路与一个时钟同步时,可能会出现时钟延迟现象。结果,所有数据都无法与正确的时钟关联并准时到达:这种现象通常称为“时钟偏差”

华硕 P5E3 Premium BIOS 中的“AI Clock Skew”选项

时钟偏差可能由多种因素造成,包括路径延长、温度波动、沿该线路添加多个逻辑电路、材料缺陷以及主板上的根本设计缺陷——换句话说,它可能发生在内存系统的许多不同部分。在不同位置消除偏差逻辑将尝试最大限度地减少负面影响,以保持数据和系统时钟之间的一致性关系。然而,随着内存性能的不断提高,并非所有问题都能轻松解决。

发烧友可能更熟悉主板 BIOS 中恰如其名的“Clock Skew”变量,它可以用于在超频计算机内存时获得更高的稳定性,从而解决 DIMM 之间的时钟偏差。不可避免的是,内存性能越高,出现时钟偏差的可能性就越大。

当主板上使用四条内存条而不是两条内存条时,时钟偏差会更加严重,偏差量取决于同时使用哪两条内存条,以及 PCB 的基本设计。

经过大量设计仿真和测试,质量极高的主板通常能够很好地控制时钟偏差问题。然而,由于市场竞争压力巨大,产品生命周期缩短,许多存在缺陷的主板在没有足够测试时间的情况下就过早上市并大肆宣传,之后又在 BIOS 更新中尽可能地进行修补。日益复杂的主板芯片组和更高的内存速度也增加了这方面出现故障的可能性。

单端差分选通到差分选通架构

虽然单端数据选通信号最初用于 DDR1,但 DDR2 是支持单端和差分选通信号的演进转折点。最基本的解释是,单端选通信号依赖于一个振荡波,而差分架构则使用两个相互交织、交叉的反向振荡波。

镁光科技的 Aaron Boehm 强调,“差分时钟和选通信号方案对串扰引起的变化不太敏感”,而对于高速 DDR2 和 DDR3 来说,使用差分设计至关重要,Boehm 解释说,“随着我们不断降低 DRAM 电压并不断提高速度,降低时钟和选通信号对此类噪声的敏感度至关重要。 ”

对于单端选通信号设计,任何少量的噪声和干扰都会导致选通信号沿水平电压阈值(有时也称为参考电压电平)向左或向右偏移。这种水平偏移是有害的,因为它代表了时间的变化,从而导致了时间的不准确性。

存储器依赖于“相交”参考点的稳定性才能可靠地进行读写操作。差分选通脉冲设计更加稳定,因为波形异常只会导致相交中心点上下移动,这代表参考电压 (Vdd/2) 的变化,而不是时序偏移(左移或右移)。波动的电压阈值不如时间偏移严重。

在同步存储器系统中,任何显著的时间偏移都是致命的,因为这意味着数据不再与时钟一致,因此,只有这样的差分信号架构才能保证高速存储器正常工作。

FireBeetle 2 ESP32 P4 USB 速度测试

ESP32 P4 终于开始了量产,可以轻松的在市面上购买到芯片和模块了。
相比之前的型号,这个型号最大的不同是:增加了USB High Speed的支持,这样在 Arduino 开发环境的支持下,

这个芯片可以快捷简单的和PC进行连接,制作出更多的好玩项目。

最近 DFRobot 也推出了对应的 ESP32 P4 开发板:FireBeetle 2 ESP32 P4。笔者有幸拿到一块,这次做一个简单的测试,测试ESP32 P4 的 USB 速度。

FireBeetle 2 ESP32 P4  USB 速度测试图1

可以看到,板子带有2个 TypeC 接口,其中一个是用于下载的接口(来自P4芯片内部),另外一个是可以编程的 TypeC 接口(同样来自P4内部)

FireBeetle 2 ESP32 P4  USB 速度测试图2

开发板上手很简单,使用 Arduino 环境即可。测试的代码是将自身模拟为一个 U盘,上面有一个文件可以用于测试。

代码如下:

#include "USB.h"
#include "USBMSC.h"
#include "256MBDisk.bin.h"

#if ARDUINO_USB_CDC_ON_BOOT
#define HWSerial Serial0
#define USBSerial Serial
#else
#define HWSerial Serial
USBCDC USBSerial;
#endif

USBMSC MSC;

uint32_t findLBA(uint32_t LBA) {
  for (uint16_t i=0; i<415;i++) {
      if (Index[i]==LBA) {
          return i;
        }
    }
  return 0xFFFFFF;  
}
static const uint32_t DISK_SECTOR_COUNT = 520192; 

static int32_t onRead(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize){
  //HWSerial.printf("MSC READ: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize);

  int32_t getLBA=0;
  uint8_t *p;
  p=(uint8_t *)buffer;
  //HWSerial.printf("Buffer1 %X\n", buffer);
  for (uint32_t i=0;i<bufsize/DISK_SECTOR_SIZE;i++) {
     //HWSerial.printf("Check %u\n", lba+i);
     getLBA=findLBA(lba+i);
     //HWSerial.printf("getLBA %u\n", getLBA);
     if (getLBA!=0xFFFFFF) { //如果找到了
        memcpy((void *)&p[i*DISK_SECTOR_SIZE], &msc_disk[getLBA][0], DISK_SECTOR_SIZE);
        //HWSerial.printf("Send %u\n", getLBA);
        //HWSerial.printf("Buffer2 %X\n", (void *)&p[i*DISK_SECTOR_SIZE]);
      } else {
        //HWSerial.printf("Send all zero to %u\n", getLBA);
        for (uint16_t j=0;j<DISK_SECTOR_SIZE;j++) {
              p[i*DISK_SECTOR_SIZE+j]=0;
          }
          
      }
    }
  return bufsize;
}

static bool onStartStop(uint8_t power_condition, bool start, bool load_eject){
  HWSerial.printf("MSC START/STOP: power: %u, start: %u, eject: %u\n", power_condition, start, load_eject);
  return true;
}

static void usbEventCallback(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data){
  if(event_base == ARDUINO_USB_EVENTS){
    arduino_usb_event_data_t * data = (arduino_usb_event_data_t*)event_data;
    switch (event_id){
      case ARDUINO_USB_STARTED_EVENT:
        HWSerial.println("USB PLUGGED");
        break;
      case ARDUINO_USB_STOPPED_EVENT:
        HWSerial.println("USB UNPLUGGED");
        break;
      case ARDUINO_USB_SUSPEND_EVENT:
        HWSerial.printf("USB SUSPENDED: remote_wakeup_en: %u\n", data->suspend.remote_wakeup_en);
        break;
      case ARDUINO_USB_RESUME_EVENT:
        HWSerial.println("USB RESUMED");
        break;
      
      default:
        break;
    }
  }
}

static int32_t onWrite(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize){
  HWSerial.printf("MSC WRITE: lba: %u, offset: %u, bufsize: %u\n", lba, offset, bufsize);
  return bufsize;
}
void setup() {
  HWSerial.begin(115200);
  HWSerial.setDebugOutput(true);

  USB.onEvent(usbEventCallback);
  MSC.vendorID("ESP32");//max 8 chars
  MSC.productID("USB_MSC");//max 16 chars
  MSC.productRevision("1.0");//max 4 chars
  MSC.onStartStop(onStartStop);
  MSC.onRead(onRead);
  MSC.onWrite(onWrite);
  MSC.mediaPresent(true);
  MSC.begin(DISK_SECTOR_COUNT, DISK_SECTOR_SIZE);
  USBSerial.begin();
  USB.begin();
}

void loop() {
  // put your main code here, to run repeatedly:
}

需要特别注意

1.选择 TinyUSB

FireBeetle 2 ESP32 P4  USB 速度测试图3

2.型号使用 P4

FireBeetle 2 ESP32 P4  USB 速度测试图4

连接板卡上方 TypeC 即可烧录, 然后连接右侧的TypeC,系统中会出现一个U盘

FireBeetle 2 ESP32 P4  USB 速度测试图5

测试显示速度可以稳定在 10MB/S 左右。

FireBeetle 2 ESP32 P4  USB 速度测试图6

之前的 ESP32 S2/S3 同样代码最高速度在 750KB/S 左右。相比之下速度提升了 13倍。

完整的代码在【参考1】可以看到

参考:
1.https://www.lab-z.com/fakeud/  ESP32 S2 上实现假U盘(ESP32 2.0.1 )
2.https://mc.dfrobot.com.cn/thread-309859-1-1.html  ESP32 S2 做一个假U盘

Step to memory 011 第二代DDR内存:DDR2

https://www.bit-tech.net/reviews/tech/memory/the_secrets_of_pc_memory_part_3/5

DDR2 台式机模块由 240 针连接接口组成。

JEDEC 定义的 DDR2 工作电压为 1.8V,然而,一些厂商生产的高性能模块可在高达 2.4V 的电压下运行,并且仍然提供保修。与之相反,一些廉价模块缺乏良好的散热,为了长期可靠的运行,需要主动降低电压。

我们最近就更高的 DRAM 电压及其对寿命的影响向镁光科技计算部门高级市场经理 Brett Williams 进行了咨询。例如,我们询问了一个典型的 2.0V 电压运行的内存模块;“ [它] 的寿命实际上会比 1.8V 模块短。现在,当我说‘寿命短’时……这可能会或可能不会成为您的顾虑。在 1.8V 电压下,该模块可能可以使用长达 200 年。在 2.0V 电压下,它可能可以使用长达 10 年。但您的系统很可能会在三到五年后就被丢弃:更换内存或升级。 ”

JEDEC 规定 DDR2的最高工作频率是 800MHz,因此超过 800MHz 的速度被认为超出了行业标准,需要主板特别支持。

需要注意的是,JEDEC 规范更关注“安全”冗余度。这是为了让所有的符合 JEDEC 标准的 RAM 能够适配最广泛的主板和芯片组,因此JEDEC DDR 标准更多地关注信号可靠性而非内存速度。

以瓦特/千兆字节/秒为单位的功率与吞吐量比的提高是一个积极的趋势,但许多 DDR2 台式机主板(BIOS)和内存(SPD)在出厂时就已预编程为在 1.85V 至 1.95V 的电压下运行,以应对更广泛的稳定性问题。

值得一提的是,镁光公司推出的一类特殊 1,066MHz DDR2 DRAM 原生电压为 1.8V,但仍符合 JEDEC 的要求。通常只有 800MHz 内存的额定电压为 1.8V,但这是 DDR2 市场上唯一一款原生 1,066MHz DRAM,因此特别适合以 1,066MHz 内存速度运行并可超频的 AMD 新款 Phenom CPU。Brett Williams 解释了美光公司如何通过“大幅提升利润率”实现这一目标。他告诉我们,美光公司的 D9 基本上采用了比许多竞争对手更先进的制造工艺:美光公司采用 78nm 工艺,而其他公司采用 95nm 工艺。“正是工艺和设计技术的结合,帮助美光公司实现了更高的内存频率,同时保持了最宽的信号传输裕度。 ”镁光科技的 Kirstin Bordner 为我们提供了需要注意的 D9 特定标识符,这些标识符指示 1.8V 1,066MHz DRAM。

  • D9HCD MT47H64M8B6-25:D
  • D9GKX MT47H64M8B6-25E:D
  • D9GMH MT47H64M8B6-3:D

对称 T 型分支拓扑

PC 内存的秘密:第 3 部分

https://www.bit-tech.net/reviews/tech/memory/the_secrets_of_pc_memory_part_3/6

DDR2 与 DDR1 共享类似的架构,称为 T-Branch 拓扑。然而,DDR2 与上一代产品的不同之处在于它采用了对称设计。因此,每个 DRAM 芯片的命令、地址和时钟总线完全均衡,从而提高了高频信号的质量,因为更好的对称性可以降低信号抖动。

这种设计在减少 SDR 和 DDR1 总线拓扑中常见的非单调性信号(non-monotonic signal behaviour)行为方面取得了重大改进。

LAB-Z注释:非单调性(non monotonic)问题指的是信号在上升过程中出现了部分下降的情况【参考1】

绝大多数非单调性都是由复杂的信号拓扑造成的。在一个CPU或DSP的本地总线上,非单调性问题最常见。非单调性按表现形式可以分为两种:回钩和台阶。

     对于一个沿有效的时钟来说,信号沿上的回钩和台阶是致命的。因为一个非单调性的时钟沿,可能被接收端认作多个有效沿,或在器件内部产生亚稳态,导致时序逻辑的功能错误。对于数据来说,非单调性的危害主要是造成时间裕量的减少,这也是复杂的总线系统往往需要进行时序仿真的原因之一。

参考:

  1. https://www.cnblogs.com/chenman/p/3649343.html

T-Branch 仍然会导致较长的命令-地址-时钟总线和较短的数据总线之间出现时序偏差。这是因为命令-地址-时钟 T-Branch 总线具有多个分支,而数据总线则是直接连接。这在 DDR2 下不是一个大问题,但在 DDR3 速度等级中已得到解决。

数据预取

DDR2 采用“4n 预取”设计,而非 DDR1 的“2n 预取”。在每个周期,它能够将来自内部存储库的 4 位数据排列到 IO 缓冲区中,然后再通过数据总线传输出去。

据 JEDEC DRAM 委员会成员、前 ATI Technologies(现 AMD)成员 Joe Macri 介绍,4n-Prefetch 架构的主要目的是降低 DRAM 核心频率以满足更高数据速率的需求。这样,DRAM 核心就能以数据总线频率的四分之一运行。

这种设计的直接优势在于能够维持相对成熟的制造工艺,而无需进行大规模的重新设计。它能够缓解 DDR2 芯片(尤其是具有更高数据速率和密度的芯片)的产能提升和良率压力。

Step to memory 010 数据预存取 Data Prefetch

https://www.bit-tech.net/reviews/tech/memory/the_secrets_of_pc_memory_part_3/4

DDR1 采用“2n 预取”设计,这意味着在每个周期,内存模块会在 1 个时钟周期内从内存条中准备 2 位数据,然后将它们在 IO 缓冲区中背靠背排列,最后通过数据线发送出去。这种设计相当简洁而优雅:对于每一对,在信号波的上升沿和下降沿各发送一位数据,从而有效地将数据吞吐量翻倍,而无需提高 DRAM 核心频率。

反射噪声管理

为了提高信号质量,主板的内存IO操作中内置了电阻终端,以消除信号反射引起的噪声。这种噪声是由信号从数据总线两端反射回来干扰新信号引起的。新信号与旧信号回声之间的冲突会引起抖动和相消干扰。信号可能会在阻抗不同的点发生反射,例如,内存插槽和内存条接触点。

需要注意的是,这种方法只能将噪声控制在DDR1设计性能参数范围内。超出该范围的噪声无法完全消除,甚至不足以造成稳定性问题。

如何理解信号的反射问题

信号反射噪声类似于声音沿着一条长管传播,随后从封闭的一端反射回来,在那里你会听到回声。现在想象一下,在这条长管的中途,有一个开口,你的朋友正在那里听。当你沿着管道和朋友说话时,声音传到他们中间,继续传播到管道的尽头,最终以回声的形式反弹回来。

当你的朋友开始回复时,回声会干扰他们的信息。因此,听清回复会有点困难。随着你们说话速度越来越快,越来越难以跟上对话;这类似于在处理信号反射的同时提高内存频率。

一种解决方案是消音管道末端以吸收噪声——板载电阻终端的作用就是在反射回来之前吸收掉不需要的信号。

ACPI:Object is created temporarily in another method and cannot be accessed

天杀最近在玩一台X86主机,他发现Dump出来的 DSDT Table 重新编译的时候会碰到标题的错误,更详细的错误信息如下:

SDT.dsl 2644: PARM |= (DerefOf (CDCT [^^MCHK.DCFE]) &lt;&lt; 0x15) /* _SB_.PCI0.GFX0.PARM */
Error 6163 - ^ Object is created temporarily in another method and cannot be accessed (^^MCHK.DCFE)

分析代码可以看到

  1. 出现问题的代码是尝试访问MCHK.DCFE
 If ((GESF == 0x07))
    {
   PARM = GIVD /* \_SB_.PCI0.GFX0.GIVD */
   PARM ^= One
   PARM |= (GMFN &lt;&lt; One)
   PARM |= 0x1800
   PARM |= (IDMS &lt;&lt; 0x11)
   PARM |= (DerefOf (CDCT [^^MCHK.DCFE]) &lt;&lt; 0x15) /* \_SB_.PCI0.GFX0.PARM */
       GESF = One
        Return (SUCC) /* \_SB_.PCI0.GFX0.SUCC */
 }

2.DCFE定义在MCHK 中

                Method (MCHK, 0, Serialized)
                {
                    If ((MADR != 0xFFFFFFFF))
                    {
                        OperationRegion (IGMM, SystemMemory, MADR, 0x3000)
                        Field (IGMM, AnyAcc, NoLock, Preserve)
                        {
                            Offset (0x20C8), 
                                ,   4, 
                            DCFE,   4
                        }
                    }
                }

看起来错误的原因是:如果MADR为0xFFFFFFFF,那么DCFE 就不存在,访问不到。

解决方法,修改代码如下:

PARM |= 0x1800
PARM |= (IDMS &lt;&lt; 0x11)
                                          
//LABZDebug_Start
If ((MADR != 0xFFFFFFFF))
      {
         OperationRegion (IGMM, SystemMemory, MADR, 0x3000)
         Field (IGMM, AnyAcc, NoLock, Preserve)
             {
                Offset (0x20C8),
                 ,   4,
                  DCFE,   4
              }
          PARM |= (DerefOf (CDCT [DCFE]) &lt;&lt; 0x15) /* \_SB_.PCI0.GFX0.PARM */
       }
//LABZDebug_End
                           
 GESF = One
 Return (SUCC) /* \_SB_.PCI0.GFX0.SUCC */

再次编译就通过了。

此外,还有一种更简单的方法:使用编译 AML 相同的版本重新编译,这个很容易理解:能够编译生成 AML 就说明至少有一个版本的编译器认可这种编译方法,找到这个版本即可重新编译。

具体的信息可以在 dsdt 的头部看到,比如,另外一个项目上如下位置可以看到编译器版本:

找到这个版本重新编译一个Error甚至Warning 都没有。

当然,这个问题还是给了我们一个提醒:ASL 编译器不同版本之间存在差异。

Step to memory 009 异步时钟和同步时钟的革命性变化

PC 内存的秘密:第 3 部分 

https://www.bit-tech.net/reviews/tech/memory/the_secrets_of_pc_memory_part_3/1/

早期的内存技术基于异步时钟架构。异步内存包括快速页面模式 (Fast Page Mode ,FPM)内存、扩展数据输出 (Extended-Data-Out ,EDO) RAM 以及其他变体。顾名思义,这种内存不与系统总线时钟绑定或同步,因此这种设计存在根本性的局限性,导致总线运行速度无法超过 66MHz。美光科技计算部门高级市场经理 Brett Williams 表示,从异步时钟依赖内存到同步时钟依赖内存的转变是“一场革命性的变革,信号传输方式彻底改变…… ”。

LAB-Z注释:这里多提一下

内存同步

所谓内存同步,就是内存频率CPU外频运行在同一频率。也就是说,在内存同步的情况下,内存频率=CPU外频。比如当200MHz外频的 P4 520与内存同步时,内存也运行在200MHz外频上。由于使用的是DDR内存,所以内存的频率=200MHz×2=400MHz(DDR400)。

内存异步

内存异步技术则是让内存频率与CPU外频不同,内存频率=CPU外频×N/M(特定的一个比值)。200MHz外频的P4 520在内存异步时,内存可以运行在166MHz,使用DDR333内存就可以了。当然,内存也可以运行在266MHz,此时系统只需要使用DDR533 内存即可。也就是说,N/M的比值可以大于1也可以小于1,即内存异步时,内存的频率可以高于或低于CPU外频。

存在原因

在早先的计算机系统中,内存和CPU之间的搭配,CPU处于主导的地位,也就是说当CPU的主频为100MHz,那么内存的频率就只能是 100MHz,内存的使用完全依赖于CPU。随着CPU技术的迅速发展,CPU的频率不断提高,这样就造成了用户升级CPU时就必须也对内存进行升级,无疑增加了升级的成本,这种情况直到VIA的694X芯片组发布之后才有所改变,内存与CPU外频终于可以实现异步运行了。

当然这样的异步运行技术并没有完全脱离CPU外频的束缚,而是采用了“±33MHz”的解决方案。也就是说,当P3处理器运行在100MHz 外频下,内存可以异步运行在133MHz或66MHz两种频率下。内存运行在133MHz频率的时候,系统就可以获得更大的性能提升,在当时绝对算得上领先的内存技术。至于现今的内存异步技术,已经发展到了更为先进的阶段。内存与CPU外频的异步运行甚至可以设定在4:3或5:4的比例状态下。

理论上来讲,搭配更高频率的内存就可以获得更大的数据带宽,对于系统性能的提升也会有很大帮助。并且内存异步技术还可以更为灵活的搭配内存,在CPU外频不断提高的现今,内存异步技术更可以帮助升级用户节省下更换内存的资金。

理论上来讲,内存异步技术提升内存的频率后,相应的数据带宽也会明显提高,性能应该有所增强。但就异步技术开始出现时的测试成绩来看,内存异步技术的性能提升并不是特别明显,这是为什么呢?其实这是由于采用了异步运行方式后,虽然增加了内存的带宽,但同时也增加了内存的延迟。

比如,某处理器运行在100MHz外频下,其时钟周期为10ns。运用内存异步技术之后,内存可以运行在133MHz频率下,时钟周期为 7.5ns。当周期为7.5 ns的时钟周期结束时,周期为10ns的时钟周期还没有结束,那么前者就需要等待后者完成一个周期后才能开始下一个周期,这样就造成了内存的延迟,而延迟所带来的性能损失也直接导致了测试成绩的下降。这种情况发展到NF2芯片组尤为严重,NF2主板甚至只有内存同步时才能获得最优性能,内存异步技术在当时的AMD平台甚至成为了“鸡肋”。

不过事情总是有转机的,处理器的外频不断提高时,内存技术也跟着飞速发展。高频内存与CPU外频之间,使用异步后的延时越来越小,系统性能的提升也就越来越明显,这样使得内存在一定程度上摆脱了CPU外频对其频率的束缚。内存和CPU之间可以更加灵活自由地进行搭配,这样给用户留下很大可控制的空间,在很大程度上促进了超频技术的发展。当然了,对于那些升级CPU的用户而言,也可以留下以前的内存,只要开启主板的内存异步功能就可以实现平稳的过渡升级。

现代计算机内存仍然依赖于同步时钟设计,这种设计在同步动态随机存取存储器 (SD-RAM) 大规模市场采用后变得尤为突出。SD-RAM 起始频率为 66MHz,每个时钟周期限制为一个信号。后来,这种设计演变成了 DDR 内存,即双倍数据速率同步动态随机存取存储器 (DDR)。DDR 内存是一种 SD-RAM,能够在一个时钟周期搬运两次数据。

此时,重要的是要认识到,我们所说的“计算机内存”实际上是一组不可分割的子系统,包括 RAM 模块、主板、MCH(内存控制器中枢)以及 CPU。我们知道,有时 CPU 会将 MCH 集成到其设计中,例如 AMD 的 Athlon 64 和 Phenom 处理器。

第一代:DDR1

第一代台式机双倍数据速率内存模块 (DDR1)采用 184 针接口设计,高于 SD-RAM 使用的 164 针接口。DDR1 通常基于薄小外形封装 (TSOP) 芯片,虽然也使用过一些基于球栅阵列 (BGA) 的 DRAM,但非常罕见。本系列第二部分中介绍过关于内存的封装。

TSOP 芯片的缺点是,由于两侧引脚向外延伸的特性,芯片会占用更大的 PCB 空间——这意味着密度较低。并且和 BGA封装相比,TSOP 在高速传输时也存在一些信号质量的问题。

图片的意思是 SDR 会在时钟上升沿传输一次数据,总线频率 100Mhz, 数据频率也是100Mhz;在 DDR 上,会在时钟的上升沿和下降沿分别传输一次数据,因此总线频率是100Mhz时,数据频率是200Mhz.

DDR1 DRAM 的最高工作温度通常在 85˚C/185˚F 左右,但有时也可能更低,具体取决于具体部件和制造商。理论上,与 DDR2 和 DDR3 中基于 BGA 的 DRAM 相比,采用 TSOP 芯片的 DDR1 模块可以承受更大程度的焊接温度而不会损坏连接引脚,因为焊点更大且更易于焊接。

一个内存模块的最高工作温度始终远低于 DRAM规格中所描述的数值,但这个因素会因内存芯片和印刷电路板 (PCB) 制造商以及所采用的热管理解决方案而异。

官方 DDR1 总线频率通常为 100MHz、133MHz、166MHz 和 200MHz,但偶尔也会有 150MHz、183MHz 甚至超过 200MHz 的频率出售给最终用户。由于DDR每个时钟周期可以附加两个信号,因此标准理论数据频率分别为200MHz,266MHz,333MHz和400MHz。

JEDEC 定义的 DDR1 电源为 2.5V,但一些制造商已认证其模块可在高达 2.8V 以上的电压下运行,且仍在保修范围内。这种额外的成本和购买保障对于系统超频爱好者来说非常实用。

源同步架构

DDR1 中最重要的变化之一是不再依赖 SDR 中使用的中央时钟方案,而是引入了源同步或选通设计。
这样做的好处是可以提高性能。single-ended Data Strobe(DQS) 架构的引入在数据和中央系统时钟 (CLK) 之间创建了一个额外的跟踪层。

DDR1的“单端”(Single-ended)数据选通是指只有一个上升和下降信号波的特性(DDR2开始改成了差分信号)。该单端数据选通由数据 (DQ) 跟踪,以实现更有效的信号传输——它在容忍工艺-电压-温度 (PVT) 变化以及串扰、回声和信号反射引起的问题方面具有更大的基本强度,这些问题往往会扭曲波形或导致时序不准确。

DDR2及之后的版本中,为了增强信号的抗干扰能力,尤其是对抗时钟信号的干扰,时钟信号如DQS和CLK等都被改为了差分信号。

引入一个称为数据选通的附加定时层的目的是帮助数据在更高速度等级下更有效地跟踪时钟;然而,这也带来了额外的复杂性。

前面提到的时钟信号改为差分信号,即出现了  CK和CK# 。引入的而原因是为了起到触发时钟校准的作用

由于数据是在CK的上下沿触发,造成传输周期缩短了一半,因此必须要保证传输周期的稳定以确保数据的正确传输,这就要求CK的上下沿间距要有精确的控制。但因为温度、电阻性能的改变等原因,CK上下沿间距可能发生变化,此时与其反相的CK#就起到纠正的作用(CK上升快下降慢,CK#则是上升慢下降快)。

  而由于上下沿触发的原因,也使CL=1.5和2.5成为可能,并容易实现。【参考1】https://www.cnblogs.com/leaven/archive/2010/07/21/1782341.html

尽管数据选通可以缓解更高频率下数据与系统时钟之间的定时误差,但数据选通本身可能会与系统时钟不对齐或出现偏差。因此,必须在两者之间构建额外的“去偏差”或同步逻辑,以确保正常运行。

这个叫做数据选通或 DQS 的东西是什么?

数据选通信号 (SD RAM) 是数据相对于系统时钟的跟踪信号。它是一种振荡电信号,用于定义数据必须位于何处以及数据应在何处停留多长时间。

正如“同步”动态 (SD) RAM 的名称所暗示的那样,现代计算机内存依赖于所有部件按照集中时钟进行排列,以实现可靠的信号传输。它最初在 DDR1 中采用单端设计。在更高的 DDR2 速度下,需要采用差分选通设计。

美光科技应用工程师 Aaron Boehm 解释说,问题在于“时钟可能会有很大差异,因此 DQS 用于将所有数据与时钟对齐。在 DRAM 内部,选通脉冲跟踪时钟。因此,当 DRAM 输出数据时,数据会与选通脉冲对齐,而选通脉冲又跟踪时钟。当内存控制器写入 DRAM 时,数据集中到选通脉冲。数据选通脉冲 (DQS) 允许控制器和 DRAM 查看并锁定数据。 ”

关于为什么需要多增加一个 DQS 信号,有如下解释【参考2】

a、进行DDR拓扑,多个DDR芯片共同使用一个CK时钟,DDR控制器的数据总线可以以最短距离连接到DDR上去,但CK时钟需要进行分叉连接到DDR上去,导致CK走线比数据总线要长,若要想走线等长,那么需要数据总线做等长走线,数据总线的数量远比CK多,不利于PCB等长走线,所以不使用CK为基准。

b、当DDR向DDR控制器发送数据时,由于PCB走线和DDR发送电路的延迟对于DDR芯片而言不知道有多长,所以DDR控制器无法准确的通过CK对数据总线上的数据进行采样。所以不使用CK为基准

针对于以上两个问题,数据总线中引入了DQS这一信号,使用DQS做数据总线采样的参考时钟,因此DQS必须与DQ等长,DQS频率与CK一致,允许相位差,这个相位差(可提前可滞后)可以通过DLL调节,写数据时二者上升沿对齐误差允许0.75~1.25个时钟周期,读数据时的对齐误差以芯片的规格书为准。

【参考】

2.https://zhuanlan.zhihu.com/p/1896493235079193557

回忆:成人礼

大约是97年,“成人礼”这种仪式忽然流行起来。印象中那一段时间在电视和报纸上看到过很多次相关报道,几乎所有的学校都会把学生拉出去搞这个仪式。我所在的大庆中学同样追随潮流,将实际上尚未成年的我们拉出去走参加一圈仪式,仿佛尚未成年的猪仔盖上“检疫合格”章一般。

时隔快30年,我依然记忆深刻原因是偶然学到的一个歇后语:马槽改棺材—-成(盛)人了,以至于现在我听到“成人礼”三个字还会想起来这个歇后语。

成人礼那天,大巴车把我们拉到广场上列队。还特地让每个人穿上校服,这样看起来更加整齐划一。当年的校服是类似化肥袋子一样的材质,具有颜色鲜艳耐磨方便洗涤等优点,唯一的缺点是不透气。

许多学校的学生列队站在一起,之后是冗长的各路领导下凡讲话。具体的内容早已忘记,印象最深刻的倒是领导讲话过程中不断有学生倒下。原因很多,比如,早晨没吃饭的低血糖,校服太闷散热不良,或者是鞋子不适合长期站立影响头部供血等等。几年前《中国青年报》上的曾经有一篇《夏令营中的较量》,让全国上下都在焦虑未来的青少年如何超越那些负重20公斤步行50公里的“平成小超人”。当然,亲眼见到身边人倒下,我也认真思考“这 TMD 体质,要是真的遇到外敌入侵怎么办”。

这个成人礼只有半天,中午没管饭,大巴车直接把我们拉回去了。当然,只要不上课,我们的心情都是无比舒畅的。

仪式结束之后,我们都收到了“成人卡”,上面有着时任市长钱棣华的签名(印刷的)。这个名字印象深刻的原因有两个:一个是这个名称让人产生和某个男性器官产生联想;另外一个原因是这个大爷后来进去了。

这张签名卡一直在我家的立柜中间矗立了很久。若干年后,大学寒假回家时还看到过。记得我父亲对于这个老头落马颇感惋惜,每每提及都是感叹“这么多年的老会战怎么就出这个事儿”,“他女儿找人办事还被直接卷了面子”等等言语。

好奇心驱使下,搜索了一下,在【参考1】有了一些收获(这个大爷的事情被写入论文了,收录到“知网”中了,文章题目还颇有自媒体风范《”糖弹”轰倒”红旗手”——大庆市原人大主任钱棣华受贿案实录》。相当于写入史书了,未来会被人无数次提起)。除了普通的受贿,这个大爷还在审查起诉阶段试图翻供,更是为了坊间传闻提供了无数的素材。当然,翻供未遂,经过黑龙江省检察院的调查,发现是他女儿和亲属贿赂办案人员和看守所管教编造伪证,试图翻案。最终认定“受贿22.5万,有期徒刑10年”。相关人员也都跟着判刑开除公职。

参考:

1. https://www.chinanews.com/2000-07-31/26/39783.html

UEFITIPS:BASE_LIST 用法

最近又在开关于Debug Message的内容,因此研究了一下BASE_LIST。简单的说,有时候你要传递一些长度不定的数据就可以使用这个定义。比如,一个数据块,有时候其中有10个UINTN,有时候其中有2个UINTN (特别注意的是每个单元的大小必须相同)。

具体结构体定义在 Edk2\MdePkg\Include\Base.h,可以看到BASE_LIST 实际上是一个指向 UINTN 的指针。

///
/// Pointer to the start of a variable argument list stored in a memory buffer. Same as UINT8 *.
///
typedef UINTN *BASE_LIST;

此外,经常和 BASE_ARG 结合起来使用,这个宏会返回指针指向的下一个值:

/**
  Returns an argument of a specified type from a variable argument list and updates
  the pointer to the variable argument list to point to the next argument.

  This function returns an argument of the type specified by TYPE from the beginning
  of the variable argument list specified by Marker.  Marker is then updated to point
  to the next argument in the variable argument list.  The method for computing the
  pointer to the next argument in the argument list is CPU specific following the EFIAPI ABI.

  @param   Marker   The pointer to the beginning of a variable argument list.
  @param   TYPE     The type of argument to retrieve from the beginning
                    of the variable argument list.

  @return  An argument of the type specified by TYPE.

**/
#define BASE_ARG(Marker, TYPE)  (*(TYPE *) ((Marker += _BASE_INT_SIZE_OF (TYPE)) - _BASE_INT_SIZE_OF (TYPE)))

编写代码验证:

#include  <Uefi.h>
#include  <Library/UefiLib.h>
#include  <Library/ShellCEntryLib.h>

INTN
EFIAPI
ShellAppMain (
  IN UINTN Argc,
  IN CHAR16 **Argv
  )
{
  UINTN A[4]={1,2,3,4};
  BASE_LIST TestList;
  
  TestList=(BASE_LIST) &A;
  
  for (int i=0;i<4;i++) {
	  Print(L"%d ",BASE_ARG(TestList,UINTN));
  }
   Print(L"\n");
  return(0);
}

运行结果:

开源硬盘SMART检测工具

https://github.com/smartmontools/smartmontools 可以看到一个硬盘检测工具。

项目的介绍是:

About Smartmontools
The smartmontools package contains two utility programs (smartctl and smartd) to control and monitor storage systems using the Self-Monitoring, Analysis and Reporting Technology System (SMART) built into most modern ATA/SATA, SCSI/SAS and NVMe disks. In many cases, these utilities will provide advanced warning of disk degradation and failure.

Smartmontools was originally derived from the Linux smartsuite package and supports ATA/SATA, SCSI/SAS, and NVMe disks and also SCSI/SAS tape devices. It should run on any modern Linux, FreeBSD, NetBSD, OpenBSD, Darwin (macOS), Solaris, Windows, Cygwin, OS/2, eComStation, or QNX system. Smartmontools can also be run from one of many different Live CDs/DVDs.

有支持 Windows 的版本,安装后进入安装的目录,使用如下命令即可检测输出当前硬盘的信息:

smartctl,exe -x /dev/sda

例如,在一台测试机上结果如下:

smartctl 7.5 2025-04-30 r5714 [x86_64-w64-mingw32-w11-24H2] (AppVeyor)
Copyright (C) 2002-25, Bruce Allen, Christian Franke, www.smartmontools.org

=== START OF INFORMATION SECTION ===
Model Number:                       SKHynix_HFS256GEJ4X112N
Serial Number:                      4DBCQ48581010CG2R
Firmware Version:                   51030C31
PCI Vendor/Subsystem ID:            0x1c5c
IEEE OUI Identifier:                0xace42e
Controller ID:                      1
NVMe Version:                       1.4
Number of Namespaces:               1
Namespace 1 Size/Capacity:          256,060,514,304 [256 GB]
Namespace 1 Formatted LBA Size:     512
Namespace 1 IEEE EUI-64:            ace42e 0026df381b
Local Time is:                      Sun Jul 20 22:46:46 2025 PDT
Firmware Updates (0x16):            3 Slots, no Reset required
Optional Admin Commands (0x0017):   Security Format Frmw_DL Self_Test
Optional NVM Commands (0x005f):     Comp Wr_Unc DS_Mngmt Wr_Zero Sav/Sel_Feat Timestmp
Log Page Attributes (0x1e):         Cmd_Eff_Lg Ext_Get_Lg Telmtry_Lg Pers_Ev_Lg
Maximum Data Transfer Size:         64 Pages
Warning  Comp. Temp. Threshold:     86 Celsius
Critical Comp. Temp. Threshold:     87 Celsius

Supported Power States
St Op     Max   Active     Idle   RL RT WL WT  Ent_Lat  Ex_Lat
 0 +   4.5000W       -        -    0  0  0  0      100     100
 1 +   3.0000W       -        -    1  1  1  1      200     200
 2 +   0.6000W       -        -    2  2  2  2      400     400
 3 -   0.0150W       -        -    3  3  3  3     2000    2000
 4 -   0.0030W       -        -    4  4  4  4     5000   10000

Supported LBA Sizes (NSID 0x1)
Id Fmt  Data  Metadt  Rel_Perf
 0 +     512       0         0

=== START OF SMART DATA SECTION ===
SMART overall-health self-assessment test result: PASSED

SMART/Health Information (NVMe Log 0x02, NSID 0xffffffff)
Critical Warning:                   0x00
Temperature:                        30 Celsius
Available Spare:                    100%
Available Spare Threshold:          10%
Percentage Used:                    15%
Data Units Read:                    117,427,832 [60.1 TB]
Data Units Written:                 118,434,215 [60.6 TB]
Host Read Commands:                 565,071,947
Host Write Commands:                434,694,135
Controller Busy Time:               8,007
Power Cycles:                       5,554
Power On Hours:                     1,648
Unsafe Shutdowns:                   1,034
Media and Data Integrity Errors:    0
Error Information Log Entries:      21
Warning  Comp. Temperature Time:    0
Critical Comp. Temperature Time:    0
Temperature Sensor 1:               35 Celsius
Temperature Sensor 2:               30 Celsius
Thermal Temp. 1 Transition Count:   249

Error Information (NVMe Log 0x01, 16 of 256 entries)
No Errors Logged

Self-test Log (NVMe Log 0x06, NSID 0xffffffff)
Self-test status: No self-test in progress
No Self-tests Logged

ACPI 官方工具

ACPICA 官方提供了一些工具可供直接使用,具体列表如下: