32位模式下使用64位寄存器注意事项

8051架构革新:金水32051指令集助力32位运算与双核开发 在嵌入式系统开发中,指令集架构(ISA)是连接硬件与软件的核心桥梁。传统8051架构凭借其简洁性和稳定性,长期主导低端嵌入式市场。随着物联网设备功能复杂化,32位数据处理和双核架构需求日益凸显。金水32051指令集通过创新的分层设计,在保留经典8051兼容性的同时,新增32位运算指令和双核编程支持。这种架构革新不仅提升了70倍运算性能,还通过虚拟执行环境实现提前验证,显著改善代码密度和可维护性。该技术特别适用于实时控制系统、传感器融合等场景,为国产MCU在工业自动化和消费电子领域提供了差异化竞争优势。 阅读详情


1. 汇编环境

龙芯2E平台32位OS模式下,要使用64位寄存器可以在汇编代码里直接 用,运算时使用d开头的指令(double-word, 64bit),作用于寄存器即可。如:dadd, dsub, dmult, dmultu, ddiv, dsll, dsrl, dsra 等等。

访问存储器可以直接使用ld/sd, ldc1/sdc1

使用这些指令前,先用伪操作 .set mips3 告诉汇编器下面的指令是MIPS IV(64位指令集,兼容32位指令)中的指令。


2. C语言环境

可以内嵌汇编,在汇编中使用dadd, dsub, dmult, dmultu, ddiv, dsll, dsrl, dsra 等指令

内嵌汇编与C语言之间的数据方式要特别注意,如读取CP0 25 寄存器(64位,高低32位各为一个计数器)的值,使用如下代码,获取的高32位的值是不正确的:

  long long counter;
  int c0, c1;

  asm(
        ".set mips3/n/t"
        "dmfc0 %0, $25/n/t"
        ".set mips1/n/t"
        : "=r" (counter)
    );

  c0 = counter;
  c1 = counter >> 32;

  printf("low is 0x%x/n", c0);
  printf("high is 0x%x/n", c1);


可以与如下代码获取的值比较下就知道了:

unsigned int counter0, counter1;
unsigned int control;

void read_pmc()
{
  __asm__ volatile (
        ".set mips3   /n/t"
        "dmfc0 %0, $24 /n/t"
        ".set mips0   /n/t"
        :"=r"(control)
        );

  __asm__ volatile (
        ".set mips3   /n/t"
        "dmfc0 %0, $25 /n/t"
        ".set mips0   /n/t"
        :"=r"(counter0)
        );

  __asm__ volatile (
        ".set mips3   /n/t"
        "dmfc0 $8, $25 /n/t"
        "dsrl %0, $8, 32 /n/t"
        ".set mips0   /n/t"
        :"=r"(counter1)
        );
}


int main()
{
  read_pmc();

  printf("control register is(cp0_24): 0x%016x/n", control);
  printf("counter0 register is(cp0_25_low): 0x%08x/n", counter0);
  printf("counter1 register is(cp0_25_high): 0x%08x/n", counter1);

}


如果一定要把CP0_25的值放在一个long long 类型的变量里,则:

  long long counter;
  int c0, c1;

  asm(
    ".set mips3/n/t"
    "dmfc0 %M0, $25/n/t"
    "dsll   %L0, %M0, 32/n/t"
    "dsrl   %M0, %M0, 32/n/t"
    "dsrl   %L0, %L0, 32/n/t"
    ".set mips0/n/t"
    : "=r" (counter)
  );

  c0 = counter;
  c1 = counter >> 32;

  printf("low is 0x%x/n", c0);
  printf("high is 0x%x/n", c1);


同样的要将一个long long的值写入,需用如下代码方能正确写入:

asm(
    ".set mips3/n/t"
    "dsll   %L0, %L0, 32/n/t"
    "dsrl   %L0, %L0, 32/n/t"
    "dsll   %M0, %M0, 32/n/t"
    "or   %L0, %L0, %M0/n/t"
    "dmtc0 %L0, $25/n/t"
    ".set mips0/n/t"
    ::"r" (counter)
  );

其中counter得定义为 long long

如果要用上面的代码写入0,则一定要这样 long long counter = 0 才可,直接传常数给他是不行的。


3. 常见问题

试看如下代码:

1   long long counter;
2   int c0, c1;

3   asm(
4     ".set mips3/n/t"
5     "dmfc0 %M0, $25/n/t"
6     "dsll   %L0, %M0, 32/n/t"
7     "dsrl   %M0, %M0, 32/n/t"
8     "dsrl   %L0, %L0, 32/n/t"
9     ".set mips0/n/t"
10     : "=r" (counter)
11   );

12   c0 = counter;
13   c1 = counter >> 32;

14   if(c0 < 0)
15     printf("low is 0x%x/n", c0);

16   if(c1 < 0)
17     printf("high is 0x%x/n", c1);


其意图是在任何一个计数器溢出时(最高位为1,则补码表示即为负数),打印其值。

gcc 不带优化选项 -O 编译之,运行是没有问题的。

倘若加-O 编译之,运行时并非如我们所期待的行为,最高位为1时,他也不打印,逻辑关系完全错了。



这个问题我们来对比下gcc 生成的汇编码就清楚了:

不加-O 选项生成的代码为:

  .set mips3
  dmfc0 $3, $25
  dsll   $2, $3, 32
  dsrl   $3, $3, 32
  dsrl   $2, $2, 32
  .set mips0

  sw $2,32($fp)
  sw $3,36($fp)
  lw $2,32($fp)

  sw $2,28($fp)
  lw $4,36($fp)
  lw $5,36($fp)

  sra $2,$4,0
  sra $3,$5,31

  sw $2,24($fp)
  lw $2,28($fp)

  bgez   $2,$L2
  lw $2,%got($LC0)($28)

  addiu   $4,$2,%lo($LC0)
  lw $5,28($fp)
  lw $25,%call16(printf)($28)

  jalr   $25
  lw $28,16($fp)
  .....

加 -O 选项生成的代码为:

  .set mips3
  dmfc0 $17, $25
  dsll   $16, $17, 32
  dsrl   $17, $17, 32
  dsrl   $16, $16, 32
  .set mips0

  bgez   $16,$L2
  lw $4,%got($LC0)($28)

  addiu   $4,$4,%lo($LC0)
  lw $25,%call16(printf)($28)
  .set   noreorder
  .set   nomacro
  jalr   $25
  move   $5,$16
  .set   macro
  .set   reorder
  .....


可 以看到使用 -O 时,gcc 将原两条 sra 指令合并入 dsll-dsrl-dsrl 中了,那么由dsrl 作用得到的counter0 (对应$16)、counter1 (对应$17),其高32位是都为0的,如果counter0的值为 0x8000 0012,则此时它在$16中的全值为0x0000 0000 8000 0012,而按照运行于32位兼容模式下的定义,低32位的值应该高位符号扩展的,$16中的值是这样 0xffff ffff 8000 0012 才表示为负数。故而在下面 bgez 判断的时候就会出现差错。

从这一点可以看到,分支转移指令的作用范围还是整个64位的。

解决的方法是将嵌入的汇编中的 dsrl 换成 dsra。

代码中的这种问题极其隐蔽,且很难发现,需要谨慎在意才是。


另外,内核中 include/asm-mips/mipsregs.h 中定义的__read_64bit_c0_split 宏就有这个问题,使用时要小心在意,因为内核编译时,是打开 -O 选项的。



 
从ARMv7到AArch64:图解分支指令的演变与迁移注意事项 本文详细解析了从ARMv7到AArch64架构分支指令的演变与迁移注意事项,重点对比了无条件分支、条件分支和函数调用指令的关键差异。通过图解和实例代码,帮助开发者理解64位ARM架构的简化设计,并提供实用的迁移策略和调试技巧,优化代码性能。 阅读详情

相关推荐

深入解析UART高级功能:硬件流控、9位模式与FIFO中断策略

UART(通用异步收发器)是嵌入式系统中最基础且广泛应用的串行通信接口,其核心原理是通过异步时序实现设备间的数据交换。传统应用多关注其基本配置,但在面对大数据量、多机通信或高可靠性场景时,需深入理解其高级功能机制。硬件流控(RTS/CTS)通过专用握手信号线协调收发速率,有效防止数据溢出;9位多机通信模式则在硬件层面提供了高效的总线寻址方案,简化了一主多从网络协议。这些功能与深度可调的FIFO缓冲区及灵活的中断触发策略相结合,能显著提升通信链路的稳定性和吞吐效率,降低CPU负载。本文以TI Tiva™ MC

weixin_30652491的博客 299

单片机为32bit时运算中64bit运算中遇到的bug及其规避手段

在单片机运算中。一般只能处理32bit的运算。在有些场合,不得不处理64bit的运算的时候。发现编译器也是支持的。编译器应该是通过软件实现的。 设想一种场合,要对一个32bit的数进行乘以0xffffffff的操作。 方式1: //先定义一个 numTmp_64bit numTmp_64bit = numA_32bit*0xff; numTmp_64bit *= 0xffffff; ...

weixin_34416649的博客 2534

ARM A64指令集ADDS与ADR指令详解

在计算机体系结构中,指令集架构(ISA)是处理器与软件之间的关键接口。ARMv8作为主流的64位RISC架构,其A64指令集通过精简高效的指令设计,在移动计算和服务器领域广泛应用。ADDS指令作为基础算术运算指令,不仅执行加法操作,还会设置条件标志位(NZCV),为后续条件分支和条件执行提供判断依据。地址计算指令ADR则利用PC相对寻址实现位置无关代码,这对操作系统内核和动态链接库开发尤为重要。理解这两类指令的工作原理和优化技巧,可以帮助开发者编写更高效的底层代码,特别是在性能敏感场景如循环控制、条件分支和

weixin_26884391的博客 333

Long Long、__int64使用总结

转载自 tianxingjianhd 最终编辑 tianxingjianhd 前言:   在16位环境下,int/unsigned int 占16位,long/unsigned long占32位   在32位环境下,int占32位,unsigned

tanhaiyuan 1327

SPI通信核心配置:数据长度与时钟格式详解

SPI(串行外设接口)是一种广泛应用的同步串行通信协议,以其全双工、高速和简单的硬件接口而著称。其工作原理基于主从架构和移位寄存器,通过时钟信号同步数据交换。理解SPI的核心在于精确配置其关键参数,这直接决定了通信的稳定性和效率。其中,数据长度定义了单次传输的位数,而时钟格式则通过CPOL和CPHA的组合,精确控制了数据采样与移位的时序关系。这些配置是确保主从设备间数据正确同步的基石,对于连接各类传感器、存储芯片等外设至关重要。本文聚焦于SPI通信中数据长度与时钟格式的深度解析,通过剖析8位与16位模式下的

anuancong1219的博客 386

【优化系列】汇编优化技术(二):X86架构汇编优化及demo

DATE: 2021.8.15 文章目录1、简介2、入门基础3、寄存器3.1、32位寄存器3.2、64位寄存器4、调用规则4.1、32位函数调用规则4.2、64位模式(linux64)调用规范4.3、64位模式(windows64)调用规范4.4、调用规则实例5、指令集使用方法5.1、数据表示和寻址方式5.2、指令格式和通用指令5.2.1、指令格式5.2.2、通用指令5.3、MMX指令5.3.1、MMX指令简介5.3.2、MMX指令使用5.4、SSE/SSE2/SSE3/SSSE3/SSE4.1指令5.5

优快云明星博主,认证博客专家,视频、Matlab领域优质创作者。 1398

32位64位系统long字节大小

32位 64位 LONG 字节区别

ananxuezhanga的博客 8530

《Sigrity SystemSI 2023+LPDDR4仿真自学笔记》(一)创建工程(Part1)

为了加强SystemSI 2023软件的熟悉度,咱们完整的走一个仿真全流程。

weixin_45199544的博客 6324

stm32F407学习DAY.15​(1) 软件SPI读写W25Q64芯片程序

可以看出是一个3.3V供电的芯片:相当于对SPI设备进一次中断,指在正常读写时突然产生中断要用SPI通信线去操控其他器件,若将CS置高电平时序会终止,若不想终止总线,又要控制其他器件,可以将HOLD置低电平,此时芯片释放总线,但不会终止时序,会记住当前状态,当操作完其他的器件再回来可以从之前的状态继续操作,相当于SPI总线进了一次中断,且仍可以用SPI去做其他事情。

qwsgdjfk的博客 2754

【医学图像分割网络】之Res U-Net网络PyTorch复现

【医学图像分割网络】之Res U-Net网络PyTorch复现 1.内容 U-Net网络算是医学图像分割领域的开山之作,我接触深度学习到现在大概将近大半年时间,看到了很多基于U-Net网络的变体,后续也会继续和大家一起分享学习。这次分享ResNet+U-Net的一个改进版,ResNet本身就是一个十分优秀的backbone,目前应用仍然十分广泛,我们融合进ResNet后,我们就可以使得U-Net进行迁移学习了。 1.将Resnet作为encoder替换U-Net原始结构 2.U-Net提出时间较早,当时还没

qq_39071739的博客 1万+

Python自然语言处理 NLTK 库用法入门教程【经典】

@本文来源于公众号:csdn2299,喜欢可以关注公众号 程序员学府 本文实例讲述了Python自然语言处理 NLTK 库用法。分享给大家供大家参考,具体如下: 在这篇文章中,我们将基于 Python 讨论自然语言处理(NLP)。本教程将会使用 Python NLTK 库。NLTK 是一个当下流行的,用于自然语言处理的 Python 库。 那么 NLP 到底是什么?学习 NLP 能带来什么好处? ...

python函数基础教程 1万+

32位系统处理64位数据

64位返回值x86平台ARM平台参数传递及加减运算x86平台ARM平台右移x86平台ARM平台32位数据转换为64位数据x86平台ARM平台 32位系统的通用寄存器GPR只能容纳32位数据,所以这种平台必须把64位数据转换为一对32位数据才能进行运算 64位返回值 #include <stdio.h> uint64_t f() { return 0x1234567890ABCDEF...

qq_24601427的博客 4016

如何用 OBProxy 实现 OceanBase 的最佳路由策略

本文基于业务中一类常见的路由问题展开,对OceanBase的路由功能及对应配置项做详细介绍,指导用户在业务实践中如何正确的配置路由策略及快速排查路由问题

OceanBase分布式数据库的博客 1679

x86-64与arm64对寄存器访问操作的一些特征

本文主要介绍Intel x86-64架构与ARM64架构对通用目的寄存器以及SIMD寄存器的访问操作的情况。比如,哪些寄存器或某些指令对它们低位修改时,高位仍保持不变;而哪些寄存器或某些操作对它们低位修改时,高位会被清零。

zenny_chen的专栏 2212

从零搭建Obsidian智能知识库:Ollama本地模型与Copilot插件实战指南

本文详细介绍了如何从零搭建Obsidian智能知识库,结合Ollama本地模型与Copilot插件实现高效知识管理。通过本地部署AI助手,用户可以在保证隐私安全的同时,快速检索和整理笔记,提升工作效率。文章涵盖硬件准备、Ollama部署、插件配置及实战技巧,适合需要高效知识管理的专业人士。

weixin_29230773的博客 631

基于STM32L4XX 、HAL库的SGM452B数字温度传感器驱动应用C语言程序设计

SGM452B_RESOLUTION_12BIT = SGM452B_CONFIG_R1 | SGM452B_CONFIG_R0 /* 12位分辨率,精度0.0625°C,转换时间200ms */SGM452B_RESOLUTION_11BIT = SGM452B_CONFIG_R1, /* 11位分辨率,精度0.125°C,转换时间100ms */SGM452B_RESOLUTION_10BIT = SGM452B_CONFIG_R0, /* 10位分辨率,精度0.25°C,转换时间50ms */

PP_Cottage的博客 327

X86平台Linux 32bit和64bit编程注意事项

http://www.ibm.com/developerworks/cn/linux/l-pow-inteltopwr/index.html 关于作者:Calvin Sze 是 IBM eServer Solutions Enablement 组织的一名 Linux 顾问。他在得克萨斯州的奥斯汀市工作。Calvin 的主要职责是帮助解决方案开发人员将他们的应用程序引入 Linux on POWE

Walter的专栏 2014

《UDS协议从入门到精通》系列——图解0x14:清除诊断信息

图解0x14:清除诊断信息,简洁易懂,迅速上手!

车载系统攻城狮 4824

【汇编指令1】解锁计算机底层操作的核心密码,从基础指令开启编程智慧之门,洞察数据处理与程序流程掌控奥秘,以简洁代码诠释高效运算逻辑,于数字世界构建强大功能基石,引领深入理解计算机运行机制新征程

寄存器是中央处理器(CPU)内的组成部分,它是有限存储容量的高速存储单元,用来暂存指令、数据和地址。

qq_67578580的博客 1289

芒果YOLOv5改进107:ARConv自适应旋转卷积,全网首发 | 即插即用:以增强其表征能力,从而准确检测方向物体,ICCV顶会论文idea

ARConv自适应旋转卷积,全网首发 | 即插即用:以增强其表征能力,从而准确检测方向物体,ICCV顶会论文idea

包括YOLOv5、YOLOv7、YOLOv8等模型改进 956

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

ARMv8、AArch64 与 arm64:命名与体系结构要点

本文介绍了ARMv8、AArch64与arm64的关系与要点。ARMv8是ARM架构的64位版本,包含AArch64(64位执行状态)和AArch32(32位兼容状态)。AArch64使用A64指令集,具有31个64位通用寄存器。工程中常用arm64或aarch64表示AArch64,二者二进制兼容。文章对比了AArch64与x86-64的差异,并概述了ARMv9在AArch64基础上的扩展方向,包括SVE2向量扩展和安全特性。开发时需注意ARM的弱内存模型,正确使用原子操作和内存屏障。

REDcker的博客 1063

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

X86-64架构核心特性与开发实战解析

X86-64架构作为现代计算的基础指令集,通过64位扩展实现了地址空间与寄存器体系的革命性升级。其核心原理包括48位虚拟地址管理、16个64位通用寄存器以及硬件级内存保护机制(NX位),这些改进显著提升了数据处理效率与系统安全性。在工程实践中,该架构通过长模式与兼容模式的智能切换,实现了对32位应用的完美兼容,这一特性被Windows WoW64子系统和Linux multiarch机制广泛应用。开发者需要特别关注编译器指令控制、内存对齐优化等关键技术点,尤其在处理SIMD指令集和大页内存配置时,合理运用X

weixin_33908217的博客 359

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

UART进阶应用:流控制、9位模式与FIFO操作实战解析

在嵌入式系统与微控制器通信领域,串口通信(UART)作为基础且广泛应用的异步串行通信接口,其核心价值在于实现设备间稳定可靠的数据交换。其工作原理基于起始位、数据位和停止位的帧格式,通过预定义的波特率进行同步。为了提升通信的可靠性与效率,工程师需要深入理解其进阶功能模块。硬件流控制通过RTS/CTS信号线实现全双工握手机制,能有效防止数据因缓冲区满而丢失,是高速可靠通信的基石;而9位模式则创新地利用一个额外位实现软件寻址,为构建简易多节点网络提供了优雅的解决方案,无需为每个从设备增加物理片选线。这些技术显著提

weixin_34138056的博客 395

AM64x/AM243x CPTS模块深度解析:硬件时间同步原理与IEEE 1588实践

在工业通信和实时控制系统中,高精度时间同步是确保分布式设备协同工作的基础。其核心原理在于通过统一的硬件时间基准,为网络报文打上精确的时间戳,从而消除软件延迟带来的抖动。这项技术的核心价值在于为IEEE 1588(PTP)等精密时间协议提供纳秒级的硬件支持,广泛应用于工业自动化、运动控制和电信网络等领域。CPTS(通用平台时间同步)模块正是实现这一目标的关键硬件引擎,它集成了高精度计数器、事件FIFO和可编程输出,能够自动捕获和处理以太网PTP报文的时间戳。通过深入理解其时钟域、事件驱动机制以及COMP、SY

weixin_33827731的博客 351

64位Ubuntu中C与intel汇编混合编程

部分转载自:王宁 知识储备 默认情况下, GCC在链接时优先使用动态链接库,只有当动态链接库不存在时才考虑使用静态链接库,如果需要的话可以在编译时加上-static选项,强制使用静态链接库。 在Linux中无法使用masm,我想编译intel风格的汇编源程序,所以选择使用nasm。(AT&T风格的汇编源程序可以用as命令编译。) nasm和masm语法相似但亦有不同之处,具体请查

这个博客,写给十年后的自己...... 2168

深入解析TI AM64x CPSW:以太网统计与CPTS时间同步实战

在嵌入式网络与工业控制系统中,网络性能监控与高精度时间同步是保障系统可靠性与协同精度的两大基石。网络性能监控通过分析链路层数据,如帧统计、错误计数与碰撞检测,为诊断网络拥塞、物理层故障提供了量化依据,其技术价值在于实现从被动响应到主动预防的运维转变。时间同步技术,尤其是基于IEEE 1588(PTP)协议的硬件时间戳,通过消除操作系统协议栈延迟,为实现微秒乃至纳秒级时钟对齐提供了硬件保障,这对于机器人协同、电力系统同步等场景至关重要。本文聚焦于德州仪器(TI)AM64x/AM243x处理器集成的CPSW模块

406
上一篇: MIPS 平台下 I/O 端口的读写--以龙芯为例
下一篇: 龙芯2E平台程序性能分析
Jack Tan
博客等级 码龄22年 28粉丝 52原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值