📄 dmaw.asm
字号:
;*************************************
;* Source Code
;* "DMA Read"
;* 采用DMA方式读主存数据到软盘
;* DMAC: 0号8237A
;* FDC: uPD765
;*************************************
;8237的模式字:55
;46H: 单一方式,地址加1,非自动预置,DMA写主存,通道2
;4aH: 单一方式,地址加1,非自动预置,DMA读主存,通道2
;=====================================================
DMA EQU 0
;=====================================================
DISP_CH MACRO CHAR
PUSH BX
MOV AL,CHAR ;字符
MOV AH,0EH ;显示字符
MOV BL,0 ;背景色
INT 10H
POP BX
ENDM
;=====================================================
SSTACK SEGMENT PARA STACK 'STACK'
DB 100 DUP(?)
SSTACK ENDS
;=====================================================
S0040 SEGMENT AT 40H ;以下11字节为软盘数据区
ORG 3EH
DISKDATA LABEL BYTE
SSS DB ? ;询道状态
MS DB ? ;马达状态
MC DB ? ;马达计数
DSS DB ? ;软区状态
NS DB 7 DUP(?) ;nec状态
S0040 ENDS
;=====================================================
DDATA SEGMENT
DPARA LABEL BYTE ;软盘参数表,系统BIOS中使用的参数值
DB 11011111B
DB 00000010B
DB 25H
DB 02H
DB 3FH
DB 1BH
DB 0FFH
DB 054H
DB 0F6H
DB 0FH
DB 08H
BUF DB 512 DUP(72) ;磁盘缓冲区
OLDPARAS DW 0 ;保存系统软盘参数入口地址
OLDPARAO DW 0
OLDINTS DW 0 ;保存系统软盘中断处理程序入口
OLDINTO DW 0
EMES DB 'ERROR!$'
DDATA ENDS
;=====================================================
CODE SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CODE,ES:DDATA,DS:S0040,SS:SSTACK
START PROC FAR
MOV AX,DDATA
MOV DS,AX
CLI ;关中断
XOR AX,AX ;设置中断向量
MOV ES,AX
MOV DI,38H ;4*0EH,0EH号中断为软盘中断
MOV AX,ES:[DI]
MOV OLDINTO,AX
MOV AX,OFFSET DISKINT
CLD
STOSW
MOV AX,ES:[DI]
MOV OLDINTS,AX
MOV AX,SEG DISKINT
STOSW
MOV DI,78H ;4*1EH,1EH为软盘参数块
MOV AX,ES:[DI]
MOV OLDPARAO,AX
MOV AX,OFFSET DPARA
STOSW
MOV AX,ES:[DI]
MOV OLDPARAS,AX
MOV AX,SEG DPARA
STOSW
MOV AX,S0040
MOV DS,AX
MOV AX,DDATA ;ES指向系统数据区
MOV ES,AX
MOV SI,OFFSET DPARA ;SI指向软盘参数区入口
AND SSS,07FH ;清中断标志
STI
MOV DH,1 ;设置DMA参数
MOV BX,OFFSET BUF
MOV AX,SEG BUF
MOV ES,AX
MOV AL,4aH ;4aH为8237的模式字
CALL DMA_SETUP
JNC ST1
MOV DSS,09H
MOV AX,09H ;返回DOS系统
CALL SHWORD
MOV AX,4C00H
INT 21H
ST1: MOV AX,DDATA
MOV ES,AX
CLI
MOV MC,0FFH ;马达延长计数值设置为最大
TEST MS,01H ;驱动器1马达是否已经转动
JNZ ST2 ;已转动转J14
AND MS,0F0H ;以下为启动处理
OR MS,01H
MOV AL,00011100B ;选择驱动器1,开马达,允许中断,FDC
MOV DX,3F2H
OUT DX,AL ;送数字输出寄存器
MOV SSS,0
MOV DSS,0
ST2: STI ;开中断,完成询道操作
TEST SSS,01H ;检查1号驱动器是否需要归零道
JNZ ST3
ST21: MOV AH,07H ;执行归零操作
CALL NEC_OUTPUT
MOV BX,11H
JC ST22
MOV AH,0H
CALL NEC_OUTPUT
MOV BX,12H
JC ST21
mov cx,0F10h
st211: CALL CHK_STAT
mov bx,13h
JNC ST3
loop st211
ST22: MOV AX,bx
CALL SHWORD
JMP ENDR
ST3: MOV AH,0FH
CALL NEC_OUTPUT
MOV BX,21H
JC ST31
MOV AH,0
CALL NEC_OUTPUT
MOV BX,22H
JC ST31
MOV AH,12
CALL NEC_OUTPUT
MOV BX,23H
MOV CX,0F10H
ST311: CALL CHK_STAT
mov bx,24h
JNC J29
LOOP ST311
ST31: MOV AX,BX
CALL SHWORD
JMP ENDR
J29: MOV AH,ES:[SI+9]
J29A: OR AH,AH
JZ J31
MOV CX,550
J30: LOOP J30
DEC AH
JMP J29A
J31: mov ah,0c5h
CALL NEC_OUTPUT
MOV AH,0
CALL NEC_OUTPUT
MOV AH,12
CALL NEC_OUTPUT
MOV AH,0
CALL NEC_OUTPUT
MOV AH,1
CALL NEC_OUTPUT
MOV AH,ES:[SI+3]
CALL NEC_OUTPUT
MOV AH,ES:[SI+4]
CALL NEC_OUTPUT
MOV AH,ES:[SI+5]
CALL NEC_OUTPUT
MOV AH,ES:[SI+6]
CALL NEC_OUTPUT
MOV CX,0F10H
J311: CALL WAIT_INT
JNC J32
LOOP J311
CALL RESULTS
MOV AX,07H
CALL SHWORD
JMP ENDR
J32: CALL RESULTS
JNC S11
MOV AX,08H
CALL SHWORD
JMP ENDR
S11: call delay
mov ax,ddata
mov es,ax
mov di,offset buf
mov cx,20h
s111: mov ax,es:[di]
call shword
loop s111
JMP REND
ENDR: MOV AH,ES:[SI+2]
MOV MC,AH
MOV AX,OFFSET DDATA
MOV DS,AX
MOV DX,OFFSET EMES
MOV AH,09H
INT 21H
REND: CLI ;关中断
MOV AX,DDATA
MOV DS,AX
XOR AX,AX ;设置中断向量
MOV ES,AX
MOV DI,38H ;4*0EH,0EH号中断为软盘中断
MOV AX,ES:[DI]
MOV AX,OLDINTO
CLD
STOSW
MOV AX,ES:[DI]
MOV AX,OLDINTS
STOSW
MOV DI,78H ;4*1EH,1EH为软盘参数块
MOV AX,ES:[DI]
MOV AX,OLDPARAO
STOSW
MOV AX,ES:[DI]
MOV AX,OLDPARAS
STOSW
STI
wait_press_key:
mov ah, 0bh ;检测是否有键按下?检查键盘状态,al=00则无输入
int 21h
cmp al, 0h
je wait_press_key ;若无键按下,则程序往下执行
MOV AX,4C00H
INT 21H
START ENDP
NEC_OUTPUT PROC NEAR ;AH为参数
PUSH DS
PUSH DX
PUSH CX
MOV DX,S0040
MOV DS,DX
MOV DX,3F4H ;将软盘FDC的主状态寄存器地址送DX
XOR CX,CX ;置循环等待时间,清标志
N1: IN AL,DX ;读主状态寄存器,判是否可以写数据寄存器
MOV BL,AL
AND AL,0C0H
CMP AL,80H
JZ N3
LOOP N1
N2: OR DSS,80H ;置超时错误码
POP CX
POP DX
POP DS
STC
RET
N3: MOV AL,AH ;输出命令
MOV DX,3F5H
OUT DX,AL
POP CX
POP DX
POP DS
RET
NEC_OUTPUT ENDP
DISKINT PROC FAR
STI
PUSH DS
PUSH AX
MOV AX,S0040
MOV DS,AX
OR SSS,80H
MOV AL,20H
OUT 20H,AL
POP AX
POP DS
IRET
DISKINT ENDP
WAIT_INT PROC NEAR
STI
PUSH DS
PUSH BX
PUSH CX
MOV BX,S0040
MOV DS,BX
XOR CX,CX
MOV CX,0FFFFH
W1: TEST SSS,80H
JNZ W2
LOOP W1
OR DSS,80H
STC
W2: PUSHF
AND SSS,07FH
POPF
POP CX
POP BX
POP DS
RET
ENDP
DMA_SETUP PROC NEAR ;DMA初始化程序,AH为参数,决定DMA的方式字
PUSH CX ;ES指向缓冲区所在段
CLI
OUT 0CH,AL ;清除字节指针触发器
OUT 0BH,AL ;写模式寄存器
MOV AX,ES ;缓冲区段地址
MOV CL,4
ROL AX,CL
MOV CH,AL ;取得页面地址
AND AL,0F0H
ADD AX,BX ;计算页内偏移
JNC D1 ;没有跨页
INC CH ;保存页内偏移
D1: PUSH AX ;设置通道2内存地址初值
OUT 04H,AL ;写低字节
MOV AL,AH
OUT 04H,AL ;写高字节
MOV AL,CH
AND AL,0FH
OUT 81H,AL ;写通道2的页面地址寄存器
MOV AH,DH ;送扇区数到AH中
SUB AL,AL
SHR AX,1 ;<=> 扇区数*128
PUSH AX
PUSH DS
MOV AX,DDATA
MOV DS,AX
MOV AX,OFFSET DPARA
MOV SI,AX
MOV BX,3
MOV AH,[BX+SI] ;取每扇区的字节数
POP DS
JNC D2
CALL NEC_OUTPUT
D2: MOV CL,AH ;写传送字节数
POP AX
SHL AX,CL
DEC AX
PUSH AX ;送通道2字节计数值
OUT 05,AL ;写低字节
MOV AL,AH
OUT 05,AL ;写高字节
STI ;开中断
POP CX
POP AX
ADD AX,CX
MOV AL,2
OUT 0AH,AL ;清通道2 的屏蔽字
POP CX
RET
DMA_SETUP ENDP
RESULTS PROC NEAR
CLD
PUSH DS
PUSH CX
PUSH DX
PUSH BX
MOV BX,S0040
MOV DS,BX
MOV DI,OFFSET NS
MOV BL,7
R1: XOR CX,CX
MOV DX,3F4H
R2: IN AL,DX
TEST AL,80H
JNZ R4
LOOP R2
OR DSS,80H
R3: STC
POP BX
POP DX
POP CX
POP DS
RET
R4: IN AL,DX
TEST AL,40H
JNZ R6
R5: OR DSS,20H
JMP R3
R6: MOV DX,3F5H
IN AL,DX
MOV [DI],AL
INC DI
XOR CX,CX
R7: LOOP R7
MOV DX,3F4H
IN AL,DX
TEST AL,10H
JZ R8
DEC BL
JNZ R1
JMP R5
R8: POP BX
POP DX
POP CX
POP DS
RET
RESULTS ENDP
CHK_STAT PROC NEAR
PUSH CX
CALL WAIT_INT
mov bx,55H
JC C1
MOV AH,08H
CALL NEC_OUTPUT
CALL RESULTS
mov bx,66H
JC C1
MOV AL,NS
AND AL,60H
CMP AL,60H
mov bx,77H
JZ C2
CLC
mov bx,88H
C1: POP CX
RET
C2: OR DSS,40H
STC
POP CX
RET
CHK_STAT ENDP
SHWORD PROC NEAR
PUSH BX
MOV BL,AH
CALL SHOW
MOV BL,AL
CALL SHOW
POP BX
RET
ENDP
SHOW PROC NEAR
PUSH AX
PUSH DX
MOV AL,BL
AND AL,0F0H ;取高4位
SHR AL,4
CMP AL,0AH ;是否是A以上的数
JB SC2
ADD AL,07H
SC2: ADD AL,30H
MOV DL,AL ;显示字符
MOV AH,02H
INT 21H
MOV AL,BL
AND AL,0FH ;取低4位
CMP AL,0AH
JB SC3
ADD AL,07H
SC3: ADD AL,30H
MOV DL,AL ;显示字符
MOV AH,02H
INT 21H
POP DX
POP AX
RET
ENDP
DELAY PROC NEAR
PUSH BX
PUSH CX
MOV CX,0FFFFH
DD2: PUSH CX
MOV CX,0FFFH
DD1: LOOP DD1
POP CX
LOOP DD2
POP CX
POP BX
RET
DELAY ENDP
CODE ENDS
END START
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -