📄 llegasup.asm
字号:
xchg ah,al
ror ax,cl ;align to video
sub bp,8 ;8 bits done
ja NWrLoop ;go if bit count not exhausted
add bp,8 ;restore BP to #bits in last byte
cmp cx,bp ;did we use any of the second byte?
jb NWrLast ;go if so
or si,si ;at start of segment?
jnz NWrUnfl ;go if not
call B$DecDS ;backup to previous segment
NWrUnfl:
dec si ;move ptr back
NWrLast:
push ax
and dh,dl ;combine first|middle mask with end mask
mov ah,dh ;last byte bit mask
MOV DX,GRPADD ;address graphics controller
mov al,BMKREG ; bit mask register
EGAINT10CLI ;disable ints for direct EGA manipulation
OUT DX,AL
XCHG AL,AH
INC DX
OUT DX,AL ;output bit mask
DEC DX
pop ax
.erre ID_SSEQDS ;assumes ss = ds
call bx ;put the last byte
EGAINT10STI ;reenable ints if using EGAINT10
cEnd
NWrOvfl3:
call B$BumpDS ;move array pointer over segment boundary
jmp short NWrOvfl2 ;back to loop
ASSUME DS:DGROUP
;***
; B$EgaNSetC
;
;Purpose:
; Set a horizontal line of pixels to the current attribute for EGA
; modes. The line starts at the current cursor position and moves right.
;
; This becomes a bit of a mess with EGAINT10 and QCG support. Here's
; the current approach:
; No EGAINT10 (QCG or not, doesn't matter) --
; No problem, just execute straight code, modifying the EGA
; hardware directly where needed.
; EGAINT10 and no QCG --
; Disable ints at the beginning and reenable them at the end.
; This will work because in the worst case the entire routine
; takes approx. 1500 clock cycles, and we are using a ceiling
; of 1800 clock cycles between CLI/STI.
; EGAINT10 and QCG --
; Now things get ugly. We can't just disable ints over the
; whole routine because it would exceed the 1800 clock max.
; Instead, we use a combination of writing regs through the
; EGAINT10 interface (like setting RWMReg, because it's needed
; for the entire routine), and modifying regs directly within
; small CLI/STI brackets (like setting BMKReg for a byte and
; then restoring it before reenabling ints).
;Entry:
; b$AddrC specifies start pixel
; b$PenC = cursor mask and attribute
; BX = number of pixels to set
;Exit:
; None
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
cProc B$EgaNSetC,<PUBLIC,NEAR>,<ES,DI>
cBegin
EGAINT10CLI ;disable ints for entire routine if EGAINT10
MOV DX,GRPADD ;address of graphics index register
MOV AL,RWMREG ;r/w mode register
OUT DX,AL ;index the mode register
MOV AL,b$EgaWrMd ;write mode 2; odd/even or sequential addr.
INC DX ;to data port
OUT DX,AL
DEC DX ;back to index port
MOV AL,BMKREG
OUT DX,AL ;index the mask register
INC DX ;to data port
les di,b$AddrC ;graphics cursor address
mov cx,b$PenC ;ch = desired attribute
;cl = cursor mask
or cl,cl ;left aligned in byte?
js NSet2a ;go if so, skip single-bit start
NSet1:
xor ah,ah ;zero out new mask accumulator
NSet2:
or ah,cl ;include this pixel in mask
dec bx ;decrement pixel count
jz NSet4 ;treat as last byte if bit count exhausted
ror cl,1 ;move 1 pixel right
jnb NSet2 ;continue if not right-most bit
mov al,ah ;mask to AL for OUT
out dx,al ;set bit mask
mov al,ch ;copy desired attribute
xchg al,es:[di] ;set the byte
inc di ;bump cursor byte pointer
NSet2a:
push cx
mov al,0FFH ;set bit mask for full bytes
out dx,al
mov ax,bx ;remaining bit count
mov cl,b$DivShift ;pixels/byte divisor shift
shr ax,cl ;compute full byte count
jz NSet3 ;go do remaining bits if no full bytes
xchg ax,cx ;byte count to cx
mov al,ah ;attribute byte
rep stosb ;block write full bytes
NSet3:
pop cx
and bx,b$ModMask ;mask in remaining bit count
jnz NSet1 ;go do remaining bits
jmp short NSet5 ;no bits remaining - exit
NSet4: ;update last byte
mov al,ah ;mask to AL for OUT
out dx,al ;set bit mask
xchg ch,es:[di] ;set the byte
NSet5:
EGAINT10STI ;reenable ints if using EGAINT10
CALL B$ResetEGA ;call routine to reset write mode for BIOS
cEnd
;***
; B$EgaPaintBound_11
;
;Purpose:
; Called by PAINT before painting each scan line for
; Screen 11 to facilitate fast viewport edge detection.
; Set VIEW left and right cursor addresses and masks.
;Entry:
; b$OffC = address of current pixel
;Exit:
; B$LEOFST = left edge offset
; B$REOFST = right edge offset
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
cProc B$EgaPaintBound_11,<PUBLIC,NEAR>
cBegin
mov AX,b$OffC ;video offset
MOV CX,80 ;divisor = 80
XOR DX,DX
DIV CX ;quotient in AX = row # (INT(b$OffC/80))
SHL AX,1 ;row * 2
JMP SHORT PntBndCommon ;finish the math and store the results
cEnd <nogen>
;***
; B$EgaPaintBound_D
;
;Purpose:
; Called by PAINT before painting each scan line for
; Screen 7 to facilitate fast viewport edge detection.
; Set VIEW left and right cursor addresses and masks.
;Entry:
; b$OffC = address of current pixel
;Exit:
; B$LEOFST = left edge offset
; B$REOFST = right edge offset
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
cProc B$EgaPaintBound_D,<PUBLIC,NEAR>
cBegin
mov ax,b$OffC ;video offset
MOV CX,40 ;divisor = 40
XOR DX,DX
DIV CX ;quotient in AX = INT(CLOC/40) -- this is row
CALL PntBndCommon ;finish the math and store the results
JMP SHORT SetColorBits ;set up ColorBits array and exit
cEnd <nogen>
;***
; B$EgaPaintBound
;
;Purpose:
; Called by PAINT before painting each scan line for
; EGA modes to facilitate fast viewport edge detection.
; Set VIEW left and right cursor addresses and masks.
;Entry:
; b$OffC = address of current pixel
;Exit:
; B$LEOFST = left edge offset
; B$REOFST = right edge offset
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
cProc B$EgaPaintBound,<PUBLIC,NEAR>
cBegin
mov ax,b$OffC ;video offset
MOV CX,80 ;divisor = 80
XOR DX,DX
DIV CX ;quotient in AX = INT(CLOC/80) -- this is row
SHL AX,1 ;row * 2
CALL PntBndCommon ;finish the math and store the results
; In order for SCANL and SCANR to be able to check whether any tiles
; will actually change, we need bit-specific information about the
; tile pattern for the current byte. This is collected as binary
; representations of the colors of each bit, and stored in the array
; ColorBits.
;
; At this point, the SetTile routine has set up the AttrTile array
; with the tile pattern for this row. Now calculate the ColorBits
; array.
SetColorBits:
PUSH DI
PUSH SI
PUSH BX
MOV SI,7 ;offset to color array
MOV DI,3 ;offset into AttrTile
SHFTBT:
XOR BH,BH ;clear byte for isolating one color
GETCOL:
ROR AttrTile[DI],1 ;plane 3 bit
RCL BH,1 ;rotate carry into color accumulator
DEC DI ;next plane
TEST b$Planes,2 ;if 2-plane graphics --
JZ GETCL1 ;we need to pass up next plane down --
DEC DI ;to find color bit for odd/even mode
ROR AttrTile[DI],1 ;get bit for low plane
RCL BH,1 ;rotate carry
JMP SHORT STTIL3
GETCL1:
ROR AttrTile[DI],1 ;plane 2 bit
RCL BH,1 ;rotate carry
DEC DI ;for 4-plane, repeat down through 0
ROR AttrTile[DI],1 ;plane 1 bit
RCL BH,1
DEC DI
ROR AttrTile[DI],1 ;plane 0 bit
RCL BH,1
STTIL3:
MOV ColorBits[SI],BH ;store color in array element
MOV DI,3 ;go back to plane 3 pattern
DEC SI ;next lower offset in color array
JNS SHFTBT ;and shift out next color
POP BX
POP SI
POP DI
cEnd
cProc PntBndCommon,<NEAR>
cBegin
SHL AX,1 ;row * 2 (or row * 4)
SHL AX,1 ; * 4 (or row * 8)
SHL AX,1 ; * 8 (or row * 16)
MOV DX,AX ;save (row * 8) or (row * 16)
SHL AX,1 ;row * 16 (or row * 32)
SHL AX,1 ;row * 32 (or row * 64)
ADD AX,DX ;(row*32) + (row*8) = row*40 = byte address
;(or (row*64)+(row*16)=row*80 = byte address)
;left margin of screen at this row
MOV DX,AX ;two copies of this value
ADD AX,B$VLOFST ;byte address at (x=0) + offset to viewport
MOV B$LEOFST,AX ;left margin = byte address of left margin
ADD DX,B$VROFST ;byte address at (x=0) + offset to viewport
MOV B$REOFST,DX ;right margin = byte address of right margin
cEnd
;***
; B$EgaSetTile
;
;Purpose:
; This routine stores the internal form of the current tile attribute.
; This routine is called each time a row is to be painted.
;Entry:
; BL = internal form of the tile attribute
; BH = which plane the attribute is for
;Exit:
; AttrTile[plane] = attribute
; b$AttrC = attribute
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
cProc B$EgaSetTile,<PUBLIC,NEAR>,<AX,DI>
cBegin
MOV AL,BH
XOR AH,AH
MOV DI,AX ;DI = 1 based plane number
CMP b$Planes,2 ;2 plane system?
JA FOUR_PLANE
SHL DI,1 ;plane now 2 or 4
DEC DI
MOV AttrTile[DI],BL
FOUR_PLANE:
DEC DI ;0 based
MOV AttrTile[DI],BL
MOV b$AttrC,BL ;set attribute to the tile attribute
cEnd
;***
; B$EgaScanInit
;
;Purpose:
; This routine does some initialization for both ScanL and ScanR
; for EGA modes. Set up EGA Read/Write Mode register for color
; compare read and EGA Color Compare register with b$PaintBorder.
;Entry:
; None
;Exit:
; ES:SI = Video segment address (b$AddrC)
; CH = cursor mask (b$MaskC)
; CL = flag for pixels changed (0)
; BX = count of pixels changed (0)
;Uses:
; per conv.
;Exceptions:
;******************************************************************************
cProc B$EgaScanInit,<PUBLIC,NEAR>,<DX>
cBegin
les si,b$AddrC ;di=cursor offset, es=video seg
mov ch,b$MaskC ;ch=cursor mask
MOV DX,GRPADD ;address of graphics index register
MOV AL,RWMREG
OUT DX,AL ;index the mode register
MOV AL,8H ;set read mode 1 for color compare
INC DX ;to data port
OUT DX,AL
DEC DX ;back to index port
MOV AL,LOW CLCREG
OUT DX,AL ;index the color compare register
MOV AL,b$PaintBorder ;set up color compare with border attribute
INC DX ;to data port
OUT DX,AL
XOR CL,CL ;flag for pixels changed
XOR BX,BX ;count of pixels changed initialized to 0
cEnd
;***
; B$EgaPAINPX
;Purpose:
; Paint first byte (and) last byte (and) whole bytes in between
; Fast write is left to right or v.v. depending on whether SCANR, SCANL.
; Call has reset or set direction flag.
;
; This becomes a bit of a mess with EGAINT10 and QCG support. Here's
; the current approach:
; No EGAINT10 (QCG or not, doesn't matter) --
; No problem, just execute straight code, modifying the EGA
; hardware directly where needed.
; EGAINT10 and no QCG --
; Disable ints at the beginning and reenable them at the end.
; This will work because in the worst case the entire routine
; takes approx. 1500 clock cycles, and we are using a ceiling
; of 1800 clock cycles between CLI/STI. TILING is an exception:
; If tiling is used then the routine takes too long, but there
; is an opportune point in the middle to reenable ints and then
; disable them again without too much of a speed hit.
; EGAINT10 and QCG --
; Now things get ugly. We can't just disable ints over the
; whole routine because it would exceed the 1800 clock max.
; Instead, we use a combination of writing regs through the
; EGAINT10 interface (like setting RWMReg, because it's needed
; for the entire routine), and modifying regs directly within
; small CLI/STI brackets (like setting BMKReg for a byte and
; then restoring it before reenabling ints).
;Entry:
; DI = first byte
; SI = last byte,
; BL = bit mask for first byte
; BH = bit mask for last byte
; BP = count of whole bytes to paint in between first and last
; CH = 00 if SCANR (for INC DI before REP) or
; = FF if SCANL (for DEC DI before REP)
;Exit:
; CL = non-zero to flag pixels changed
;Uses:
;Exceptions:
;******************************************************************************
; Now to write the whole line from [DI], first pixel, to [SI],
; final pixel first set up for write mode 2, if solid color PAINT,
; or 0, if tile PAINT.
cProc B$EgaPAINPX,<PUBLIC,NEAR>,<DX>
cBegin
MOV DX,GRPADD
MOV AH,b$EgaWrMd
CMP b$Tiling,0
JZ PAINT1
AND AH,10H ;if TILE write, use write mode 0
PAINT1:
MOV AL,LOW RWMREG
EGAINT10CLI ;disable interrupts if using EGAINT10
OUT DX,AL ;index the mode register
XCHG AL,AH ;set write mode
INC DX ;to data port
OUT DX,AL
DEC DX ;back to index port
; Set up bit mask.
MOV AL,LOW BMKREG
OUT DX,AL ;index the bit mask register
MOV AL,BL
INC DX ;to data port
OUT DX,AL
DEC DX ;back to index port
; Latch
MOV AL,ES:[DI]
CMP b$Tiling,0
JZ NOTIL1 ;tiling not on, write solid color b$AttrC
CALL WRTTIL ;else call routine for writing partial tile
JMP SHORT CHKLST ;proceed to check for a last byte
NOTIL1:
; Write first byte.
MOV BL,b$AttrC
MOV ES:[DI],BL
CHKLST:
OR BH,BH ;see if a last byte to write
JNZ MORWRT
CALL CLRMSK ;all done -- clear bit mask
JMP SHORT WHLBYT
MORWRT:
; Set up bit mask for last byte.
MOV AL,LOW BMKREG
OUT DX,AL ;index the bit mask register
MOV AL,BH ;set mask
INC DX ;to data port
OUT DX,AL
DEC DX ;back to index port
; Latch
MOV AL,ES:[SI]
CMP b$Tiling,0
JZ NOTIL2
XCHG DI,SI ;WRTTIL addresses screen with DI
CALL WRTTIL ;if tiling is on, set [partial] last byte
XCHG DI,SI ;restore DI for whole-byte write
JMP SHORT CLRBT1
NOTIL2:
MOV ES:[SI],BL ;write last byte
CLRBT1:
CALL CLRMSK
WHLBYT:
OR BP,BP ;check if intermediate whole bytes
JZ CLRBT2
; Set up to write all whole bytes.
INC DI ;if SCANR, go right
OR CH,CH
JZ BYTE2
DEC DI
DEC DI ;else start to left of first byte
BYTE2:
MOV BH,CH ;may need INC/DEC flag for 2-plane write
MOV CX,BP ;whole-byte counter in CX
MOV AL,BL ;attribute in AL for no-tile speed routine
CMP b$Tiling,0 ;see whether tiling is on
JZ WRITE4
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -