;**********************************************************************; ;* H E R C U L E S *; ;*--------------------------------------------------------------------*; ;* doel : definieert een aantal elementaire functies *; ;* voor de Hercules-kaart *; ;*--------------------------------------------------------------------*; ;* opm : alle functies verdelen het scherm in de *; ;* kolommen 0-79 en de regels 0-24 (tekstmodus) *; ;* resp. 0-719 en 0-347 (grafische modus) *; ;*--------------------------------------------------------------------*; ;* auteur : Roland Leurs *; ;* ontwikkeld : 24-1-92 *; ;*--------------------------------------------------------------------*; ;* gebruik : in hoofdprogramma opnemen met include, *; ;* de functies kunnen daarna via macro's opge- *; ;* roepen worden. *; ;**********************************************************************; ;== constanten ========================================================= STUUR_REG = 03B8h ;portadres stuurregister ADRES_6845 = 03B4h ;adresregister v.d. 6845 DATA_6845 = 03B5h ;data-register v.d. 6845 CONFIG_REG = 03BFh ;configuratieregister VIO_SEG = 0B000h ;segmentadres v.h. video-RAM CUR_START = 10 ;registernr. CRTC: 1e beeldlijn cursor CUR_END = 11 ;registernr. CRTC: laatste b.l. cursor CURPOS_HI = 14 ;registernr. CRTC: cursorpos. hi-byte CURPOS_LO = 15 ;registernr. CRTC: cursorpos. lo-byte ;== macro's ============================================================ setmode macro modus ;stuurregister zetten mov dx,STUUR_REG ;adres scherm-stuurregister mov al,modus ;nieuwe modus naar AL-register out dx,al ;modus naar stuurregister endm setvc macro ;schrijft een waarde in een ;van de CRTC-registers ;invoer: AL = registernummer ; AH = waarde mov dx,ADRES_6845 ;adres v.h. indexregister out dx,ax ;registernr. en nieuwe waarde endm regelz dw 0*160, 1*160, 2*160 ;beginadressen regels als dw 3*160, 4*160, 5*160 ;offsetadressen in het video-RAM dw 6*160, 7*160, 8*160 dw 9*160,10*160,11*160,12*160,13*160,14*160,15*160,16*160 dw 17*160,18*160,19*160,20*160,21*160,22*160,23*160,24*160 grafixt db 35h, 2Dh, 2Eh, 07h, 5Bh, 02h ;registerwaarden voor db 57h, 57h, 02h, 03h, 00h, 00h ;grafische modus textt db 61h, 50h, 52h, 0Fh, 19h, 06h ;registerwaarden voor db 19h, 19h, 02h, 0Dh, 0Bh, 0Ch ;tekstmodus ; werkruimte voor grafische routines: gcur_x dw ? ;grafische cursor gcur_y dw ? old_x dw ? ; oude coordinaten old_y dw ? lengte_x dw ? ; lengte van de lijn lengte_y dw ? teken_x dw ? ; richting teken_y dw ? plot_x dw ? ; te plotten coordinaat plot_y dw ? hulp dw ? ; hulppointer ;== code =============================================================== ;-- CONFIG: configureert de Hercules-kaart ---------------------------- ;-- invoer : AL : bit 0 = 0 : alleen tekstweergave mogelijk ;-- 1 : ook grafische weergave mogelijk ;-- bit 1 = 0 : 2e schermpagina niet te activeren ;-- 1 : 2e schermpagina ook te activeren ;-- uitvoer : geen ;-- registers: geen registers worden veranderd config proc near push ax push dx mov dx,CONFIG_REG ;adres configuratieregister out dx,al ;nieuwe waarde zetten pop dx pop ax ret config endp ;-- TEXT: schakelt de tekstmodus in --------------------------------- ;-- invoer : geen ;-- uitvoer : geen ;-- registers: geen registers worden veranderd text proc near push ax push bx push dx mov si,offset textt ;offsetadres registertabel mov bl,00100000b ;pagina 0 weergeven, tekst, knipperen jmp short vcprog ;video-controller opnieuw programmeren text endp ;-- GRAFIX: schakelt de grafische weergave aan -------------------------- ;-- invoer : geen ;-- uitvoer : geen ;-- registers: geen registers worden veranderd grafix proc near push ax push bx push dx mov si,offset grafixt ;offsetadres registertabel mov bl,00000010b ;pagina 0 weergeven, grafische modus grafix endp ;-- VCPROG: programmeert de video-controller -------------------------- ;-- invoer : SI = adres registertabel ;-- BL = waarde scherm-stuurregister ;-- uitvoer : geen ;-- registers: SI, en FLAGS worden veranderd vcprog proc near setmode bl ;bit 3 = 0: scherm uit push cx mov cx,12 ;12 registers worden gezet xor bh,bh ;met register 0 beginnen vcp1: lodsb ;registerwaarde uit tabel halen mov ah,al ;registerwaarde naar AH mov al,bh ;nummer register naar AL setvc ;waarde aan controller doorgeven inc bh ;volgend register aanspreken loop vcp1 ;verdere registers zetten or bl,8 ;bit 3 = 1: scherm aan setmode bl ;nieuwe modus activeren pop cx pop dx pop bx pop ax ret vcprog endp ;-- CDEF: definieert de 1e en laatste beeldlijn van de cursor ----- ;-- invoer : CL = eerste beeldlijn ;-- CH = laatste beeldlijn ;-- uitvoer : geen ;-- registers: AX en DX cdef proc near ; mov al,CUR_START ;register 10: eerste beeldlijn ; mov ah,cl ;eerste beeldlijn naar AH ; setvc ;aan video-controller doorgeven ; mov al,CUR_END ;register 11: laatste beeldlijn ; mov ah,ch ;laatste beeldlijn naar AH ; setvc ;aan video-controller doorgeven mov ah,01h ; functie 1 van int 10h int 10h ret cdef endp ;-- SETBLINK: zet de knipperende schermcursor -------------------- ;-- invoer : DI = offsetadres cursor ;-- uitvoer : geen ;-- registers: BX, AX en DX worden veranderd setblink proc near mov bx,di ;offset naar BX overbrengen mov al,CURPOS_HI ;register 14: hi-byte cursoroffset mov ah,bh ;hi-byte offset setvc ;aan video-controller doorgeven mov al,CURPOS_LO ;register 15: lo-byte cursoroffset mov ah,bl ;lo-byte offset setvc ;aan video-controller doorgeven setblink endp ;-- GETVC: leest een byte uit een register van de video-controller - ;-- invoer : AL = nummer register ;-- uitvoer : AL = inhoud register ;-- registers: DX en AL worden veranderd getvc proc near mov dx,ADRES_6845 ;adres indexregister out dx,al ;nummer register jmp $+2 ;korte pauze inc dx ;adres indexregister in al,dx ;inhoud naar AL ret getvc endp ;-- SCROLLUP: scrollt een venster N regels naar boven ---------------- ;-- invoer : BL = regel linker bovenhoek ;-- BH = kolom linker bovenhoek ;-- DL = regel rechter onderhoek ;-- DH = kolom rechter onderhoek ;-- CL = aantal regels dat wordt gescrolld ;-- BP = nummer schermpagina (0 of 1) ;-- uitvoer : geen ;-- registers: alleen FLAGS wordt veranderd ;-- opm : de vrijgekomen regels worden gewist scrollup proc near cld ;bij strings omhoog tellen push ax ;alle veranderde registers push bx ;op stack opslaan push di ;in dit geval is de push si ;volgorde belangrijk! push bx ;deze 3 registers worden al voor het push cx ;einde v.d. routine weer van stack geh. push dx sub dl,bl ;aantal regels berekenen inc dl sub dl,cl ;aantal te scr. regels aftrekken sub dh,bh ;aantal kolommen berekenen inc dh call calo ;linker bov.h. in offset omrekenen mov si,di ;adres in SI opslaan add bl,cl ;eerste regel gescrolld venster call calo ;eerste regel in offset omrekenen xchg si,di ;SI en DI verwisselen push ds ;segmentregister op stack push es ;opslaan mov ax,VIO_SEG ;segmentadres video-RAM mov ds,ax ;naar DS mov es,ax ;en ES brengen sup1: mov ax,di ;DI in AX opslaan mov bx,si ;SI in BX opslaan mov cl,dh ;aantal kolommen in teller rep movsw ;n regel verschuiven mov di,ax ;DI uit AX terughalen mov si,bx ;SI uit BX terughalen add di,160 ;telkens in volgende regel zetten add si,160 dec dl ;alle regels afgehandeld? jne sup1 ;NEE --> nog een regel verschuiven pop es ;segmentregister weer van pop ds ;stack halen pop dx ;rechter onderhoek terughalen pop cx ;aantal regels terughalen pop bx ;linker bovenhoek terughalen mov bl,dl ;onderste regel naar BL sub bl,cl ;aantal regels aftrekken inc bl mov ah,07h ;inverse video call clear ;vrijgekomen regels wissen pop si ;CX en DX zijn al pop di ;hersteld pop bx pop ax ret scrollup endp ;-- SCROLLDN: scrollt een venster N regels naar beneden -------------- ;-- invoer : BL = regel linker bovenhoek ;-- BH = kolom linker bovenhoek ;-- DL = regel rechter onderhoek ;-- DH = kolom rechter onderhoek ;-- CL = aantal regels dat wordt gescrolld ;-- BP = nummer schermpagina (0 of 1) ;-- uitvoer : geen ;-- registers: alleen FLAGS wordt veranderd ;-- opm : de vrijgekomen regels worden gewist scrolldn proc near cld ;bij strings omhoog tellen push ax ;alle veranderde push bx ;registers naar stack push di ;in dit geval is de push si ;volgorde belangrijk! push bx ;deze 3 registers worden al voor het push cx ;einde v.d. routine weer van stack geh. push dx sub dh,bh ;aantal kolommen berekenen inc dh mov al,bl ;linker bov.h. in AL opslaan mov bl,dl ;regel r.o. naar regel l.o. call calo ;linker bov.h. in offset omrekenen mov si,di ;adres in SI opslaan sub bl,cl ;aantal te scrollen regels aftrekken call calo ;linker bov.h. in offset omrekenen xchg si,di ;SI en DI verwisselen sub dl,al ;aantal regels berekenen inc dl sub dl,cl ;aantal te scr. regels aftrekken push ds ;segmentregister op stack push es ;opslaan mov ax,VIO_SEG ;segmentadres video-RAM mov ds,ax ;naar DS mov es,ax ;en ES bringen sdn1: mov ax,di ;DI naar AX mov bx,si ;SI naar BX mov cl,dh ;aantal kolommen in teller rep movsw ;n regel verschuiven mov di,ax ;DI uit AX terughalen mov si,bx ;SI uit BX terughalen sub di,160 ;telkens in volgende regel zetten sub si,160 dec dl ;alle regels afgehandeld? jne sdn1 ;NEE --> nog een regel verschuiven pop es ;segmentregister weer van pop ds ;stack halen pop dx ;rechter onderhoek terughalen pop cx ;aantal regels terughalen pop bx ;linker bovenhoek terughalen mov dl,bl ;bovenste regel naar DL add dl,cl ;aantal regels optellen dec dl mov ah,07h ;inverse video call clear ;vrijgekomen regels wissen pop si ;CX en DX zijn al pop di ;hersteld pop bx pop ax ret scrolldn endp ;-- CLS: hele scherm wissen --------------------------------------- ;-- invoer : BP = nummer schermpagina (0 of 1) ;-- uitvoer : geen ;-- registers: alleen FLAGS wordt veranderd clscr proc near xor bl,bl mov bh,schermpag mov bp,bx mov ah,07h ;normal video xor bx,bx ;linksboven is (0/0) mov dx,4F18h ;rechtsonder is (79/24) ;-- automatisch verder met CLEAR ----------------------------- clscr endp ;-- CLEAR: vult een bepaald schermgedeelte met spaties ------------ ;-- invoer : AH = attribuut ;-- BL = regel linker bovenhoek ;-- BH = kolom linker bovenhoek ;-- DL = regel rechter onderhoek ;-- DH = kolom rechter onderhoek ;-- BP = nummer schermpagina (0 of 1) ;-- uitvoer : geen ;-- registers: alleen FLAGS wordt veranderd clear proc near cld ;bij strings omhoog tellen push cx ;alle registers opslaan die push dx ;veranderen push si push di push es sub dl,bl ;aantal regels berekenen inc dl sub dh,bh ;aantal kolommen berekenen inc dh call calo ;offsetadres linker bovenhoek mov cx,VIO_SEG ;segmentadres video-RAM mov es,cx ;naar ES xor ch,ch ;hi-bytes teller op 0 mov al," " ;spatie clearl: mov si,di ;DI in SI opslaan mov cl,dh ;aantal kolommen in teller rep stosw ;spatie opslaan mov di,si ;DI uit SI terughalen add di,160 ;in volgende regel zetten dec dl ;alle regels afgehandeld? jne clearl ;NEE --> nog een regel wissen pop es ;registers pop di ;herstellen pop si pop dx pop cx ret clear endp ;-- PRINT: voert een string op het scherm uit ---------------------- ;-- invoer : AH = attribuut ;-- DI = offsetadres eerste teken ;-- SI = offsetadres string t.o.v. DS ;-- BP = nummer schermpagina (0 of 1) ;-- uitvoer : DI wijst op positie na laatste teken ;-- registers: AL, DI en FLAGS worden veranderd ;-- opm : string moet eindigen met nul-byte print proc near cld ;bij strings omhoog tellen push si ;SI, DX en ES op stack opslaan push es push dx mov dx,VIO_SEG ;segmentadres video-RAM eerst mov es,dx ;naar DX en dan naar ES lodsb ;eerste teken halen or al,al ;is het NUL je printe ;JA --> klaar print1: stosw ;attribuut in V-RAM opslaan lodsb ;volgende teken uit string halen or al,al ;is het NUL jne print1 ;NEE --> uitvoeren printe: pop dx ;SI, DX en ES weer van stack halen pop es pop si ret print endp ;-- CALO: rekent regel en kolom in een offsetadres om ----------------- ;-- invoer : BL = regel ;-- BH = kolom ;-- BP = nummer schermpagina (0 of 1) ;-- uitvoer : DI = het offsetadres ;-- registers: DI en FLAGS worden veranderd calo proc near push ax ;AX op stack opslaan push bx ;BX op stack opslaan shl bx,1 ;kolom en regel maal 2 mov al,bh ;kolom naar AL xor bh,bh ;hi-byte mov di,[regelz+bx] ;offsetadres regel halen xor ah,ah ;hi-byte kolomoffset add di,ax ;regel- en kolomoffset optellen or bp,bp ;schermpagina 0? je caloe ;JA --> adres o.k. add di,8000h ;32 Kb schermpagina 1 optellen caloe: pop bx ;BX weer van stack halen pop ax ;AX weer van stack halen ret calo endp ;-- CGR: hele grafische scherm wissen --------------------------------- ;-- invoer : BP = nummer schermpagina (0 of 1) ;-- AL = 00h : alle punten wissen ;-- FFh : alle punten zetten ;-- uitvoer : geen ;-- registers: AH, BX, CX, DI en FLAGS worden veranderd cgr proc near push es ;ES op stack opslaan cbw ;AL uitbreiden tot AH xor di,di ;offsetadres in video-RAM mov bx,VIO_SEG ;segmentadres schermpagina 0 or bp,bp ;pagina 1 wissen? je cgr1 ;NEE --> pagina 0 wissen add bx,0800h ;segmentadres schermpagina 1 cgr1: mov es,bx ;segmentadres naar segmentregister mov cx,4000h ;n pagina is 16 Kb woorden rep stosw ;pagina vullen pop es ;ES van stack terughalen ret cgr endp ;-- PIXEL: zet een punt in het grafische scherm ------------------------ ;-- invoer : BP = nummer schermpagina (0 of 1) ;-- BX = kolom (0-719) ;-- DX = regel (0-347) ;-- AL = bewerking (1=zetten,2=inverteren,3=wissen) ;-- uitvoer : geen ;-- registers: AX, DI en FLAGS worden veranderd pixel proc near cmp bx,719 ;test of beeldpunt buiten beeld valt ja spix6 ;spring indien buiten beeld cmp dx,347 ;idem voor y-coordinaat ja spix6 push es ;ES op stack opslaan push ax ;AX op stack opslaan push bx ;BX op stack opslaan push cx ;CX op stack opslaan push dx ;DX op stack opslaan push ax ;AX op stack opslaan mov ax,348 ;dx:=348-dx sub ax,dx mov dx,ax xor di,di ;offsetadres in video-RAM mov cx,VIO_SEG ;segmentadres schermpagina 0 or bp,bp ;pagina 1? je spix1 ;NEE --> pagina 0 add cx,0800h ;segmentadres schermpagina 1 spix1: mov es,cx ;segmentadres naar segmentregister mov ax,dx ;regel naar AX shr ax,1 ;regel 2 maal naar rechts schuiven, shr ax,1 ;d.w.z. door 4 delen mov cl,90 ;factor is 90 mul cl ;regel met 90 vermenigvuldigen and dx,11b ;alle bits behalve 0 en 1 uitzetten mov cl,3 ;3 verschuivingen ror dx,cl ;naar rechts roteren (* 2000h) mov di,bx ;kolom naar DI mov cl,3 ;3 verschuivingen shr di,cl ;door 8 delen add di,ax ;+ 90 * int(regel/4) add di,dx ;+ 2000h * (regel mod 4) mov cl,7 ;maximaal 7 verschuivingen and bx,7 ;kolom mod 8 sub cl,bl ;7 - kolom mod 8 mov ah,1 ;bitwaarde punten bepalen shl ah,cl mov al,es:[di] ;8 punten halen pop bx ;bewerking van stack halen cmp bl,03 ;mode 03 = pixel wissen jne spix2 xor ah,0ffh ;inverteer ah and al,ah ;punt wissen jmp short spix4 spix2: cmp bl,01 ;mode 01 = pixel zetten jne spix3 or al,ah ;punt zetten jmp short spix4 spix3: cmp bl,02 ;mode 02 = pixel inverteren jne spix5 xor al,ah ;punt inverteren spix4: mov es:[di],al ;8 punten terugschrijven spix5: pop dx ;DX weer van stack halen pop cx ;CX weer van stack halen pop bx ;BX weer van stack halen pop ax ;AX weer van stack halen pop es ;ES weer van stack halen spix6: ret pixel endp ;== macro definities ==================================================== move macro x,y mov bx,x mov dx,y xor bp,bp mov al,12 call plotr endm draw macro x,y mov bx,x mov dx,y xor bp,bp mov al,5 call plotr endm plot macro mode,x,y mov bx,x mov dx,y xor bp,bp mov al,mode call plotr endm initgraph macro call grafix xor bp,bp mov ax,bp call cgr endm clg macro xor bp,bp mov ax,bp call cgr endm exitgraph macro call text xor bp,bp call clscr endm cls macro xor bp,bp call clscr endm ; ==== EMULATIE ROUTINES ATOM GRAFISCHE MODI =============================== NO_EMUL DB "Atom graphics en hoge resolutie grafics worden niet",10,13 DB "ondersteund op een Herculesscherm",10,13 DB "Gebruik indien mogelijk het CGA/EGA pakket ! $" CLEAR0: CLEAR1: CLEAR1A: CLEAR2: CLEAR2A: CLEAR3: CLEAR3A: CLEAR4: CLEAR4A: EXITGRAPH MOV DX,OFFSET NO_EMUL MOV AH,09H INT 21H HALT: JMP HALT