企业网站如何提高,足球比方类网站开发,陕西头条新闻,python基础教程电子书下载文章目录 简介产生背景应用领域 语言学习EASy68K帮助文档IDE使用 编程语言commentslabels开始标签指令标签位置标签 opcode 操作码常用操作码数据传送算术运算逻辑运算控制流分支跳转地址跳转子程序跳转 位操作比较堆栈操作 IO操作码其他操作码 directives 指令DC指令EQU 指令S… 文章目录 简介产生背景应用领域 语言学习EASy68K帮助文档IDE使用 编程语言commentslabels开始标签指令标签位置标签 opcode 操作码常用操作码数据传送算术运算逻辑运算控制流分支跳转地址跳转子程序跳转 位操作比较堆栈操作 IO操作码其他操作码 directives 指令DC指令EQU 指令SET 指令DS 指令其他指令 寄存器程序计数器PC状态寄存器SR状态寄存器的结构状态寄存器的作用示例 数据寄存器D)D 寄存器的特点D 寄存器的使用场景示例 地址寄存器A)A 寄存器的特点A 寄存器的使用场景示例 堆栈寄存器SS)堆栈操作std函数模拟 案例(9*9乘法表) 简介
68000 汇编语言是为 Motorola 68000 微处理器设计的低级编程语言。68000 微处理器于 1979 年推出因其强大的性能和灵活的架构而广泛应用于多种计算机系统和嵌入式设备中。以下是对 68000 汇编语言的背景、应用领域以及学习它的好处的详细介绍。
产生背景 技术进步 68000 微处理器是 16 位架构具有 32 位的地址总线能够寻址高达 4GB 的内存。这使得它在当时的微处理器中具有较高的性能和灵活性。其设计采用了复杂指令集计算CISC架构支持多种寻址模式和丰富的指令集。 市场需求 1970 年代末和1980年代初个人计算机和嵌入式系统的需求迅速增长。68000 微处理器因其性能和成本效益被广泛采用。许多知名的计算机系统如 Apple Macintosh、Atari ST 和 Sega Genesis都使用了 68000 处理器。
应用领域 个人计算机 68000 微处理器被用于早期的个人计算机如 Apple Macintosh 和 Atari ST。这些系统的操作系统和应用程序通常使用 68000 汇编语言进行开发。 嵌入式系统 68000 处理器也被广泛应用于嵌入式系统如工业控制、汽车电子和消费电子产品。 游戏机 Sega Genesis 和其他游戏机使用 68000 处理器许多经典游戏都是用 68000 汇编语言编写的学习后可以做一些hackrom的实战。 实时系统 由于其高效的性能68000 处理器在实时系统中也得到了应用如医疗设备和航空航天系统。
语言学习
EASy68K
EASy68K 是一个 68000 结构化汇编语言集成开发环境IDE。EASy68K 允许您在 Windows PC 或 Wine 上编辑、汇编和运行 68000 程序。无需额外的硬件。EASy68K 是一个开源项目根据 GNU 通用公共使用许可分发。 使用easy68k方便我们学习整套68000的编程和调试学习这件基础知识对我们hackrom或者逆向的基础。 下载地址http://www.easy68k.com/files/SetupEASy68K.exe 安装完成后的目录结构
帮助文档
helm.chm提供了完整的编程和调试工具以及68k语言的学习入门资料可以直接从该文档入手。
IDE使用
打开EDIT68K.exe菜单file-new x68 source file 。 在source里面实现一个功能打印helloworld并从空值台输入一个字符串并打印。 关于指令标签寄存器其他相关的内容请移步后续章节。 源代码
*-----------------------------------------------------------
* Title :
* Written by :
* Date :
* Description:
*-----------------------------------------------------------ORG $1000 ;告诉编译器代码从1000位置开始不指定默认从0开始
START: ; first instruction of program* 将text字符串地址写给A1lea text,A1* 将14号task print 给d0,并执行14号任务自动获取A1地址的数据并打印move #14,D0trap #15* 执行2号任务从输入流获取输入自动写入到A1move #2,D0trap #15* 打印A1地址内容move #14,D0trap #15* Put program code here
*-----------------------------------------------------------
*HELLO这是一个标签标识字符串数据的起始位置。
*DC.B这是一个伪指令表示“定义常量Define Constant”后面的 .B 表示定义的是字节Byte数据。
*Hello World这是一个字符串常量表示字符数组。每个字符占用一个字节。
*$D这是一个十六进制常量表示一个字节的值。$D 的十进制值是 13通常表示回车符Carriage Return。
*$A这是一个十六进制常量表示一个字节的值。$A 的十进制值是 10通常表示换行符Line Feed。
*0这是一个字节的值表示字符串的结束符null terminator在 C 语言中常用来标识字符串的结束。
*-----------------------------------------------------------
text dc.b helloworld,0SIMHALT ; halt simulator* Put variables and constants hereEND START ; last line of source
点击工具栏运行按钮如果由错误会有提示根据情况修正 会弹出一个确认框 点击execute 绿色圈圈点击变成红色可下断点F9运行F8 stepover,F7 stepinto,点击运行可调试。
在view可打开内存窗口栈窗口等
编程语言
汇编语言程序由以下部分组成
labels 标签 - 用户创建的名称用于标记程序中的位置。opcode 操作码 - 微处理器可以执行的特定指令比如ADDMOVE等。operands 操作数 - 某些指令所需的附加数据比如#1表示10进制立即数1$1表示16进制的1。directives 指令 - 发给汇编器的命令比如ORG $1000告诉编译器代码的开始位置代码段不占用空间类似于c语言的宏编译阶段使用。macros 宏 - 用户创建的源代码集合可以在编写程序时轻松重用。comments 注释 - 用户创建的文本字符串用于记录程序。寄存器汇编语言编程需要与微处理器进行直接交互。68000 微处理器包含八个数据寄存器 D0 到 D7。数据寄存器是通用的可以视为 8 位、16 位或 32 位的整数变量。还有八个地址寄存器 A0 到 A7地址寄存器的长度为 32 位。它们通常用于引用变量。状态寄存器SR包含状态标志用于指示比较的结果。
以下是一个例子
comments
在 Motorola 6800068k汇编语言中注释用于帮助程序员理解代码的功能和逻辑。68k 汇编语言的注释格式如下*或者;开头的为注释
* Date
TRAP #15 ;将3任务执行自动打印D1的内容labels
标签用于通过名称标识程序中的位置或内存位置。需要位置的指令或指令可以使用标签来指示该位置。标签通常在行的第一列开始必须以空格、制表符或冒号结束。如果使用冒号它不会成为标签的一部分。如果标签没有在第一列开始则必须以冒号结束。标签的前 32 个字符是有效的。标签有两种类型全局标签和局部标签。
全局标签可以在程序的任何地方被引用。因此全局标签必须是唯一的名称。全局标签应以字母开头后面可以跟字母、数字或下划线。局部标签可以在程序中重复使用。局部标签必须以点 ‘.’ 开头后面可以跟字母、数字或下划线。全局标签定义了局部标签的边界。当定义局部标签时只有在遇到下一个全局标签之前才能从局部标签上方或下方的代码中引用它。汇编器通过将局部标签名称附加到前面的全局标签并用冒号 ‘:’ 替换点来创建局部标签的唯一名称。结果名称的前 32 个字符是有效的。
开始标签
标签可以用来指定程序的起始位置。如果标签 START 指定了程序的起始位置那么 END 指令的写法如下
START: Start of programcodeEND START指令标签
标签常常放在某个指令前用来表示定义变量标签指向存储数据的首地址。 DC - DC 指令指示汇编器将后续的值放入当前内存位置。该指令有三种形式DC.B 用于字节数据DC.W 用于字16 位数据DC.L 用于长32 位数据。定义常量指令不应与 C 中声明常量混淆。 例如 ORG $1000 start of the data region
depart DC.B depart.wav,0 stores as a NULL terminated string in consecutive bytes DC.L $01234567 the value $01234567 is stored as a long wordDC.W 1,2 two words are stored as $0001 and $0002DC.L 1,2 two long words are stored as $00000001 and $00000002 depart 就是一个label是这块内存区域的首地址。 内存结果
00001000 64 65 70 61 72 74 2E 77 61 76 00
0000100C 01234567
00001010 0001 0002
00001014 00000001 00000002其他关于指令标签的用法参考也可以到指令章节
位置标签
可以定义一些位置标签当进行特殊操作时可以通过控制流opcode跳转到位置标签 实现一个从0end_index的循环打印 ORG $1000
START: ; first instruction of program* Put program code here
* 实现一个从0end_index的循环打印move #1,D1
t:move #3,D0TRAP #15 ;将3任务执行自动打印D1的内容add.b #1,d1 ;让d11CMP #end_index,d1 ;比较d1和end_index的值BNE t ;如果不相等继续跳转到t label执行SIMHALT ; halt simulator* Put variables and constants here
end_index equ 10END START ; last line of sourceopcode 操作码
在 68K 汇编语言中操作码opcode是指令的核心部分定义了要执行的操作。以下是一些常用的 68K 操作码及其功能
常用操作码
注意大部分操作码都可以添加结尾.W表示字2个字节16位.L表示双字(4个字节32位).B1个字节8位
数据传送
- MOVE将数据从一个位置移动到另一个位置。- 例MOVE.W D0, D1将 D0 的值移动到 D1
- MOVEA将地址从一个位置移动到另一个位置。- 例MOVEA.L A0, A1将 A0 的地址移动到 A1算术运算
- ADD将两个操作数相加。- 例ADD.W D0, D1将 D0 的值加到 D1
- SUB从一个操作数中减去另一个操作数。- 例SUB.W D1, D0从 D0 中减去 D1
- MULS有符号乘法。- 例MULS D0, D1将 D0 和 D1 相乘结果存储在 D1
- DIVS有符号除法。- 例DIVS D0, D1将 D1 除以 D0结果存储在 D1逻辑运算
- AND按位与运算。- 例AND.W D0, D1D1 与 D0 按位与
- OR按位或运算。- 例OR.W D0, D1D1 与 D0 按位或
- EOR按位异或运算。- 例EOR.W D0, D1D1 与 D0 按位异或
- NOT按位取反。- 例NOT.W D0D0 的值取反控制流
常用如下
- BRA无条件跳转。- 例BRA label跳转到指定标签
- BEQ如果相等则跳转。- 例BEQ label如果零标志位被设置则跳转
- BNE如果不相等则跳转。- 例BNE label如果零标志位未设置则跳转
- JSR跳转到子程序。- 例JSR subroutine跳转到子程序并保存返回地址
- RTS从子程序返回。- 例RTS返回到调用子程序的地址分支跳转
该指令将在程序中引发分支如果某些标志被设置。共有十五种检查标志的方法。每种方法都有一个由两个字母组成的符号用于替换 “cc” 在 “Bcc” 中。
BCC分支如果进位标志清除 - 当 C 标志为 0 时分支。BCS分支如果进位标志设置 - 当 C 标志为 1 时分支。BEQ分支如果相等 - 当 Z 标志为 1 时分支。BNE分支如果不相等 - 当 Z 标志为 0 时分支。BGE分支如果大于或等于 - 当 N 和 V 相等时分支。BGT分支如果大于 - 当 N 和 V 相等且 Z0 时分支。BHI分支如果高于 - 当 C 和 Z 都为 0 时分支。BLE分支如果小于或等于 - 当 Z1 或 N 和 V 不同时分支。BLS分支如果小于或相同 - 当 C1 或 Z1 时分支。BLT分支如果小于 - 当 N 和 V 不同时分支。BMI分支如果负 - 当 N1 时分支。BPL分支如果正 - 当 N0 时分支。BVC分支如果溢出标志清除 - 当 V0 时分支。BVS分支如果溢出标志设置 - 当 V1 时分支。BRA无条件分支 - 始终分支。 上面这些opcode根据标志触发跳转只能跳转到label注意进入label后会往下执行和函数调用不一样函数调用会返回继续执行之前代码的下一行这个不会是直接跳转过去不回来了。 例子 ORG $1000
START: ; first instruction of program* Put program code here
input:move.b #4,d0TRAP #15CMP #0,d1BNE input ;如果不等于0跳转到input标签继续让输入数字BEQ exit ;如果等于0直接退出labelexit:SIMHALT ; halt simulator* Put variables and constants hereEND START ; last line of source地址跳转
JMP跳转用于将程序控制转移到一个有效地址。它实际上相当于 MOVE.L xxx, PC因为它将程序计数器更改为一个有效地址计算得出。 注意JMP是无条件跳转相对于B开头的跳转他也支持 JMP label的语法同时他也支持直接JMP 地址的跳转。 ORG $1000
START: ; first instruction of program* Put program code here
input:move.b #4,d0TRAP #15CMP #0,d1BNE input ;如果不等于0跳转到input标签继续让输入数字BEQ exit ;如果等于0直接退出labelexit:LEA quit,a0 ;0跳转到这里后将quit的地址给到a0JMP直接跳转到地址,相当于move.l a0,PC这是伪代码JMP (a0) ;如果想跳转到a0的下一个地址可以1(a0) 或者n(a0),当然也可以直接JMP quitquit:SIMHALT ; halt simulator* Put variables and constants hereEND START ; last line of source子程序跳转
JSR/BSR跳转到子例程与 JMP无条件跳转类似但在跳转之前JSR 会将跳转指令后面的地址压入栈中这样可以通过 RTS返回子例程指令返回也就相当于调用函数函数执行完了执行代码的下一行。 BSR适合同一代码段里的label直接调用是相对掉哟个JSR适合指定一个绝对地址调用(比如JSR $5000) ,但是实际上两个可以互相替换没啥区别。 ORG $1000
START: ; first instruction of program* Put program code here
input:JSR input_notion ;JSR执行完后会自动执行下一行代码B开头的跳过去就不回来了move.b #4,d0TRAP #15CMP #0,d1BNE input ;如果不等于0跳转到input标签继续让输入数字BEQ exit ;如果等于0直接退出
input_notion: ;屏幕上输出提示语MOVE #14,D0LEA INPUT_STR,A1TRAP #15RTS ;注意返回了会运行调用这个函数的下一行
confirm_exit *屏幕上输出确认提示语MOVE #14,D0LEA CONFIRM_STR,A1TRAP #15RTS
exit:JSR confirm_exitmove.b #4,d0TRAP #15CMP #0,d1BEQ quitBNE input
quit:SIMHALT ; halt simulator* Put variables and constants here
INPUT_STR: dc.b please input number(exit0):,0
CONFIRM_STR: dc.b confirm exit(:exit0,not1):,0END START ; last line of source效果
位操作
- SHL左移。- 例SHL.W #1, D0D0 左移 1 位
- SHR右移。- 例SHR.W #1, D0D0 右移 1 位
- ROL循环左移。- 例ROL.W #1, D0D0 循环左移 1 位
- ROR循环右移。- 例ROR.W #1, D0D0 循环右移 1 位比较
- CMP比较两个操作数。- 例CMP.W D0, D1比较 D0 和 D1 的值堆栈操作
- PUSH将数据压入堆栈。- 例PUSH.W D0将 D0 的值压入堆栈
- POP从堆栈弹出数据。- 例POP.W D0从堆栈弹出值到 D0IO操作码
TRAP #15 被用于触发 I/O. 不同的io流任务存储在 D0. 参考chm 常用的输入输出任务
14: 将A1地址对应的字符串输出 以0结尾结束。13将A1地址对应的字符串输出 以0结尾结束加上\r\n换行。2: 从控制台获取一个字符串回车后存储在A1地址中 0结尾。4读取一个数字写入D1.L中。
例子
START ORG $1000 Program load address.move #14,D0 ;设置14号任务打印A1地址字符串lea text,A1 ;获text地址到A1trap #15 ;激活任务SIMHALT text dc.b Hello World,0 ;0表示字符串结束END START End of source with start address specified.
其他操作码
关于更加详情的指令参考chm
directives 指令
指令是汇编器需要遵循的指令。它们占据源代码行中的第二个字段与指令操作码占据的位置相同但指令并不是 68000 操作码。 “DC” 和 “DCB” 是唯一会导致数据被添加到输出文件中的指令。指令还可以用于控制宏的汇编、条件汇编和结构化语法。
在以下描述中选项项用方括号 [] 表示。用斜体显示的项应替换为适当的语法。
Usage:
[label] directive[.size] [data,data,...]^ ^ ^\_________________\_________\_____ varies by directiveDC指令
全称Define Constant定义常量用途用于定义并初始化数据常量。DC 指令可以用于定义一个或多个初始值这些值会被存储在程序的输出文件中。内存分配DC 指令会在程序的内存中分配实际的存储空间并将指定的值写入该空间。示例 使用语法
Usage:
[label] DC.size data,data,...例子
VALUE1 DC 10 ; 定义常量 VALUE1值为 10
VALUE2 DC 20, 30 ; 定义常量 VALUE2值为 20 和 30特性 定义的值在程序运行时是不可更改的。实际在内存中占用空间。 注意下面的代码修改地址的值是非法的常量无法修改 START: ; first instruction of programlea usercount,A0move.b 20,(A0) ;修改A0地址的常量这是非法的。
* Put program code hereSIMHALT ; halt simulator* Put variables and constants hereORG $1200
usercount dc.b 10,20dc.w 23EQU 指令 全称Equate等于 用途用于定义一个符号并将其与一个值关联。EQU 定义的值在整个程序中是不可更改的通常用于定义常量或符号地址类似于c语言的#define在预编译将对应引用的地方替换为值。 内存分配EQU 不会在内存中分配实际的存储空间。它只是创建一个符号所有使用该符号的地方都会被替换为其定义的值。 示例 MAX_SIZE EQU 100 ; 定义常量 MAX_SIZE值为 100 特性 一旦定义EQU 的值不能被修改。不占用内存空间编译时进行替换 ORG $1000 ; 程序起始地址
START: ; 将立即数 10 移动到 D0 寄存器; 定义常量
MAX_COUNT EQU 2 ; 定义 MAX_COUNT 为 100
START_VALUE EQU 1 ; 定义 START_VALUE 为 10MOVE.B #10, D0ADD.B #MAX_COUNT, D0 ; 将 MAX_COUNT (100) 加到 D0SUB.B #START_VALUE, D0 ; 将 START_VALUE (10) 从 D0 中减去SIMHALT ; 停止模拟器ORG $1200 ; 数据段起始地址END STARTSET 指令 用途用于定义一个符号并赋予一个初始值但与 DC 不同的是SET 定义的值是可更改的。SET 通常用于在程序运行时动态地改变值。 示例 COUNT SET 0 ; 定义符号 COUNT初始值为 0 COUNT SET COUNT 1 ; 重新定义 COUNT值为 COUNT 1 内存分配SET 指令并不分配实际的存储空间来存储值而是定义一个符号允许在程序中动态地改变该符号的值。
DS 指令 全称Define Space定义空间 用途用于定义一块未初始化的内存空间。DS 指令只分配内存但不初始化这些内存的值随时可改。 示例 BUFFER DS 256 ; 定义一个大小为 256 字节的缓冲区 内存分配DS 指令会在输出文件中分配指定大小的内存空间但这些空间的初始值是未定义的通常是随机值或零具体取决于系统。
定义一个100字节的空间可以理解为数组将MULT_TABLE数字第一个位置设置为12 ORG $1000
START: ; first instruction of program* Put program code heremove.B #0,D0LEA MULT_TABLE, A0MOVE.B #12,(A0, D0)SIMHALT ; halt simulatorORG $1200
* Put variables and constants hereMULT_TABLE: ; 乘法表的存储位置DS.B 10 * 10 ; 预留 10x10 的空间END START ; last line of source其他指令
参考chm
寄存器
程序计数器PC
程序计数器有时在不同的体系结构中也称为指令指针或指令地址寄存器保存下一条将要执行的指令的内存地址。每当 CPU 执行一条指令时PC 的值会自动更新以指向下一条指令。 更新机制在大多数情况下PC 在指令执行后自动加一或加上指令的长度以指向下一条指令的地址。 编写一个简单程序 运行默认会从start:的写一条语句开始PC寄存器指向初始代码的地址注意有效的代码时左侧绿色点点的其他都是指令或者注释 按下F8执行到下一条 我这里将usercount的地址指向A0 ,同时加了ORG $1200从1200这个地址写入。点击A0的地址可以查看内存
状态寄存器SR
在 68kMotorola 68000架构中状态寄存器SRStatus Register是一个重要的寄存器用于存储处理器的状态信息和控制标志。状态寄存器的内容影响程序的执行流程特别是在条件跳转和中断处理时。以下是对 68k 状态寄存器的详细介绍
状态寄存器的结构
68k 的状态寄存器是一个 16 位的寄存器包含多个标志位。主要的标志位包括 NNegative: 表示最近一次运算的结果是否为负数。如果结果的最高位符号位为 1则 N 标志被设置。 ZZero: 表示最近一次运算的结果是否为零。如果结果为 0则 Z 标志被设置。 VOverflow: 表示最近一次运算是否发生了溢出。溢出通常发生在有符号数运算中当结果超出可表示的范围时V 标志被设置。 CCarry: 表示最近一次运算是否产生了进位或借位。在加法运算中如果产生了进位C 标志被设置在减法运算中如果发生了借位C 标志也会被设置。 IInterrupt Mask: 这是一个 3 位的中断屏蔽位控制中断的响应。I0、I1 和 I2 位用于设置中断优先级值越大响应的中断优先级越低。 TTrace: 这是一个单个位用于启用或禁用跟踪模式。当 T 位被设置时处理器将在每个指令执行后产生一个中断适用于调试。 SSupervisor: 这是一个单个位指示当前处理器是否处于特权模式超级用户模式。当 S 位被设置时处理器处于超级用户模式允许执行特权指令。
状态寄存器的作用
条件跳转: 状态寄存器中的标志位用于条件跳转指令如 BEQ、BNE 等根据运算结果的状态决定程序的执行路径。中断处理: 中断标志位控制中断的响应允许或禁止特定级别的中断。运算结果的状态: 通过检查 N、Z、V 和 C 标志程序可以根据运算结果的状态做出相应的处理。
示例
以下是一个简单的示例展示如何使用状态寄存器的标志位 MOVE.L #5, D0 ; 将 5 加载到 D0MOVE.L #3, D1 ; 将 3 加载到 D1SUB.L D1, D0 ; D0 D0 - D1结果为 2; 检查 Z 标志BEQ zero_result ; 如果 Z 标志为 1跳转到 zero_result; 检查 N 标志BPL positive_result ; 如果 N 标志为 0跳转到 positive_resultzero_result:; 处理结果为零的情况; ...positive_result:; 处理结果为正的情况; ...
数据寄存器D)
在 6800068k架构中D 寄存器数据寄存器是用于存储数据和操作数的寄存器。68k 处理器有 8 个数据寄存器分别为 D0 到 D7。
D 寄存器的特点 数量: 68k 处理器有 8 个数据寄存器编号为 D0 到 D7。 大小: 每个 D 寄存器的大小为 32 位4 字节可以存储 32 位的整数或指针。 用途: D 寄存器主要用于存储运算的操作数、结果以及临时数据。它们在算术运算、逻辑运算、数据传输等操作中被广泛使用。 寻址模式: D 寄存器可以与多种寻址模式结合使用支持直接寻址、间接寻址等方式方便数据的访问和操作。 操作: D 寄存器可以参与各种指令的操作如加法、减法、位运算等。指令可以直接对 D 寄存器进行操作也可以将 D 寄存器的值存储到内存中或从内存中加载数据。
D 寄存器的使用场景
算术运算: D 寄存器用于存储参与运算的数值。数据传输: 在数据传输指令中D 寄存器可以作为源或目标。函数参数: 在调用子程序时D 寄存器常用于传递参数。
示例
以下是一个简单的汇编代码示例展示如何使用 D 寄存器进行基本的算术运算 MOVE.L #10, D0 ; 将 10 加载到 D0 寄存器MOVE.L #5, D1 ; 将 5 加载到 D1 寄存器ADD.L D1, D0 ; D0 D0 D1D0 现在为 15地址寄存器A)
6800068k架构中A 寄存器地址寄存器是用于存储内存地址的寄存器。68k 处理器有 8 个地址寄存器分别为 A0 到 A7。以下是对 A 寄存器的详细描述
A 寄存器的特点 数量: 68k 处理器有 8 个地址寄存器编号为 A0 到 A7。 大小: 每个 A 寄存器的大小为 32 位4 字节可以存储 32 位的内存地址。 用途: A 寄存器主要用于存储内存地址支持数据的加载和存储操作。它们在指令中用于指向数据或指令的内存位置。 寻址模式: A 寄存器可以与多种寻址模式结合使用包括直接寻址、间接寻址、基址寻址和相对寻址等。这使得程序能够灵活地访问内存中的数据。 堆栈指针: A7 寄存器通常用作堆栈指针SP指向当前堆栈的顶部。堆栈用于存储函数调用的返回地址、局部变量等。
A 寄存器的使用场景
内存访问: A 寄存器用于指向数据在内存中的位置支持数据的读取和写入。函数调用: 在函数调用中A 寄存器可以用于传递参数和返回地址。堆栈管理: A7 寄存器作为堆栈指针管理函数调用的堆栈帧。
示例
以下是一个简单的汇编代码示例展示如何使用 A 寄存器进行内存操作 LEA array, A0 ; 将数组的地址加载到 A0 寄存器MOVE.L (A0), D0 ; 从 A0 指向的地址加载数据到 D0 寄存器ADD.L #1, D0 ; D0 D0 1MOVE.L D0, (A0) ; 将 D0 的值存储回 A0 指向的地址堆栈寄存器SS)
在68k架构中堆栈寄存器是用于管理程序运行时的堆栈的关键组件。68k系列处理器使用一个专用的寄存器来指向当前堆栈的顶部这个寄存器被称为堆栈指针Stack Pointer。
在68k架构中堆栈指针寄存器通常是 A7地址寄存器7它指向当前堆栈的顶部。 堆栈是一个后进先出LIFO的数据结构用于存储临时数据如函数调用的返回地址、局部变量和中断处理程序的上下文。 堆栈操作
我们来看下堆栈指针的移动和数据写入逻辑。 在68k汇编语言中-(A7) 和 (A7) 分别用于表示压栈和出栈操作。 执行代码
move.l #10,-(a7)未执行前原始堆栈地址A7指向01000000没有任何数据 执行move.l #10,-(a7) 执行move.l #20,-(a7) 执行出栈move.l (a7),d0
std函数模拟
我们知道c语言的std约定是调用函数先压入执行代码的后一个位置然后参数从右往左压入在函数内部出栈从左后入先出往右获取参数执行完成获取代码执行的位置跳转。 我们来模拟这个过程 假设函数: public int add(int a,int b) 用98k模拟堆栈实现 ORG $1000
START: ; first instruction of program* Put program code heremove.l #10,-(a7) #第二个参数压栈。move.l #20,-(a7) #第一个参数压栈。LEA *12, A0 *计算下LEA占用4个字节一直到move.l d0,d2是12个字节*12就是从PC当前位置12个就是下一个执行代码的位置move.l a0,4(a7) *将下一个执行的地址压栈JMP addmove.l d0,d2SIMHALT ; halt simulatoradd:move.l (a7),a0 ;地址出栈move.l (a7),d0 ;第一个参数出栈move.l (a7),d1 ;第二个参数出栈add.l d1,d0JMP (a0)* Put variables and constants hereEND START ; last line of source
案例(9*9乘法表)
*-----------------------------------------------------------
* Title :
* Written by :
* Date :
* Description:
*-----------------------------------------------------------ORG $1000
START: ; first instruction of program* Put program code heremove.b #start_index,d2 ;行索引move.b #start_index,d3 ;列索引
row:jsr print_str_line ;到row的部分就添加一个换行jsr调用子程序子程序需要RTS返回add.b #1,d2 ;每运行一次1move.b #start_index,d3cmp #end_index1,d2 ;到达最后一行1直接退出BEQ exitcol:add.b #1,d3move.b d2,d1jsr print_num ;打印行的数字lea tmp_str,a1move.b #*,(a1) ;打印一个*jsr print_strmove.b d3,d1jsr print_num ;打印一个列的数字move.b #,(a1) jsr print_str ;打印一个move.b #1,d4muls d2,d4muls d3,d4move.b d4,d1jsr print_num ;打印一个列的数字move.b # ,(a1) jsr print_str ;打印一个空格cmp d3,d2BEQ rowBNE col
print_num:move.b #3,d0TRAP #15 RTS
print_str:move.b #0,1(a1) ;打印字符的结尾move.b #14,d0TRAP #15 RTS
print_str_line:move.b #0,(a1) ;打印字符的结尾move.b #13,d0TRAP #15 RTS
exit:SIMHALT ; halt simulator* Put variables and constants here
tmp_str ds.b 2
end_index equ 9
start_index equ 0END START ; last line of source
效果