6502汇编语言程序设计(2版)之程序设计part2

6502汇编语言程序设计 返回

第二部分 指令和算法 返主题

一. 简单查找

在内存中查找数据时我们常用绝对X变址或绝对Y变址指令(lda label,x或lda label,y)通过令X+1→X来向前搜索(或X-1→X向后搜索). 例: 判断字符"$"是否在某段字符串stringM定义区内,字符串以0为结束.

stringM: db "0123456789ABCDEFabcdefHh$ox"

... ...

db "+-*/%^#",0

chardef: db "$"

start:

lda chardef

ldx #$00

start02:

cmp stringM,x

beq start04 ;找到分支出口,(X)为"$"所在stringM标号后的所在位置

inx

bne start02

clc ;设置没有找到标志 当X从0加到FF后,又轮回到0时

rts

start04:

sec ;设置找到标志

rts

 

这种方法查找简单,很好设计,但是它的查找范围不得超过寄存器X所容纳的一个字节数据的偏移地址内,否则就要调整基址值才能再找.程序就会变得复杂些.下面介绍一种用指针的方法来查找.

注意指令 lda (zeropage,x) 和lda (zeropage),y zeropage零页单元地址. 在查找过程中,对于使用lda (zeropage,x)如果保持X为零,那么单元 zeropage和zeropage+1组合构成了一个访问指针,它指向程序的某个地址,两个字节刚好能对$0000--$FFFF之间进行访问,在程序中我们可以令(zeropage+1|zeropage)+1→(zeropage+1|zeropage)来对下一个地址进行访问,也即通过对 zeropage和zeropage+1两个单元内容进行改写,就可以实现对不同地址的访问.( 说明 zeropage+1表示zeropage后的一个单元,如:zeropage为$d1单元,则zeropage+1表示$d2单元)

令(zeropage+1|zeropage)+1程序如下:

p_add:

inc zeropage

bne p_add02 ;没有加到0时

inc zeropage+1 ;表示指针低位从FF加到了0,指针高位就增加一

p_add02:

rts

程序例: 查找某个单元内定义的字符是否在某段字符集区,设该段字符集以0为结束标志.若找到返回C=1,没找到返回C=0

stringdef: ;查找区域定义

db "0123456789ABCDEFabcdef"

db "Hh$ox"

... ...

db "+-/*%^#>=<",0

chardef: db "A" ;被查的字符单元

find_p: equ $d1 ;定义指针所在零页的位置

start:

lda chardef

ldx #
ldy #>stringdef

find:

sta find_ch

sty find_p

stx find_p+1 ;查找指针设设置,令指针指向要查找的地址

ldx #$00

find02:

lda (find_p,x) ;读取(find_p+1|find_p)所指向单元内的字节数据

beq find_n ;没有找到,已查到字符串末0标志

cmp find_ch ;判断所读取到A中的是否与定义的相同

beq find_y ;等于,找到分支

jsr find_next ;否则,令指针加一

jmp find02 ;继续下一个

find_y:

sec ;找到,返回 C=1

rts

find_n:

clc ;没找到,返回C=0

rts

find_ch: db

$00

find_next: ;查找令指针加一

inc find_p

bne find_next02

inc find_p+1

find_next02:

rts

 

用这种方法来做查找时也很方便高效,但它要占用零页单元,由于6502系统零页很有限,而且其它程序也会利用到零页单元,故不能定义较多这样的指针.下面再介绍一个很不错方法,同样以上面的要求为例,但是通过直接改写 lda 或sta (用X或Y寄存器做ldx ,sty等 也能完成)后的单元来实现对不同单元来访问的.程序与上例略有不同.

stringdef: ;查找区域定义

db "0123456789ABCDEFabcdef"

db "Hh$ox"

... ...

db "+-/*%^#>=<",0

chardef: ;被查字符

db "A"

start:

lda chardef

ldx #
ldy #>stringdef

search

sta search_ch

stx search_p+2

sty search_p+1 ;查找指针设设置,令指针指向要查找的地址

search02:

jsr search_p ;读出指针指向的单元的数

beq search_n ;没有找到,已查到字符串末0标志

cmp search_ch ;判断所读取到A中的是否与定义的相同

beq search_y ;等于,找到分支

jsr search_next ;否则,令指针加一

jmp search02 ;继续下一个

search_y:

sec ;找到,返回 C=1

rts

search_n:

clc ;没找到,返回C=0

rts

search_ch:

db $00

search_p:

lda $7000 ; 指针定义处

rts

search_next: ;查找令指针加一

inc search_p+1

bne search_next02

inc search_p+2

search_next02:

rts

上面的子程序较为通用, 例检查当前寄存器A中的数据是否为16进制字符,只要将16进制定义串地址递交到寄存器X|Y中,然后调用一下就可以从返回C=1或C=0来判断是或否 即:

hexstrdef:

db "0123456789ABCDEFabcdef"

db "Hh$",0

hexaddr:

dw hexstrdef

start:

ldx hexaddr+1

ldy hexaddr

jsr search ;调用检查

bcc start02

lda #"Y"

jsr putc ;是,在屏幕上输出"Y"

jmp exit ;退出程序

start02:

lda #"N"

jsr putc ;否,在屏幕上输出"N"

jmp exit ;退出程序

二. 几个常用的作法

1.我们把内存单元的内容乘以2时常常用左移的方法来完成,如做($FB|$FA)*2→($FB|$FA)程序如下:

clc

rol $FA

rol $FB

或者:

asl $FA

rol $FB

 

2.($FB|$FA)/2→($FB|$FA) 程序如下:

clc

ror $FB

ror $FA

可以通过状态寄存器的C位来判断余0或1

3. 对寄存器A内的数据,可以通过 eor #$FF 来实现按位取反,如果要保留某些位的内容,只要把$FF中的对应位改为0即可,例把寄存器A的低四位按位取反: eor #$0F . 把第四、五位按位取反: eor #$18

4. 加法操作:

例: ($FB|$FA)+($FD|$FC)→($FF|FE) 程序

如下:

clc

lda $FA

adc $FC

sta $FE

lda $FB

adc $FD

sta $FF

5. 减法操作:

例: ($FB|$FA)-($FD|$FC)→($FF|FE) 程序如下:

sec

lda $FA

sbc $FC

sta $FE

lda $FB

sbc $FD

sta $FF

 

说明一下,$FB|$FA 表示用两个8位单元合成一个16位字或整型数,其中较大的为高位放在前面,较小的为低位放在后面

三. 子程序的设计

在作子程序设计时,一个很重要的问题就是主程序如何向子程序传递参数以及结果的返回.通常有:寄存器法,固定单元法,堆栈法,指针法. 对于结果的返回如果只是简单的是或否,则可通过状态寄存器C位的设置来实现.

1.寄存器法. 当子程序所要的参数很少时,可用寄存器直接携带子程序所需的参数,6502主要可携带参数的寄存器为: A,X,Y

这三个. 例: 做一个小写字母识别的子程序,然后判断单元location内是否为小字母.是,在屏幕显示"Y". 否,在屏幕显示"N".

程序如下:

子程序部分:

islower:

cmp #"a"

bcc islower_n

cmp #"z"+1

bcc islower_y

islower_n:

clc ;否设置

rts

islower_y:

sec ;是设置

rts

;主程序:

location: db "i"

main:

lda location

jsr islower

bcc main02

lda #"Y"

jsr putc ;显示"Y"

jmp exit ;结束程序

main02:

lda #"N"

jsr putc ;显示"N"

jmp exit ;结束程序

程序中用寄存器A为子程序islower传递所需参数.

2. 固定单元法. 例:($A2|$A1)*($A4|$A3)=($A6|$A5|$A4|$A3) 其中用了$A1~$A4作为子程序参数单元,$A3~$A6作为调用后的结果返回值单元. 程序:

MUL:

lda #0

ldy #16

sta $A5

sta $A6

clc

MUL02:

ror $A4

ror $A3 ;乘数从左到右的把位移出判断,移出的同时,把不参加运算的积低位移进乘数单元高位来。

dey

bmi MUL08

bcc MUL04 ;如果乘数移出到状态寄存器C位为0时,直接将积单元位移

lda $A1 ;否则累加后再位移

clc

adc $A5

sta $A5

lda $A2

adc $A6

sta $A6

MUL04:

ror $A6 ;

ror $A5 ;

jmp MUL02

MUL08:

rts

 

3.堆栈法 例:把十进制数(0~65535)转换成机内2字节整型数据($0000~$FFFF)

说明:堆栈指针+1 返回地-1高位,堆栈指针+2 返回地-1低位,堆栈指针+3~+7

无符号十进制字符串,低位先进。出口:堆栈指针+1内存中数低位,+2内存数高

位.堆栈中的返回地址是由JSR指令产生的.

子程序部分:

decbinData: .DB $00,$00,$00,$00,$00

dectobin:

pla

sta dectobinRtn2+1

pla

sta dectobinRtn1+1

ldx #$04 ;65535

dect

obin02: ;A*10=2*(A*2*2+A)

pla

sec

sbc #$30

sta decbinData,x

cpx #$00

beq dectobin04

dex

jmp dectobin02

dectobin04:

stx dectobin_L+1

stx dectobin_H+1

dectobin08:

lda decbinData,x

clc

adc dectobin_L+1

sta dectobin_L+1

lda #$00

adc dectobin_H+1

sta dectobin_H+1 ;将decbinData以次累加到decbin中

inx

cpx #$05

beq dectobin_H ;

asl dectobin_L+1

rol dectobin_H+1 ;(decbin+1|decbin)*2

ldy dectobin_H+1

lda dectobin_L+1

asl dectobin_L+1

rol dectobin_H+1 ;*2

asl dectobin_L+1

rol dectobin_H+1 ;*2

clc

adc dectobin_L+1

sta dectobin_L+1

tya

adc dectobin_H+1

sta dectobin_H+1 ;var*10= (var*2)*2*2+(var*2)

jmp dectobin08

dectobin_H:

lda #$00 ;高位

pha

dectobin_L:

lda #$00 ;低位

pha

dectobinRtn1:

lda #$00 ;返回地低位

pha

dectobinRtn2:

lda #$00 ;返回地高位

pha

rts

4.指针法. 例: 在屏幕上显示字符串,字符串以0为结束. 入口: X|Y=字符串首在址

printf:

stx printf02+2

sty printf02+1

printf02:

lda $7000

beq printfE

jsr putc ;在屏幕当前光标处显示一个字符

printf04:

inc printf02+1

bne printf02

inc printf02+2

bne printf02

printfE:

rts

对于步步多媒体学生电脑 putc为:

putc:

tax

lda #DosDisplayChar

jmp DosIOEntry

相关文档
最新文档