📄 dmar.asm
字号:
;*************************************
;* Source Code
;* "DMA Write"
;* 采用DMA方式读软盘数据到主存
;* DMAC: 0号8237A
;* FDC: uPD765
;*************************************
;8237的模式字:
;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(?) ;磁盘缓冲区
EMES DB 'ERROR!$'
OLDPARAS DW 0 ;保存系统软盘参数入口地址
OLDPARAO DW 0
OLDINTS DW 0 ;保存系统软盘中断处理程序入口
OLDINTO DW 0
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,46H ;46H为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,066H
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 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
PUSH CX
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
OUT 04H,AL
MOV AL,AH
OUT 04H,AL
MOV AL,CH
AND AL,0FH
OUT 81H,AL
MOV AH,DH
SUB AL,AL
SHR AX,1
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
OUT 05,AL
MOV AL,AH
OUT 05,AL
STI
POP CX
POP AX
ADD AX,CX
MOV AL,2
OUT 0AH,AL
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
SHWORD 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
SHOW 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 + -