Metropoli BBS
VIEWER: amst1512.asm MODE: TEXT (ASCII)
                        COMMENT %

              GRAPHIC WORKSHOP AMSTRAD 1512 SCREEN DRIVER
              COPYRIGHT (C) 1990 MARCEL WARD + ALCHEMY MINDWORKS INC.
              VERSION 1.1

              This is a driver for use as a Amstrad 1512 loadable driver
              for Graphic Workshop.

              To generate a driver from this file, it must be assembled
              to a binary file.

              Written with A86 in mind - should carry over to MASM without
              too much adjustment though.

                        %

VERSION         EQU     1
SUBVERSION      EQU     1

_A0FF           EQU     6                  ;STACK OFFSET

AMST_WIDE       EQU     640
AMST_DEEP       EQU     200
AMST_BYTES      EQU     80
AMST_SCREENSEG  EQU     0B800H

;THIS MACRO SELECTS A COLOUR PLANE
COLOURPLANE     MACRO                      ;#1 AS AN ARGUMENT
                MOV     AL,#1
                MOV     DX,03DDH           ;WRITE PLANE ADDRESS
                OUT     DX,AL              ;SET COLOUR PLANE
                #EM                        ;CHANGE TO ENDM FOR MASM COMPAT.

;THIS MACRO SELECTS THE PLANE FROM WHICH SCREEN MEMORY READS ARE TAKEN
READPLANE       MACRO
                MOV     AL,#1
                MOV     DX,03DEH
                OUT     DX,AL
                #EM

CODE            SEGMENT PARA PUBLIC 'CODE'
                ASSUME CS:CODE

                ORG 0000H

                DB      'ALCHDRV2'         ;SIGNATURE - DON'T CHANGE THIS

;THE FOLLOWING ARE THE POINTERS TO THE CALLABLE ROUTINES AND THE COMMON
;DATA. THE SEGMENTS ARE FILLED IN BY GWS.

DISPATCH        PROC    FAR
                DW      A1512_ON           ;FAR PTR TO 16 COLOUR MODE SELECT
                DW      ?
                DW      TRY256_LINE        ;FAR PTR TO 256 > 16 COLOUR LINE
                DW      ?
                DW      A1512_OFF          ;FAR PTR TO 16 COLR MODE DESELECT
                DW      ?
                DW      NOT_USED           ;FAR POINTER TO DUMMY PROC
                DW      ?
                DW      NOT_USED
                DW      ?

                DW      A1512_ON           ;FAR POINTER TO 1512 MODE SELECT
                DW      ?
                DW      A1512_LINE         ;FAR POINTER TO 1512 LINE DISPLAY
                DW      ?
                DW      A1512_OFF          ;FAR POINTER TO 1512 MODE DESELECT
                DW      ?
                DW      A1512_PALETTE      ;FAR POINTER TO NON-EXISTENT 1512
                DW      ?                  ;PALLETE SET!

                DW      HICGA_ON           ;FAR POINTER TO CGA MODE SELECT
                DW      ?
                DW      HICGA_FRAME        ;FAR POINTER TO CGA FRAME SELECT
                DW      ?
                DW      HICGA_LINE         ;FAR POINTER TO CGA LINE DISPLAY
                DW      ?
                DW      HICGA_OFF          ;FAR POINTER TO CGA MODE DESELECT
                DW      ?

                DW      0,0                ;NULL ONE
                DW      0,0                ;NULL TWO
                DW      0,0                ;NULL THREE
                DW      0,0                ;NULL FOUR

A_256WIDE       DW      AMST_WIDE
A_256DEEP       DW      AMST_DEEP
A_256SCRNSEG    DW      AMST_SCREENSEG
A_1512WIDE      DW      AMST_WIDE          ;640
A_1512DEEP      DW      AMST_DEEP          ;200
A_1512BYTES     DW      AMST_BYTES         ;80
A_1512SCRNSEG   DW      AMST_SCREENSEG     ;0b800
A_MONOWIDE      DW      AMST_WIDE
A_MONODEEP      DW      AMST_DEEP
A_MONOBYTES     DW      AMST_BYTES
A_MONOSCRNSEG   DW      AMST_SCREENSEG


;VERSION NUMBERS FOLLOW. YOU CAN CHANGE THE SUBVERSION NUMBER TO REFLECT
;CHANGES IN YOUR DRIVER ITSELF. THE VERSION VALUE MUST REMAIN UNCHANGED.
                DW      VERSION
                DW      SUBVERSION

;THE DESCRIPTION APPEARS IN THE F10 "ABOUT" BOX IN GRAPHIC WORKSHOP WHEN
;AN EXTERNAL DRIVER IS BEING USED. IT CAN'T EXCEED 24 CHARACTERS AND MUST
;BE NULL TERMINATED
                DB      'Amstrad 16 col 640x200 ',0
DISPATCH        ENDP

;THIS ROUTINE DISPLAYS A COLOUR-FUDGED 16 COLOUR LINE USING THE AMSTRAD
;SPECIFIC 16 COLOUR MODE FROM A 256 COLOUR LINE IN MEMORY. EXPECT TO SEE
;INCORRECT COLOURS APPEAR. SOME COLOURS WHICH APPEARED AS DARK COLOURS
;ON A 256 COLOUR SCREEN MAY NOT COME OUT AT ALL IN 16 COLOURS.
;A FULL SCREEN DISPLAYS IN ABOUT 10 SECONDS - THIS IS AS FAST AS I COULD
;GET IT BECAUSE OF THE ABSENCE OF USING COMMANDS SUCH AS REPNE MOVSB.
;AS I AM RELATIVELY NEW TO MACHINE CODE, HOWEVER, I DO NOT KNOW ALL OF
;THE COMMANDS AND WOULD WELCOME ANY ALTERATIONS TO A MORE EFFICIENT CODE.

;THE FIRST ARGUMENT ON THE STACK (2 WORDS) IS A FAR POINTER TO
;THE LINE. THE SECOND ARGUMENT IS THE LENGTH OF THE LINE IN PIXELS
TRY256_LINE     PROC    NEAR
                PUSH    BP
                MOV     BP,SP
                PUSH    DS
                PUSH    ES

                MOV     SI,[BP + _A0FF + 0]           ;OFFSET OF SOURCE
                MOV     DS,[BP + _A0FF + 2]           ;SEGMENT OF SOURCE

                MOV     BX,[BP + _A0FF + 6]           ;GET LINE NUMBER
                CMP     BX,AMST_DEEP
                JGE     SHOW256X           ;RESTORE REGISTERS AND EXIT

                SHL     BX,1
                MOV     DI,CS:[SCREENTABLE+BX]

                CLD
                MOV     CX,[BP + _A0FF + 4];LENGTH OF MOVE IN BYTES
                CMP     CX,0
                JE      SHOW256X           ;CHECK FOR NASTIES
                CMP     CX,AMST_WIDE
                JL      SHOW256A
                MOV     CX,AMST_WIDE
SHOW256A:       MOV     AX,AMST_SCREENSEG
                MOV     ES,AX

                PUSH    DI                 ;SCREENTABLE
                PUSH    SI                 ;OFFSET OF SOURCE
                PUSH    CX                 ;WIDTH OF LINE

;PLANE 8
                COLOURPLANE     8
                READPLANE       3
                MOV     AL,080H            ;BIT TO CONTROL

PLANE8_REPEAT:  MOV     AH,DS:[SI]         ;GET PIXEL
                AND     AH,08              ;ONLY WORRY ABOUT 4th BIT
                JZ      PLANE8_OFF
                OR      ES:[DI],AL         ;TURN BIT ON
                JMP     PLANE8_DONE
PLANE8_OFF:     NOT     AL
                AND     ES:[DI],AL         ;TURN BIT OFF
                NOT     AL
PLANE8_DONE:    INC     SI
                SHR     AL,1
                JNZ     PLANE8_BITOK
                MOV     AL,080H
                INC     DI
PLANE8_BITOK:   LOOP    PLANE8_REPEAT      ;IF NOT FINISHED

                POP     CX
                POP     SI
                POP     DI

                JMP     PLANE4JMP


SHOW256X:       POP     ES
                POP     DS
                POP     BP
                RETF

;PLANE 4
PLANE4JMP:      PUSH    DI                 ;SCREENTABLE
                PUSH    SI                 ;OFFSET OF SOURCE
                PUSH    CX                 ;WIDTH OF LINE

                COLOURPLANE     4
                READPLANE       2
                MOV     AL,080H            ;BIT TO CONTROL

PLANE4_REPEAT:  MOV     AH,DS:[SI]         ;GET PIXEL
                AND     AH,04              ;ONLY WORRY ABOUT 4th BIT
                JZ      PLANE4_OFF
                OR      ES:[DI],AL         ;TURN BIT ON
                JMP     PLANE4_DONE
PLANE4_OFF:     NOT     AL
                AND     ES:[DI],AL
                NOT     AL
PLANE4_DONE:    INC     SI
                SHR     AL,1
                JNZ     PLANE4_BITOK
                MOV     AL,080H
                INC     DI
PLANE4_BITOK:   LOOP    PLANE4_REPEAT      ;IF NOT FINISHED

                POP     CX
                POP     SI
                POP     DI

;PLANE 2
                PUSH    DI                 ;SCREENTABLE
                PUSH    SI                 ;OFFSET OF SOURCE
                PUSH    CX                 ;WIDTH OF LINE

                COLOURPLANE     2
                READPLANE       1
                MOV     AL,080H            ;BIT TO CONTROL

PLANE2_REPEAT:  MOV     AH,DS:[SI]         ;GET PIXEL
                AND     AH,02              ;ONLY WORRY ABOUT 2nd BIT
                JZ      PLANE2_OFF
                OR      ES:[DI],AL         ;TURN BIT ON
                JMP     PLANE2_DONE
PLANE2_OFF:     NOT     AL
                AND     ES:[DI],AL
                NOT     AL
PLANE2_DONE:    INC     SI
                SHR     AL,1
                JNZ     PLANE2_BITOK
                MOV     AL,080H
                INC     DI
PLANE2_BITOK:   LOOP    PLANE2_REPEAT      ;IF NOT FINISHED

                POP     CX
                POP     SI
                POP     DI

;PLANE 1
                COLOURPLANE     1
                READPLANE       0
                MOV     AL,080H            ;BIT TO CONTROL

PLANE1_REPEAT:  MOV     AH,DS:[SI]         ;GET PIXEL
                AND     AH,01              ;ONLY WORRY ABOUT LAST BIT
                JZ      PLANE1_OFF
                OR      ES:[DI],AL         ;TURN BIT ON
                JMP     PLANE1_DONE
PLANE1_OFF:     NOT     AL
                AND     ES:[DI],AL
                NOT     AL
PLANE1_DONE:    INC     SI
                SHR     AL,1
                JNZ     PLANE1_BITOK
                MOV     AL,080H
                INC     DI
PLANE1_BITOK:   LOOP    PLANE1_REPEAT      ;IF NOT FINISHED

                JMP     SHOW256X           ;ROUND UP

TRY256_LINE     ENDP

;THIS ROUTINE SELECTS THE AMSTRAD 16 COLOUR MODE
;THE HEIGHT AND WIDTH OF THE IMAGE ARE ON THE STACK - THESE
;MAY BE USEFUL IF YOU WANT TO PICK ONE OF SEVERAL AVAILABLE
;MODES BASED ON THE AREA OF THE PICTURE TO BE DISPLAYED
A1512_ON        PROC    NEAR
                MOV     AX,0006H
                INT     10H
                MOV     DX,03D9H
                MOV     AL,0FH
                OUT     DX,AL
                RETF
A1512_ON        ENDP

;THIS ROUTINE DISPLAYS AN AMSTRAD LINE
;THE FIRST ARGUMENT ON THE STACK (2 WORDS) IS A FAR POINTER TO
;THE LINE. THE SECOND ARGUMENT IS THE LENGTH OF THE LINE IN BYTES
A1512_LINE      PROC    NEAR
                PUSH    BP
                MOV     BP,SP
                PUSH    DS
                PUSH    ES

                MOV     SI,[BP + _A0FF + 0]      ;OFFSET OF SOURCE
                MOV     DS,[BP + _A0FF + 2]      ;SEGMENT OF SOURCE
                MOV     BX,[BP + _A0FF + 6]      ;GET LINE NUMBER
                CMP     BX,AMST_DEEP
                JGE     SHOWAMSTX

                SHL     BX,1
                MOV     DI,CS:[SCREENTABLE+BX]

                MOV     AX,AMST_SCREENSEG
                MOV     ES,AX
                MOV     BX,[BP + _A0FF + 4]      ;LENGTH OF MOVE IN BYTES

                MOV     CX,BX
                COLOURPLANE     1
                CLD
                PUSH    DI
         REPNE  MOVSB
                POP     DI

                MOV     CX,BX
                COLOURPLANE     2
                PUSH    DI
         REPNE  MOVSB
                POP     DI

                MOV     CX,BX
                COLOURPLANE     4
                PUSH    DI
         REPNE  MOVSB
                POP     DI

                MOV     CX,BX
                COLOURPLANE     8
                PUSH    DI
         REPNE  MOVSB
                POP     DI
                               ;COLOURPLANE 0FH NOT NEEDED HERE
SHOWAMSTX:      POP     ES
                POP     DS
                POP     BP
                RETF
AMST_LINE       ENDP

A1512_OFF       PROC    NEAR
                MOV     AX,0003H
                INT     10H
                RETF
A1512_OFF       ENDP

A1512_PALETTE   PROC    NEAR
                RETF
A1512_PALETTE   ENDP

HICGA_ON        PROC    NEAR
                MOV     AX,0006H
                INT     10H
                RETF
HICGA_ON        ENDP


UPDATE_MOVE     EQU     2
UPDATE_PAD      EQU     4
UPDATE_ADJUST   EQU     6

;THIS ROUTINE DISPLAYS A FULL MONOCHROME PAGE
;THE FIRST ARGUMENT ON THE STACK IS A FAR POINTER TO THE PAGE
;THE SECOND ARGUMENT IS THE WIDTH OF THE BITMAP (IN BYTES)
;THE THIRD ARGUMENT IS THE NUMBER OF LINES TO DISPLAY
;NOTE : THE SOURCE BUFFER MAY BE GREATER THAN 64K
HICGA_FRAME     PROC    NEAR
                PUSH    BP
                MOV     BP,SP
                SUB     SP,UPDATE_ADJUST
                PUSH    DS
                PUSH    ES

                MOV     AX,AMST_SCREENSEG              ;POINT TO THE SCREEN
                MOV     ES,AX
                MOV     AX,[BP + _A0FF + 4]           ;GET THE WIDTH OF MOVE
                MOV     [BP - UPDATE_MOVE],AX         ;SAVE IT LOCALLY
                MOV     WORD PTR [BP-UPDATE_PAD],0    ;SET ADJUSTMENT

                CMP     AX,AMST_BYTES      ;IF THE MOVE IS LESS THAN
                JL      UPDATE0            ;SCREEN WIDTH, GO FOR IT

                SUB     AX,AMST_BYTES      ;ELSE, SET MOVE WIDTH
                MOV     [BP-UPDATE_PAD],AX ;...AND THE AMOUNT TO

                MOV     AX,AMST_BYTES      ;...ADJUST THE POINTER
                MOV     [BP-UPDATE_MOVE],AX ;..AFTER EACH LINE

UPDATE0:        MOV     SI,[BP+ _A0FF + 0] ;OFFSET OF BITMAP
                MOV     DS,[BP+ _A0FF + 2] ;SEGMENT OF BITMAP
                MOV     CX,[BP+ _A0FF + 6] ;NUMBER OF LINES

                CLD
                SUB     BX,BX

UPDATE1:        PUSH    CX                 ;SAVE COUNT (LINE NUMBER)

                MOV     DI,CS:[SCREENTABLE + BX]
                ADD     BX,2               ;POINT TO THE NEXT LINE

                MOV     CX,[BP - UPDATE_MOVE]   ;GET THE MOVE SIZE
         REPNE  MOVSB                           ;DO THE MOVE

                ADD     SI,[BP-UPDATE_PAD] ;ADJUST THE POINTER

                CMP     SI,0F800H          ;ARE WE WITHIN 2K OF THE TOP?
                JL      UPDATE2            ;IF NOT, CARRY ON

                MOV     AX,SI              ;SEE HOW MANY SEGMENTS ARE IN
                MOV     CL,4               ;...SI (SI DIV 4)
                SHR     AX,CL

                MOV     CX,DS              ;ADD THEM TO DATA SEGMENT
                ADD     CX,AX              ;...(YOU CAN'T JUST ADD DS,AX)
                MOV     DS,CX
                AND     SI,000FH           ;ADJUST SI (SI MOD 16)

UPDATE2:        POP     CX                 ;GET COUNT BACK
                LOOP    UPDATE1            ;DECREMENT AND LOOP

                POP     ES
                POP     DS

                ADD     SP,UPDATE_ADJUST
                POP     BP

                RETF
HICGA_FRAME     ENDP

;THIS ROUTINE DISPLAYS A SINGLE MONOCHROME LINE
;THE FIRST ARGUMENT ON THE STACK IS A FAR POINTER TO THE LINE
;THE SECOND ARGUMENT IS THE LINE NUMBER
;THE THIRD ARGUMENT IS THE WIDTH OF THE BITMAP (IN BYTES)
HICGA_LINE      PROC    NEAR
                PUSH    BP
                MOV     BP,SP

                PUSH    DS
                PUSH    ES

                MOV     AX,AMST_SCREENSEG  ;POINT TO THE SCREEN
                MOV     ES,AX

                MOV     CX,[BP+ _A0FF + 6] ;SET THE WIDTH OF MOVE
                CMP     CX,0
                JE      MONO_LINE2
                CMP     CX,AMST_BYTES
                JL      MONO_LINE1
                MOV     CX,AMST_BYTES

MONO_LINE1:     MOV     SI,[BP + _A0FF + 0]     ;OFFSET OF BITMAP
                MOV     DS,[BP + _A0FF + 2]     ;SEGMENT OF BITMAP
                MOV     BX,[BP + _A0FF + 4]     ;GET LINE NUMBER
                SHL     BX,1

                CLD                             ;CLEAR DIRECTION FLAG
                MOV     DI,CS:[SCREENTABLE +BX]
         REPNE  MOVSB                           ;DO THE MOVE

MONO_LINE2:     POP     ES
                POP     DS
                POP     BP

                RETF
HICGA_LINE      ENDP

HICGA_OFF       PROC    NEAR
                MOV     AX,0003H
                INT     10H
                SUB     AX,AX
                RETF
MONO_OFF        ENDP

NOT_USED        PROC    NEAR
                RETF                       ;EXIT IMMEDIATELY
NOT_USED        ENDP

;THIS IS A LINE START LOOKUP TABLE
;I FIND THIS IS A BETTER WAY TO STORE THE TABLE WITH THE AMSTRAD AS IT
;DOES NOT CHANGE AT ALL AS CGA>EGA>VGA TABLES MIGHT. YOU MIGHT, HOWEVER,
;WANT TO DO AWAY WITH THIS AND SAVE A BIT OF VALUABLE SPACE?

SCREENTABLE     dw      00,02000,050,02050, 0a0,020a0,0f0,020f0
                dw      0140,02140,0190,02190, 01e0,021e0,0230,02230
                dw      0280,02280,02d0,022d0, 0320,02320,0370,02370
                dw      03c0,023c0,0410,02410, 0460,02460,04b0,024b0
                dw      0500,02500,0550,02550, 05a0,025a0,05f0,025f0
                dw      0640,02640,0690,02690, 06e0,026e0,0730,02730
                dw      0780,02780,07d0,027d0, 0820,02820,0870,02870
                dw      08c0,028c0,0910,02910, 0960,02960,09b0,029b0
                dw      0a00,02a00,0a50,02a50, 0aa0,02aa0,0af0,02af0
                dw      0b40,02b40,0b90,02b90, 0be0,02be0,0c30,02c30
                dw      0c80,02c80,0cd0,02cd0, 0d20,02d20,0d70,02d70
                dw      0dc0,02dc0,0e10,02e10, 0e60,02e60,0eb0,02eb0
                dw      0f00,02f00,0f50,02f50, 0fa0,02fa0,0ff0,02ff0
                dw    01040,03040,01090,03090, 010e0,030e0,01130,03130
                dw    01180,03180,011d0,031d0, 01220,03220,01270,03270
                dw    012c0,032c0,01310,03310, 01360,03360,013b0,033b0
                dw    01400,03400,01450,03450, 014a0,034a0,014f0,034f0
                dw    01540,03540,01590,03590, 015e0,035e0,01630,03630
                dw    01680,03680,016d0,036d0, 01720,03720,01770,03770
                dw    017c0,037c0,01810,03810, 01860,03860,018b0,038b0
                dw    01900,03900,01950,03950, 019a0,039a0,019f0,039f0
                dw    01a40,03a40,01a90,03a90, 01ae0,03ae0,01b30,03b30
                dw    01b80,03b80,01bd0,03bd0, 01c20,03c20,01c70,03c70
                dw    01cc0,03cc0,01d10,03d10, 01d60,03d60,01db0,03db0
                dw    01e00,03e00,01e50,03e50, 01ea0,03ea0,01ef0,03ef0

CODE            ENDS
                END
[ RETURN TO DIRECTORY ]