--- /dev/null
+;-----------------------------------------------------------\r
+;\r
+; MXBB.ASM - Bit block transfer\r
+; Copyright (c) 1993,1994 by Alessandro Scotti\r
+;\r
+;-----------------------------------------------------------\r
+WARN PRO\r
+NOWARN RES\r
+INCLUDE MODEX.DEF\r
+\r
+PUBLIC mxBitBlt\r
+\r
+MX_TEXT SEGMENT USE16 PARA PUBLIC 'CODE'\r
+ ASSUME cs:MX_TEXT, ds:NOTHING, es:NOTHING\r
+\r
+EXTRN subHorizontalLineInfo : NEAR\r
+\r
+EXTRN mx_VideoSegment : WORD\r
+EXTRN mx_BytesPerLine : WORD\r
+\r
+;-----------------------------------------------------------\r
+;\r
+; Moves a block of video memory.\r
+;\r
+; Input:\r
+; SX, SY = source coordinates\r
+; Width = source width\r
+; Height = source height\r
+; DX, DY = destination coordinates\r
+; Output:\r
+; none\r
+;\r
+; Note: overlapping regions are not allowed.\r
+;\r
+mxBitBlt PROC FAR\r
+ ARG DestY:WORD, \\r
+ DestX:WORD, \\r
+ Height:WORD, \\r
+ Width:WORD, \\r
+ SY:WORD, \\r
+ SX:WORD = ARG_SIZE\r
+ LOCAL PlaneWidth:WORD:4, \\r
+ SourceOffset:WORD, \\r
+ DestOffset:WORD, \\r
+ Count:BYTE, \\r
+ ReadPlane:BYTE, \\r
+ WritePlane:BYTE, \\r
+ LeftMask:BYTE, \\r
+ RightMask:BYTE = AUTO_SIZE\r
+ .enter AUTO_SIZE\r
+ .push ds, si, es, di\r
+\r
+; Exit now if null width\r
+ cmp [Width], 0\r
+ je @@Exit\r
+\r
+; Calls the proper procedure to handle transfer\r
+ mov ax, [SX]\r
+ and al, 03h ; AL = source plane\r
+ mov dx, [DestX]\r
+ and dl, 03h ; DL = destination plane\r
+ mov bx, OFFSET subPlaneBlt\r
+ cmp al, dl ; Same source and destination plane?\r
+ jne @@BitBlt ; No, use slow procedure\r
+ mov bx, OFFSET subMoveBlt\r
+@@BitBlt:\r
+ call bx\r
+\r
+@@Exit:\r
+ xor ax, ax\r
+ .pop ds, si, es, di\r
+ .leave ARG_SIZE\r
+\r
+;-----------------------------------------------------------\r
+; Uses write mode 1 for maximum speed. Only works if source\r
+; and destination are plane-aligned.\r
+;\r
+subMoveBlt PROC NEAR\r
+; Get horizontal line info and address of destination\r
+ mov bx, [DestX]\r
+ mov ax, [DestY]\r
+ mov cx, [Width]\r
+ call subHorizontalLineInfo\r
+ mov [LeftMask], al\r
+ mov [RightMask], ah\r
+ mov [Width], cx\r
+\r
+; Setup segments\r
+ mov ax, [mx_VideoSegment]\r
+ mov ds, ax\r
+ mov es, ax\r
+\r
+; Get address of source pixel\r
+ mov ax, [SY]\r
+ mul [mx_BytesPerLine]\r
+ mov si, [SX]\r
+ .shr si, 2\r
+ add si, ax\r
+\r
+; Set write mode 1\r
+ mov dx, GDC\r
+ mov ax, 4105h\r
+ out dx, ax\r
+ cld\r
+\r
+; Move left block\r
+@@L0:\r
+ mov ah, [LeftMask]\r
+ or ah, ah\r
+ jz @@C0\r
+ mov dx, TS\r
+ mov al, 02h\r
+ out dx, ax ; Set write plane mask\r
+ mov ax, [mx_BytesPerLine]\r
+ dec ax\r
+ mov cx, [Height]\r
+ .push si, di\r
+@@L1:\r
+ movsb\r
+ add si, ax\r
+ add di, ax\r
+ dec cx\r
+ jnz @@L1\r
+ .pop si, di\r
+ inc si\r
+ inc di\r
+\r
+; Move center block\r
+@@C0:\r
+ mov bx, [Width]\r
+ test bx, bx\r
+ jz @@R0\r
+ mov dx, TS\r
+ mov ax, 0F02h\r
+ out dx, ax ; Enable all planes\r
+ mov ax, [mx_BytesPerLine]\r
+ sub ax, bx\r
+ mov dx, [Height]\r
+ .push si, di\r
+@@C1:\r
+ mov cx, bx ; CX = image width\r
+ rep movsb ; Cannot use "movsw" here!\r
+ add si, ax ; Next scan line\r
+ add di, ax ; Next scan line\r
+ dec dx ; All lines processed?\r
+ jnz @@C1 ; No, continue\r
+ .pop si, di\r
+ add si, bx\r
+ add di, bx\r
+\r
+; Move right block\r
+@@R0:\r
+ mov ah, [RightMask]\r
+ or ah, ah\r
+ jz @@Done\r
+ mov dx, TS\r
+ mov al, 02h\r
+ out dx, ax ; Set write plane mask\r
+ mov ax, [mx_BytesPerLine]\r
+ dec ax\r
+ mov cx, [Height]\r
+@@R1:\r
+ movsb\r
+ add si, ax\r
+ add di, ax\r
+ dec cx\r
+ jnz @@R1\r
+\r
+@@Done:\r
+ mov dx, GDC\r
+ mov ax, 4005h\r
+ out dx, ax ; Restore write mode 0\r
+\r
+@@Exit:\r
+ ret\r
+subMoveBlt ENDP\r
+\r
+;-----------------------------------------------------------\r
+; Moves one plane at a time.\r
+;\r
+subPlaneBlt PROC NEAR\r
+; Compute extra bytes and width count for each plane\r
+ mov cx, [Width]\r
+ mov bx, cx\r
+ shr bx, 1\r
+ shr bx, 1 ; Width for each plane\r
+ and cl, 03h\r
+ mov al, 00001000b\r
+ shr al, cl\r
+ mov si, 3 SHL 1\r
+@@PatchLoop:\r
+ mov PlaneWidth[si], bx\r
+ shr al, 1\r
+ adc bx, 0\r
+ dec si\r
+ dec si\r
+ jge @@PatchLoop\r
+\r
+; Get pixel addresses\r
+ mov ax, [mx_VideoSegment]\r
+ mov ds, ax\r
+ mov es, ax\r
+ mov ax, [SY]\r
+ mul [mx_BytesPerLine]\r
+ mov si, [SX]\r
+ shr si, 1\r
+ shr si, 1\r
+ add si, ax ; DS:SI points to source\r
+ mov [SourceOffset], si\r
+ mov ax, [DestY]\r
+ mul [mx_BytesPerLine]\r
+ mov di, [DestX]\r
+ shr di, 1\r
+ shr di, 1\r
+ add di, ax ; ES:DI points to destination\r
+ mov [DestOffset], di\r
+\r
+; Adjust plane for output to VGA registers\r
+ mov ax, [SX]\r
+ and al, 03h\r
+ mov [ReadPlane], al\r
+ mov cx, [DestX]\r
+ and cl, 03h\r
+ mov al, 00010001b\r
+ shl al, cl\r
+ mov [WritePlane], al\r
+\r
+; Ready to move now\r
+ cld\r
+ mov [Count], 4 ; Four planes\r
+ lea bx, PlaneWidth ; SS:[BX] = width in bytes for plane\r
+@@PlaneLoop:\r
+ cmp WORD PTR ss:[bx], 0\r
+ je @@Done\r
+ mov ah, [WritePlane]\r
+ and ah, 0Fh\r
+ mov al, 02h\r
+ mov dx, TS\r
+ out dx, ax ; Select write plane\r
+ mov ah, [ReadPlane]\r
+ mov al, 04h\r
+ mov dx, GDC\r
+ out dx, ax ; Select read plane\r
+ mov dx, [Height]\r
+ mov ax, [mx_BytesPerLine]\r
+ sub ax, ss:[bx] ; AX = extra bytes per line\r
+@@Loop:\r
+ mov cx, ss:[bx]\r
+ shr cx, 1\r
+ rep movsw\r
+ rcl cx, 1\r
+ rep movsb\r
+ add si, ax\r
+ add di, ax\r
+ dec dx\r
+ jnz @@Loop ; Repeat for all lines\r
+ inc bx\r
+ inc bx ; Select width for next plane\r
+ inc [ReadPlane]\r
+ and [ReadPlane], 03h ; Should be faster on 386 using\r
+ jnz @@ReadPlaneOk ; BTR and ADC...\r
+ inc [SourceOffset]\r
+@@ReadPlaneOk:\r
+ rol [WritePlane], 1\r
+ adc [DestOffset], 0\r
+ mov si, [SourceOffset]\r
+ mov di, [DestOffset]\r
+ dec [Count]\r
+ jnz @@PlaneLoop ; Repeat for all planes\r
+\r
+@@Done:\r
+ ret\r
+subPlaneBlt ENDP\r
+\r
+mxBitBlt ENDP\r
+\r
+MX_TEXT ENDS\r
+END\r