//非内核区闪存的修改
闪存的修改也包括内核区闪存的修改和非内核区闪存的修改,这里讨论内核区闪存的修改.
要修改闪存区域的某个地址或某段地址的内容,首先必须保证该个地址或该段地址的内容为 FF
如果不是,那么必须擦除该个地址或该段地址所在的闪存块.
如图1:
这里由于地址4010-4017内容是 FF,所以这里我们就修改0E页码地址4010 -地址 4017的内容为 00 01 02 03 04 05 06 07
但是大家要注意的是,我这里的0E页码是没有被系统占用的,大家实验的时候,先找块没有被系统用的页码,然后才可以实验
程序如下:
A 2000
2000:SEI //设置中断标志
2001:LDA $00 //保护地址00 0A 0D 的内容,方法是先压入堆栈
2003:PHA
2004:LDA $0A
2006:PHA
2007:LDA $0D
2009:PHA
200A:LDA $0A //地址0A的最高位置 0
200C:AND #$7F
200E:STA $0A
2010:LDA #$10 //这里把目标地址的高8位送地址 41, 低8位送地址 40
2012:STA $40
2014:LDA #$40
2016:STA $41
2018:LDA #$0E //把页码数送寄存器A
201A:STA $00 //切换到了 09 页码了
201C:LDY #$00 //X,Y寄存器初始化均为 00
201E:LDX #$00
2020:TXA //寄存器 X的内容送 A
2021:PHA //A 的内容送堆栈
2022:LDA #$AA //这里就是 修改闪存的 代码了,大家不能改,照着抄
2024:STA $5555
2027:LDA #$55
2029:STA $AAAA
202C:LDA #$A0
202E:STA $5555
2031:PLA //把原来压入堆栈 的 X 的内容弹出堆栈,并送寄存器A
2032:STA ($40),Y //寄存器 A 的内容送以 地址 40的内容为低8位,41的内容为高8位的16地址,实现修改闪存
2034:LDA $8000 //这段代码是检测是否修改成功,大家不要变
2037:AND #$88
2039:CMP #$88
203B:BNE $2034 //这里是可能要变的,反正是跳转到 LDA $8000那里的地址
203D:LDA #$F0
203F:STA $8000
2042:CPX #$07 //寄存器X的内容为07 吗,如果是,那就说明全部修改完了,转结束
2044:BCS $2050
2046:INX //没有,那么,寄存器X的内容加1
2047:INC $40 //地址40的内容加1,为写入下一个地址做准备
2049:BNE $204D
204B:INC $41
204D:JMP $2020 //继续开始修改闪存
2050:CLI //程序结束
2051:PLA
2052:STA $0D
2054:PLA
2055:STA $0A
2057:PLA
2058:STA $00
205A:RTS
然后我们 G 2000
再 D 4000 0E,发现已经修改成功,如图2:
这里要提醒大家的是,在运行 修改闪存代码前,请将要修改的数据压入堆栈,然后运行完 修改闪存代码后
把压入堆栈的数据弹出,而且必须采用 后变址Y间接寻址方式,将数据写入 闪存地址,这里不支持 直接X变址 和 直接Y变址
但还支持 直接寻址,不过我们一般就是用 后变址Y间接寻址 方式
前面的程序比较的简单,因为闪存地址的内容已经是 FF,所以我们不需要擦除闪存,不过下面我们要修改一段内容不为 FF 的闪存地址的
内容为 00 01 02 03 04 05 06 07,那么我们应该怎么做,请看我们分析:
假如我们要修改 图 2 的地址4018-401F 的内容为 00 01 02 03 04 05 06 07
由于地址 4018-401F 的内容不为 FF,所以我们要先擦除 该段地址所处的闪存块,很明显,处与 01 闪存块,那么我们就需要先擦除
地址 4000-47FF 的内容全部为 FF,那么就出现一个问题,我们这样做,势必会破坏其他地址的内容啊?
所以我们需要先保护地址4000-47FF的内容,在 NC1020中,我们可以这样做:
1.先把 地址 4000-47FF的内容 发送到 地址 3000-37FF
2.把 00 01 02 03 04 05 06 07 发送到地址 3018-301F,注意,这里是3018-301F
3.擦除 地址 4000-47FF
4.把地址 3000-37FF 的内容 送地址 4000-47FF
5.修改完毕,OK!
由于上面有大量的数据传送程序,我们先来编写一个数据传输的子程序,可以实现任意地址数据之间的传输,这个子程序也被广泛
用于我的 XASM,NCTOOLS等DEBUG工具中.
我这里是这样规定的:
地址 40 41 源开始的地址
地址 42 43 源结束地址
地址 44 45 目标开始地址
地址 46 源页码,若是 RAM,页码为 FF
地址 47 目标页码,若是 RAM,页码为 FF
A 2000
2000:SEI //这里设置中断标志,保护地址 0D 0A 00的内容
2001:LDA $00
2003:PHA
2004:LDA $0A
2006:PHA
2007:LDA $0D
2009:PHA
200A:LDA $0A //保证地址OA 最高位为 0
200C:AND #$7F
200E:STA $0A
2010:LDY #$00 //寄存器 Y的内容为00,因为后面要用到的 后变址Y间接寻址 要求 (Y)=00
2012:LDA $46 //这里 切换到 源页码
2014:STA $00
2016:LDA ($40),Y //读取源页码的相应地址数据到 寄存器 A
2018:PHA //寄存器A的内容压入堆栈,准备写入 目标页码的闪存
2019:LDA $47 //目标页码 数是放在地址47,这里如果地址47的内容 大于 10,那说明目标地址所在区域为 RAM
201B:CMP #$10 那么就不需要运行 修改闪存 的代码
201D:BCS $2048 //若页码数 >10,那么转地址 2048,可以直接把数据写入目标地址
201F:STA $00 //那么说明目标地址处于闪存 或者 00页码
2021:CMP #$00 //如果是 00 页码,由于地址 4000-7FFF也是 RAM,所以也可以直接写入
2023:BEQ $2048
2025:LDA #$AA //这里就是 写闪存的 代码,不能变
2027:STA $5555
202A:LDA #$55
202C:STA $AAAA
202F:LDA #$A0
2031:STA $5555
2034:PLA //把压入堆栈的数据出栈,写入 目标闪存
2035:STA ($44),Y
2037:LDA $8000 //检测 是否已经 修改 完毕,和前面的一样
203A:AND #$88
203C:CMP #$88
203E:BNE $2037
2040:LDA #$F0
2042:STA $8000
2045:JMP $204B //跳过下面的两行代码
2048:PLA //这里当目标地址 是RAM,直接把数据写入
2049:STA ($44),Y
204B:LDA $40 //把地址40 41的内容和地址 42 43的数据比较,如果相同,说明数据全部发送完毕
204D:CMP $42
204F:BNE $2062
2051:LDA $41
2053:CMP $43
2055:BNE $2062
2057:CLI //如果地址 40 41的内容和地址 42 43的内容相同,程序结束
2058:PLA
2059:STA $0D
205B:PLA
205C:STA $0A
205E:PLA
205F:STA $00
2061:RTS
2062:INC $40 //地址40, 44的内容加1,为读取和写入 下一字节做 准备
2064:BNE $2069
2066:INC $41
2068:INC $44
206A:BNE $206F
206C:INC $45
206E:JMP $2012 //继续转地址2012
有了前面的基础,我想上面的程序大家应该可以看懂吧!
在前面的擦除闪存 教程中,已经介绍了擦除任意连续闪存块的子程序,现在我们派上用场了,程序如下:
2100:SEI
2101:LDA $00
2103:PHA
2104:LDA $0A
2106:PHA
2107:LDA $0D
2109:PHA
210A:LDA $0A
210C:AND #$7F
210E:STA $0A
2110:LDA $F4 //这里读取地址F4的内容作为页码,在调用这个子程序前,要先把页码送地址F4
2112:STA $00
2114:LDA #$F0 //下面的代码就是擦除闪存的代码,是不能变的,大家也别问为什么是这样的代码,照抄就是!!!
2116:STA $8000
2119:LDA #$AA
211B:STA $5555
211E:LDA #$55
2120:STA $AAAA
2123:LDA #$80
2125:STA $5555
2128:LDA #$AA
212A:STA $5555
212D:LDA #$55
212F:STA $AAAA
2132:LDY #$00 //寄存器Y的内容 = 0
2134:LDA #$30 //地址 F0为块头地址低8位, F1为块头地址高8位,然后把立即数30送块头地址
2136:STA ($F0),Y
2138:LDA $8000 //这段代码是固定的,大家照抄!!
213B:AND #$88
213D:CMP #$88
213F:BNE $2138 //注意,这里是变化的,因为代码开始执行地址是不同的,不要这个也照抄,那就完了!!反正是跳转到 LDA $8000 那个地址
2141:LDA #$F0
2143:STA $8000
2146:LDA $F1 //由于是擦除连续的闪存块,所以这里要检查是不是已经全部擦除完毕,方法是把地址F1的内容和地址F3比较
2148:CMP $F3 如果相同,则说明已经擦除完,转地址2152,准备结束程序
214A:BEQ $2154
214C:CLC //如不同, 地址 F1的内容加 8,请想想为什么是加 8
214D:ADC #$08
214F:STA $F1
2151:JMP $2114 //继续擦除下一闪存块
2154:CLI //清除中断标志,恢复被保护的地址内容,程序结束
2155:PLA
2156:STA $0D
2158:PLA
2159:STA $0A
215B:PLA
215C:STA $00
215E:RTS
现在我们可以很容易的实现修改闪存了,下面我们就实现 修改 0E 页码 的4018-401F 的内容为 00 01 02 03 04 05 06 07
A 220B
220B:LDA #$00
220D:STA $40
220F:LDA #$40
2211:STA $41
2213:LDA #$FF
2215:STA $42
2217:LDA #$47
2219:STA $43
221B:LDA #$00
221D:STA $44
221F:LDA #$30
2221:STA $45
2223:LDA #$0E
2225:STA $46
2227:LDA #$FF
2229:STA $47
222B:JSR $2000 //实现了将0E页码地址4000-47FF 送地址3000-37FF
222E:LDA #$00
2230:STA $F0
2232:LDA #$40
2234:STA $F1
2236:LDA #$00
2238:STA $F2
223A:LDA #$40
223C:STA $F3
223E:LDA #$0E
2240:STA $F4
2242:JSR $2100 //实现 擦除 0E 页码 4000-47FF
2245:LDX #$00 //实现将 0 1 2 3 4 5 6 7 写入地址 3018-301F
2247:TXA
2248:STA $3018,X
224B:INX
224D:CPX #$08
224F:BNE $2247
2251:LDA #$00
2252:STA $40
2254:LDA #$30
2256:STA $41
2258:LDA #$FF
225A:STA $42
225C:LDA #$37
225E:STA $43
2260:LDA #$00
2262:STA $44
2264:LDA #$40
2266:STA $45
2268:LDA #$FF
226A:STA $46
226C:LDA #$0E
226E:STA $47
2270:JSR $2000 //实现将地址 3000-37FF 送0E 页码 4000-47FF
2273:RTS //结束