3127 字
16 分钟
sdcc汇编伪指令

汇编助记符中的符号含义#

符号含义说明
Rn工作寄存器 R0~R7n 可取 0~7,表示当前寄存器组中的寄存器
Ri间接寻址寄存器 R0 或 R1i 可取 0 或 1,用于间接寻址
@Ri以 Ri 中的值为地址,访问该地址的数据间接寻址方式,Ri 中存放的是内存地址
#data立即数直接跟在指令后的常数,如 #30H
direct直接地址8位内部 RAM 地址或 SFR 地址,如 30HP1

SDCC伪指令详细说明及示例#

一、段定义伪指令(.area)#

1. 基本格式#

.area 段名 (属性1,属性2,...) [重定位类型]

2. 常用段类型#

; 代码段(程序存储器)
.area CSEG (CODE) ; 常规代码段
.area HOME (CODE) ; 起始段(0x0000-0x00FF)
.area GSINIT (CODE) ; 全局变量初始化代码
.area GSFINAL (CODE) ; 初始化后的代码
; 数据段
.area DSEG (DATA) ; 内部可直接寻址数据(0x30-0x7F)
.area ISEG (DATA) ; 内部间接寻址数据(0x80-0xFF)
.area OSEG (DATA) ; 覆盖数据段
.area XSEG (XDATA) ; 外部数据存储器
.area ESEG (EDATA) ; 扩展数据存储器(STC8G特有)
; 其他
.area RSEG (ABS) ; 绝对定位段
.area ASEG (ABS) ; 绝对段(已过时)
.area BSEG (BIT) ; 位寻址区(0x20-0x2F)

3. 段属性#

  • CODE - 程序代码
  • DATA - 内部RAM数据
  • XDATA - 外部RAM数据
  • EDATA - 扩展RAM数据(STC8G)
  • ABS - 绝对地址
  • BSS - 未初始化数据
  • BIT - 位数据
  • OVR - 可覆盖段
  • REL - 可重定位段
  • CON - 常量段

4. 示例#

; 定义绝对地址中断向量表
.area VEC (ABS)
.org 0x0000
ljmp _main ; 复位向量
.org 0x0003
ljmp _ext0_isr ; 外部中断0
.org 0x000B
ljmp _timer0_isr ; 定时器0中断
; 代码段
.area CSEG (CODE)
_main:
mov SP, #0x80 ; 设置堆栈指针
; 内部数据段
.area DSEG (DATA)
counter:
.byte 0x00 ; 单字节变量
buffer:
.ds 16 ; 16字节缓冲区
; 外部数据段
.area XSEG (XDATA)
large_buffer:
.ds 1024 ; 1KB外部缓冲区
; 位寻址区
.area BSEG (BIT)
flag1: .dbits 1 ; 定义1个位
flags: .dbits 8 ; 定义8个位(1字节)

二、数据定义伪指令#

1. 字节数据#

; 定义字节(8位)
.byte value1, value2, ... ; 定义字节序列
.db value1, value2, ... ; 同.byte
; 示例
data1: .byte 0x12 ; 单个字节
table: .byte 0, 1, 2, 3, 4 ; 数组
str: .byte 'H','e','l','l','o',0 ; 字符串

2. 字数据#

; 定义字(16位)
.word value1, value2, ... ; 定义字序列(小端序)
.dw value1, value2, ... ; 同.word
; 示例
vectors: .word 0x0000, 0x1000, 0x2000 ; 地址表
const: .dw 0x1234, 0x5678 ; 16位常量

3. 双字数据#

; 定义双字(32位)
.long value1, value2, ... ; 32位数据
.dl value1, value2, ... ; 同.long
; 示例
long_val: .long 0x12345678 ; 32位值
float_val: .long 0x4048F5C3 ; 浮点数(3.14的IEEE754表示)

4. 浮点数#

; 定义浮点数
.float value1, value2, ... ; 单精度浮点数
; 示例
pi: .float 3.1415926
temp: .float 25.5

5. 字符串#

; ASCII字符串
.ascii "string" ; 无结束符
.asciz "string" ; 以\0结尾
; 示例
msg1: .ascii "Error" ; 长度5
msg2: .asciz "Hello" ; 长度6(含\0)

6. 保留空间#

.ds size ; 保留size字节空间
.blkb size ; 同.ds(块)
; 示例
buffer: .ds 100 ; 100字节缓冲区
stack: .blkb 32 ; 32字节堆栈空间

7. 位数据#

; 位定义(仅用于BSEG段)
.dbits size ; 定义size个位
; 示例
.area BSEG (BIT)
flags: .dbits 8 ; 8个标志位
status: .dbits 1 ; 单状态位

三、符号定义伪指令#

1. 常量定义#

; 等值定义
.equ symbol, value ; 定义符号常量
.set symbol, value ; 同.equ(可重复定义)
= symbol = value ; 另一种形式
; 示例
.equ BUFFER_SIZE, 256 ; 定义常量
.set COUNTER_MAX, 1000
TIMEOUT = 5000 ; 使用等号

2. 全局符号声明#

.globl symbol ; 声明全局符号
.global symbol ; 同.globl
.gblel symbol ; 声明全局外部符号
; 示例
.globl _main ; C主函数
.globl _isr_timer0 ; 中断服务函数

3. 外部符号声明#

.extern symbol ; 声明外部符号
.external symbol ; 同.extern
; 示例
.extern _printf ; 外部C函数
.extern buffer ; 外部变量

四、条件汇编伪指令#

1. 基本条件#

; 条件块
.if condition ; 开始条件
.else ; 否则分支
.endif ; 结束条件
; 示例
.if DEBUG == 1
mov A, #0x55 ; 调试代码
.else
mov A, #0xAA ; 发布代码
.endif

2. 符号条件#

; 符号检查
.ifdef symbol ; 如果符号已定义
.ifndef symbol ; 如果符号未定义
; 示例
.ifdef USE_UART
call uart_init ; 如果定义了USE_UART
.endif
.ifndef OPTIMIZE
nop ; 如果没有优化
.endif

3. 比较条件#

; 比较表达式
.ifeq expression ; 如果等于
.ifne expression ; 如果不等于
.ifgt expression ; 如果大于
.ifge expression ; 如果大于等于
.iflt expression ; 如果小于
.ifle expression ; 如果小于等于
; 示例
.ifeq VERSION-2
ljmp legacy_code ; VERSION==2时
.else
ljmp new_code ; 其他情况
.endif

五、宏定义与使用#

1. 基本宏定义#

; 宏定义
.macro macroname [param1, param2, ...] ; 定义宏
; 宏体
.endm ; 结束宏
; 示例:延时宏
.macro DELAY cycles
mov R7, #(\cycles & 0xFF) ; 使用参数
djnz R7, $
.endm
; 使用宏
DELAY 100 ; 扩展为:mov R7, #100; djnz R7, $
DELAY 255 ; 扩展为:mov R7, #255; djnz R7, $

2. 带参数的宏#

; 带多个参数的宏
.macro MOV16 src, dst
mov A, \src ; 参数前加反斜杠
mov \dst, A
mov A, \src+1
mov \dst+1, A
.endm
; 使用
MOV16 #0x1234, R6 ; 将16位值传送到R6:R7

3. 局部标签宏#

; 带局部标签的宏
.macro DELAY_MS ms
mov R5, #\ms
1$: ; 局部标签(数字+$)
mov R6, #200
2$:
mov R7, #250
djnz R7, $
djnz R6, 2$
djnz R5, 1$
.endm

4. 条件宏#

; 条件判断宏
.macro BIT_SET reg, bit
.if \bit < 8
setb \reg.\bit ; 使用位操作符
.else
.error "Bit out of range"
.endif
.endm
; 使用
BIT_SET P1, 0 ; setb P1.0
BIT_SET ACC, 3 ; setb ACC.3

5. 嵌套宏#

; 宏嵌套
.macro PUSH_REG reg
push \reg
.endm
.macro PUSH_REGS regs
.irp reg, \regs ; 迭代参数列表
PUSH_REG \reg
.endm
.endm
; 使用
PUSH_REGS ACC, B, PSW ; 压栈多个寄存器

6. 宏函数示例#

; 计算平方的宏函数
.macro SQUARE x, result
mov A, #\x
mov B, A
mul AB
mov \result, A ; 低8位
mov \result+1, B ; 高8位
.endm
; 使用
SQUARE 5, square_result
; 带返回值的宏
.macro ADD16 a, b
mov A, \a
add A, \b
mov R0, A
mov A, \a+1
addc A, \b+1
mov R1, A
; 结果在R0:R1中
.endm

六、包含文件与模块化#

1. 包含文件#

.include "filename.inc" ; 包含汇编文件
.include <stddef.h> ; 包含C头文件(需要-i指定路径)
; 示例
.include "stc8g.h"
.include "macros.inc"
.include "config.inc"

2. 模块化组织#

; 主文件 main.asm
.module main
.globl _main
.include "uart.inc"
.include "timer.inc"
_main:
call uart_init
call timer_init
; ...
; 子模块 uart.inc
.module uart
.globl uart_init, uart_send
uart_init:
; ...
ret
uart_send:
; ...
ret

七、地址控制伪指令#

1. 地址定位#

.org address ; 设置当前位置
.radix base ; 设置数字基数(2,8,10,16)
; 示例
.radix 16 ; 设置为16进制
.org 1000H ; 从1000H开始
.byte 1,2,3,4
.org 2000H ; 跳转到2000H
.word 1234H

2. 对齐#

.even ; 对齐到偶数地址
.odd ; 对齐到奇数地址
.align power ; 对齐到2^power边界
; 示例
.align 4 ; 对齐到16字节边界
data: .ds 10
.even ; 确保下面代码在偶地址
code: mov A, #0

八、列表控制伪指令#

1. 列表文件控制#

.list ; 开启列表
.nolist ; 关闭列表
.lst ; 生成列表文件
.nolst ; 不生成列表文件
; 示例
.nolist ; 不列出包含文件内容
.include "macros.inc"
.list ; 恢复列表

2. 其他控制#

.title "标题" ; 设置标题
.sbttl "子标题" ; 设置子标题
.page ; 分页
.width columns ; 设置列宽

九、标签的 : 和 :: 区别#

1. 单冒号 :(局部标签)#

; 局部标签(默认)
label1: ; 局部标签,文件内可见
nop
; 示例
loop: ; 局部循环标签
djnz R7, loop ; 可访问
func1:
call subfunc
ret
subfunc: ; 另一个局部标签
nop
ret

2. 双冒号 ::(全局标签)#

; 全局标签
label2:: ; 全局标签,外部可访问
; 示例
.globl _main ; 需要配合.globl声明
_main:: ; C入口函数(全局)
mov SP, #0x80
; 中断服务函数(全局)
_ext0_isr::
push PSW
; ... 中断处理
pop PSW
reti
; 在另一个文件中可这样引用
.extern _main ; 声明外部全局符号
.extern _ext0_isr

3. 标签作用域规则#

; 文件: module1.asm
.local_label: ; 仅本文件可见
nop
global_label:: ; 全局可见(自动.globl)
nop
.globl exported_label ; 需要显式声明
exported_label: ; 全局可见(需.globl)
nop
; 文件: module2.asm
.extern global_label ; 引用全局标签
.extern exported_label
call global_label ; 可调用
call exported_label ; 可调用
; call local_label ; 错误!不可访问

4. 数字标签(局部)#

; 数字标签(自动局部)
1: ; 数字标签,可重复定义
nop
jb P1.0, 1b ; 向后跳转到最近的1:
2: ; 另一个数字标签
nop
jnb P1.1, 2f ; 向前跳转到下一个2:
; 示例:循环中使用
mov R7, #10
1$: ; 带$的数字标签(推荐)
djnz R7, 1$ ; 向后跳转
; 嵌套循环
mov R6, #5
2$:
mov R7, #10
1$:
djnz R7, 1$
djnz R6, 2$

十、完整示例#

; ============================================
; STC8G 汇编程序示例
; ============================================
; 包含头文件
.include "stc8g.inc"
; 常量定义
.equ BUFFER_SIZE, 256
.equ LED_PIN, P1_0
.equ BUTTON_PIN, P3_2
.set TIMEOUT, 1000
; 宏定义
.macro DELAY_US us
.if \us > 0
mov R7, #((\us * 2) & 0xFF)
1$: djnz R7, 1$
.endif
.endm
.macro LED_ON
setb LED_PIN
.endm
.macro LED_OFF
clr LED_PIN
.endm
.macro TOGGLE_LED
cpl LED_PIN
.endm
; 位定义
.area BSEG (BIT)
button_flag: .dbits 1 ; 按键标志
tx_busy: .dbits 1 ; 发送忙标志
rx_ready: .dbits 1 ; 接收就绪标志
; 数据段
.area DSEG (DATA)
counter: .byte 0
buffer: .ds BUFFER_SIZE
tx_index: .byte 0
rx_index: .byte 0
; 绝对地址段(中断向量)
.area VEC (ABS)
.org 0x0000
ljmp _main ; 复位向量
.org 0x0003
ljmp ext0_isr ; INT0中断
.org 0x000B
ljmp timer0_isr ; Timer0中断
.org 0x0023
ljmp uart_isr ; UART中断
; 代码段
.area CSEG (CODE)
; ============================================
; 主程序
; ============================================
.globl _main
_main::
; 初始化堆栈
mov SP, #0x80
; 初始化端口
mov P1M0, #0x01 ; P1.0推挽输出
mov P1M1, #0x00
; 初始化定时器
call timer0_init
; 初始化串口
call uart_init
; 使能中断
setb EA
setb EX0 ; 使能INT0
setb ET0 ; 使能Timer0
setb ES ; 使能串口中断
; 主循环
main_loop:
; 检查按键
jnb button_flag, no_button
clr button_flag
; 按键处理
TOGGLE_LED
call send_message
no_button:
; 检查接收数据
jnb rx_ready, main_loop
clr rx_ready
; 处理接收数据
call process_data
sjmp main_loop
; ============================================
; 延时函数(毫秒)
; 使用宏实现
; ============================================
.macro DELAY_MS ms
push ACC
push PSW
mov A, #\ms
call delay_ms_func
pop PSW
pop ACC
.endm
; 实际的延时函数
delay_ms_func:
mov R6, A
1$: mov R7, #200
2$: mov R8, #250
3$: djnz R8, 3$
djnz R7, 2$
djnz R6, 1$
ret
; ============================================
; 中断服务函数
; ============================================
ext0_isr::
push PSW
push ACC
; 防抖延时
DELAY_US 100
; 设置按键标志
setb button_flag
pop ACC
pop PSW
reti
timer0_isr::
push PSW
push ACC
; 定时器处理
inc counter
; 1秒闪烁
mov A, counter
anl A, #0x80
jz timer_done
TOGGLE_LED
timer_done:
pop ACC
pop PSW
reti
uart_isr::
push PSW
push ACC
; 串口中断处理
jnb RI, uart_tx_check
clr RI
; 接收数据
mov A, SBUF
call store_rx_data
uart_tx_check:
jnb TI, uart_done
clr TI
setb tx_busy ; 发送完成
uart_done:
pop ACC
pop PSW
reti
; ============================================
; 子函数
; ============================================
; 初始化定时器0
timer0_init::
mov TMOD, #0x01 ; 定时器0模式1
mov TH0, #0xFC ; 1ms定时
mov TL0, #0x66
setb TR0 ; 启动定时器
ret
; 初始化串口
uart_init::
mov SCON, #0x50 ; 模式1,允许接收
mov PCON, #0x80 ; 波特率加倍
mov TH1, #0xFD ; 9600 bps @11.0592MHz
mov TL1, #0xFD
setb TR1 ; 启动定时器1
ret
; 存储接收数据
store_rx_data:
push PSW
mov PSW, #0x10 ; 使用第2组寄存器
mov R0, rx_index
mov @R0, A ; 存储数据
inc rx_index
; 设置接收就绪标志
setb rx_ready
pop PSW
ret
; 发送消息
send_message::
mov DPTR, #welcome_msg
call send_string
ret
; 发送字符串
send_string:
push ACC
1$: clr A
movc A, @A+DPTR
jz send_done
call send_char
inc DPTR
sjmp 1$
send_done:
pop ACC
ret
; 发送单个字符
send_char:
jnb tx_busy, $ ; 等待发送完成
clr tx_busy
mov SBUF, A
ret
; 处理数据
process_data::
; 处理接收缓冲区数据
ret
; ============================================
; 常量数据
; ============================================
welcome_msg:
.asciz "STC8G Ready!\r\n"
; ============================================
; 程序结束
; ============================================
.end

十一、编译与链接#

1. 编译命令#

Terminal window
# 编译汇编文件
sdcc -c -mmcs51 --model-small example.asm
# 编译C文件(含内联汇编)
sdcc -c -mmcs51 --model-small main.c
# 链接目标文件
sdcc -mmcs51 --model-small example.rel main.rel
# 生成Intel HEX文件
packihx example.ihx > example.hex

2. Makefile示例#

TARGET = example
SRCS = main.asm uart.asm timer.asm
OBJS = $(SRCS:.asm=.rel)
CC = sdcc
CFLAGS = -mmcs51 --model-small --opt-code-size
all: $(TARGET).hex
$(TARGET).hex: $(OBJS)
$(CC) $(CFLAGS) $(OBJS) -o $(TARGET).ihx
packihx $(TARGET).ihx > $(TARGET).hex
%.rel: %.asm
$(CC) -c $(CFLAGS) $<
clean:
rm -f *.rel *.asm *.lst *.sym *.ihx *.hex *.map

十二、注意事项#

  1. 大小写敏感:SDCC汇编器是大小写敏感的
  2. 下划线规则:C函数在汇编中前加下划线(如 _main
  3. 参数传递:通过寄存器R5-R7传递参数
  4. 返回值:8位在A中,16位在DPL/DPH中
  5. 内存模型:使用 --model-small--model-medium--model-large 指定
  6. 优化选项:使用 --opt-code-size--opt-code-speed
  7. 调试信息:使用 --debug 生成调试信息
sdcc汇编伪指令
https://www.mintlab.top/posts/stc8g汇编笔记/stc8g_asm_guide/
作者
Mint
发布于
2025-11-21
许可协议
CC BY-NC-SA 4.0
发表评论

输入用户名和邮箱后自动检查登录状态。登录后用户名和邮箱将被绑定, 只可以修改头像和主页链接。

未登录
昵称
邮箱
填写头像链接与主页链接

头像链接为空默认使用gravatar头像

头像
主页
评论列表

以下是可爱的评论们:

暂无评论, 呜呜, 快来评论喵!