'                                X86IOPIX.BAS
'                       * PALETTE PROGRAMMING EXAMPLE *
'                      * FROM CPCALIVE X86 ENVIRONMENT *
|input,"ex\X86IOPix.exe":call 0
10 defint p:dim pal(256*3)
20 |PALASK,@pal(0):'load palette (keep 16 first pens)
30 gosub 1000:|PALSET,@pal(0):mode 1
50 PRINT"display a line with |OPIX and read"
60 PRINT"colors index (GRAPHICS PEN) with |IPIX"
70 pix%=0:for x=0 to 200:|OPIX,x,190,x:|IPIX,x,190,@pix%:?hex$(pix%,2)":";:next
80 end
1000 '*PALETTE PROGRAMMING EXAMPLE*
1010 InkRef=128:'<-Change InkRef value for various result
1020 for i=16 to 31:pal(i*3+0)=(i-8)*8:pal(i*3+1)=(i-8)*8:pal(i*3+2)=(i-8)*8:next
1030 for i=32 to 63:pal(i*3+0)=InkRef:pal(i*3+1)=(i-32)*8:pal(i*3+2)=(i-32)*8:next
1040 for i=64 to 95:pal(i*3+0)=(i-64)*8:pal(i*3+1)=InkRef:pal(i*3+2)=(i-64)*8:next
1050 for i=96 to 127:pal(i*3+0)=(i-96)*8:pal(i*3+1)=(i-96)*8:pal(i*3+2)=InkRef:next
1060 for i=128 to 159:pal(i*3+0)=InkRef:pal(i*3+1)=InkRef:pal(i*3+2)=(i-128)*8:next
1070 for i=160 to 191:pal(i*3+0)=InkRef:pal(i*3+1)=(i-160)*8:pal(i*3+2)=InkRef:next
1080 for i=192 to 223:pal(i*3+0)=(i-192)*8:pal(i*3+1)=InkRef:pal(i*3+2)=InkRef:next
1090 for i=224 to 255:pal(i*3+0)=InkRef:pal(i*3+1)=int(InkRef/2):pal(i*3+2)=(i-224)*8:next
1100 return
run
|INPUT,":CLOSE"
;                               X86IOPIX.ASM
.MODEL SMALL ; forces Masm to make a .EXE
.STACK 040h
.CODE
.386
;****************************************************************************
;**                   MODULE EXAMPLE FOR CpcALive                          **
;****************************************************************************
; Assembly from the CpcAlive directory:
; Ml /Zi /c /FoEX\X86IOPix.OBJ EX\X86IOPix.ASM
;	-> create the file EX\X86IOPix.OBJ
; LINK /LINENUMBERS EX\X86IOPix.OBJ,EX\X86IOPix.EXE,EX\X86IOPix.MAP,,,
;	-> create the file EX\X86IOPix.EXE and EX\X86IOPix.MAP
; Loading this module from the Dos command line: ! EX\X86IOPix.EXE
; Loading this module from a CpcAlive command file: EX\X86IOPix.EXE
; Loading this module from the Cpc BASIC interpreter: |INPUT, "EX\X86IOPix":call 0
; commands from the Dos command line:
; |OPIXDBG,X,Y,pen   - FOR DEBUGGER EXAMPLE
; |OPIX,X,Y,pen   - OUTPUT PIXEL
; |IPIX,X,Y,@pen% - INPUT PIXEL
; |PALSET,@PAL(0) - SET PALETTE FROM A SUBSCRIPTED VARIABLE
; |PALASK,@PAL(0) - LOAD PALETTE INTO A SUBSCRIPTED VARIABLE
; |PALGREY        - CONVERT A PALETTE INTO SHADES OF GRAY
; - initialize the variable @pen% with pen%=0 for |IPIX
; - X and Y are relative to the top left corner of the screen
;****************************************************************************

START:          push cs
                pop ds
                mov dx,offset Mes
                mov ah,9
                int 021H
                mov ax,04C00h
                int 021h

Mes             db "Ce fichier est un module CpcAlive.",13,10
                db "This file is a CpcAlive module.",13,10
                db "http://cpcalive.com.",13,10,"$"

;installation table of this X86 module

org 0200h
                db 'X86CPC'			; 0200h mark
                dw 2                ; 0206h version
                dw offset X86Vec    ; 0208h entry vectors table
                dw 0                ; 020Ah reserved
                dw 0                ; 020Ch reserved
                dw 0                ; 020Eh reserved
                dw offset MnemoTb   ; 0210h offset names table for calls with Basic
                db -1               ; 0212h (*) receipt the X86 module area number
                db -1               ; 0213h module complement number or bank Cpc block number
                db -1                             ; 0214h (*) reçeipt the Z80 rom number associated
                db -1               ; 0215h indicator for Cpc banks or modules complements connection
                dw -1               ; 0216h (*) receipt the first Cpc accessible address (0=no address accessible)
                db 0                ; 0218h reserved
                dw 0                ; 0219h (*) receipt the ems handle associated to the module
                dw 0                ; 021Bh (*) receipt the logical number of the first 16K page of the module
                db 0                ; 021Dh reserved
                dw 0                ; 021Eh address called when the emulator exit (0=no call)
                dw 0                ; 0220h address called when the emulator is put in "sleep mode" (0=no call)
                dw 0                ; 0222h address called when the emulator return from "sleep mode" (0=no call)
                dw 0                ; 0224h address called when the module is load (0=no call)
                dw 0                ; 0226h reserved
                db 0                ; 0228h receipt the number of 16K pages allocated to the module (*)
                                    ;            or number of pages to be allocated (if <>0 when the module is loaded)
                                    ;            or number of connected pages (*)
                                    ;            or number of pages to connect
				dw offset MapName	; 0229h offset .MAP file for debugger
									;		assembly:	ML /Zi /c /FoFileName.OBJ Filename.ASM
									;					LINK /LINENUMBERS FileName.OBJ,FileName.EXE,FileName.MAP,,,
				dw 0				; 022Bh memorize the stack segment SS for C++ modules
				dw 0				; 022Dh memorize the stack pointer SP for C++ modules
				db 6				; 022Fh vector number to debug (-1=not set)
                db 0100h-029h dup (0)   ; 0229h reserved

;(*) = value generated by the system

;*****************************************************************************
MnemoTb         db "PIXIN","I" or 080h          ; |PIXINI
                db "OPI","X" or 080h            ; |OPIX
                db "IPI","X" or 080h            ; |IPIX
                db "PALSE","T" or 080h          ; |PALSET
                db "PALAS","K" or 080h          ; |PALASK
                db "PALGRE","Y" or 080h         ; |PALGREY
                db "OPIXDB","G" or 080h         ; |OPIXDBG <-- Debugger X86 test --
                db 0

X86Vec          dw offset PixIni        ; 00 ** |PIXINI - INIT **
                dw offset OPix          ; 01 ** |OPIX,X,Y,PEN - OUTPUT PIXEL TROUGHT INT 010H **
                dw offset IPix          ; 02 ** |IPIX,X,Y,@PEN% - READ PIXEL TROUGHT INT 010H **
                dw offset PalSet        ; 03 ** |PALSET,@PAL(0) - SET PALETTE FROM A SUBSCRIPTED VARIABLE **
                dw offset PalAsk        ; 04 ** |PALASK,@PAL(0) - LOAD PALETTE INTO A SUBSCRIPTED VARIABLE **
                dw offset PalGrey       ; 05 ** |PALGREY - CONVERT A PALETTE INTO SHADES OF GRAY **
										; -- X86 test debugger --
										; CS:022Fh=6=vector number to debug (-1=not set)
                dw offset OPixDbg       ; 06 ** |OPIXDBG,X,Y,PEN - OUTPUT PIXEL TROUGHT INT 010H **
                ;... 128 vectors max

MapName			db 'EX\X86IOPix.MAP',0			; .MAP filename for debugger

; AH or AX values for the interruption 018H
; ** Reading the ram BANK 0 of the Cpc (ram blocs 0,1,2,3) from the X86 environment
ReadAL=0        ; (AH) Read the byte pointed by SI and put it in AL
ReadAH=0200h    ; (AX) Read the byte pointed by SI and put it in AH
ReadBL=0201h    ; (AX) Read the byte pointed by SI and put it in BL
ReadBH=0202h    ; (AX) Read the byte pointed by SI and put it in BH
ReadCL=0203h    ; (AX) Read the byte pointed by SI and put it in CL
ReadCH=0204h    ; (AX) Read the byte pointed by SI and put it in CH
ReadDL=0205h    ; (AX) Read the byte pointed by SI and put it in DL
ReadDH=0206h    ; (AX) Read the byte pointed by SI and put it in DH
ReadAX=0207h    ; (AX) Read the word pointed by SI and put it in AX
ReadBX=0208h    ; (AX) Read the word pointed by SI and put it in BX
ReadCX=0209h    ; (AX) Read the word pointed by SI and put it in CX
ReadDX=020Ah    ; (AX) Read the word pointed by SI and put it in DX
ReadSI=020Bh    ; (AX) Read the word pointed by SI and put it in SI
ReadDI=020Ch    ; (AX) Read the word pointed by SI and put it in DI
ReadBP=020Dh    ; (AX) Read the word pointed by SI and put it in BP
; ** Writing in the ram BANK 0 of the Cpc (ram blocs 0,1,2,3) from the X86 environment
WriteAL=1       ; (AH) Write the value of AL in the byte pointed by DI
WriteBL=0301h   ; (AX) Write the value of BL in the byte pointed by DI
WriteBH=0302h   ; (AX) Write the value of BH in the byte pointed by DI
WriteCL=0303h   ; (AX) Write the value of CL in the byte pointed by DI
WriteCH=0304h   ; (AX) Write the value of CH in the byte pointed by DI
WriteDL=0305h   ; (AX) Write the value of DL in the byte pointed by DI
WriteDH=0306h   ; (AX) Write the value of DH in the byte pointed by DI
WriteBX=0308h   ; (AX) Write the value of BX in the word pointed by DI
WriteCX=0309h   ; (AX) Write the value of CX in the word pointed by DI
WriteDX=030Ah   ; (AX) Write the value of DX in the word pointed by DI
WriteBP=030Dh   ; (AX) Write the value of BP in the word pointed by DI

PixIni:
                pusha
                mov dx,offset IniMes
                mov ah,9
                int 021H
                popa
                stc                     ; carry="ok"
                RETF                    ; FAR RETURN

IniMes          db " X86IOPix - 2025",13,10
                db "$"

; -- Debugger X86 test --
; CS:022Fh=vector number to debug (-1=not set)
; ** |OPIXDBG,X,Y,PEN - OUTPUT PIXEL TROUGHT INT 010H **
OPixDbg:		jmp Opix

; ** OUTPUT PIXEL TROUGHT INT 010H - |OPIX,X,Y,PEN **
; < input conditions RamCpc:[SI+0] = PEN number
;                    RamCpc:[SI+2] = y
;                    RamCpc:[SI+4] = x
OPix:
                mov ah,ReadAL           ; load RamCpc:[SI+0] value in AL
                int 018h                ; pen number in AL
                push ax                 ; save pen number
                add si,2                ; Y coordinate point in RamCpc
                mov ax,ReadDX           ; load value in DX
                int 018h                ; Y coordinate in DX
                add si,2                ; X coordinate point in RamCpc
                mov ax,ReadCX           ; load value in CX
                int 018h                ; X coordinate CX
                pop ax                  ; pen number
                mov ah,0Ch              ; //BIOS//FUNCTION 0CH = OUTPUT PIXEL
                INT 010h                ; CALL BIOS INTERRUPTION 010H
                RETF                    ; FAR RETURN

; ** INPUT PIXEL TROUGHT INT 010H - |IPIX,X,Y,@PEN% **
; < input conditions  RamCpc:[SI+2] = y
;                     RamCpc:[SI+4] = x
; > output conditions RamCpc:[SI+0] = PEN number
IPix:                
                push bx
                push di
                push si                 ; save pointer address PEN
                add si,2                ; Y coordinate point in RamCpc
                mov ax,ReadDX           ; load value in DX
                int 018h                ; Y coordinate in DX
                add si,2                ; X coordinate point in RamCpc
                mov ax,ReadCX           ; load value in CX
                int 018h                ; X coordinate in CX
                mov ah,0Dh              ; //BIOS//FUNCTION 0DH = INPUT PIXEL
                INT 010h                ; CALL BIOS INTERRUPTION 010H
                pop si                  ; restore pointer address PEN
                push ax                 ; save pen number
                mov ax,ReadDI           ; load PEN adress in DI
                int 018h
                pop bx                  ; restore pen number
                xor bh,bh
                mov ax,WriteBX          ; put BX in RamCpc:[DI+0]
                int 018h
                pop di
                pop bx
                RETF                    ; FAR RETURN

; ** |PALASK,@PAL(0) - LOAD PALETTE INTO A SUBSCRIPTED VARIABLE **
PalAsk:
                pusha
                push es
                mov ax,ReadSI           ; load the address of the 1st element of the array into SI
                int 018h

                push si
                sub si,2
                mov ax,ReadCX           ; load "number of elements in the array + 1" into CX
                int 018h
                dec cx
                and ch,3                ; number of elements in the array 3*256 max
                pop di                  ; point 1st element of the table

                push cx
                mov ax,cx               ; number of elements in the array
                mov cx,3                ; divisor
                xor dx,dx               ; ?
                div cx                  ; /3 = number of colors to load into the buffer
                mov cx,ax               ; result in cx

                push cs
                pop es                  ; segment of color palette
                mov dx,offset Palette   ; offset color palette
                mov bx,0                ; first index
                mov ax,01017h           ; //BIOS//FUNCTION: READ CONTENT MULTIPLE COLOR REGISTERS DAC
                INT 010H                ; CALL BIOS INTERRUPTION 010H
                pop cx                  ; retrieve number of elements from the array

                mov si,offset Palette   ; offset color palette
PalAskCont:     mov al,cs:[si]          ; load collor index
                shl al,2                ; 64>255tones
                mov ah,WriteAL          ; Write the value of AL in the byte pointed to by DI.
                int 018h
                add di,2                ; 2 bytes per element for the destination array
                inc si                  ; 1 byte per element for the source buffer
                loop PalAskCont         ; continue if there are still elements
                pop es
                popa
                RETF                    ; FAR RETURN

Palette         db 256*3 dup (0)        ; color palette buffer (RGB)

; ** |PALSET,@PAL(0) - SET PALETTE FROM A SUBSCRIPTED VARIABLE **
; remark: the table must have been defined by the basic instruction DEFINT
PalSet:
                pusha
                push es
                mov ax,ReadSI           ; load the address of the 1st element of the array into SI
                int 018h

                push si
                sub si,2
                mov ax,ReadCX           ; load "number of elements in the array + 1" into CX
                int 018h
                dec cx
                and ch,3                ; number of elements in the array 3*256 max
                pop si

                push cx
                mov di,offset Palette   ; offset color palette
PalSetCont:     mov ah,ReadAL           ; load RamCpc:[SI+0] value in AL
                int 018h                ; pen number in AL
                shr al,2                ; 255>64tones
                mov cs:[di],al          ; set color number in 'Palette' buffer
                add si,2                ; 2 bytes per element for the source table
                inc di                  ; 1 byte per element for the destination buffer
                loop PalSetCont         ; continue if there are still elements
                pop ax                  ; number of elements in the array
                mov cx,3                ; divisor
                xor dx,dx               ; ?
                div cx                  ; /3 = number of colors to redefine
                mov cx,ax               ; result in cx
                push cs
                pop es                  ; segment of color palette
                mov dx,offset Palette   ; offset of color palette
                mov bx,0                ; first index
                mov ax,01012h           ; //BIOS//FUNCTION: LOAD MULTIPLE COLOR DAC REGISTERS
                INT 010h                ; CALL BIOS INTERRUPTION 010H
                pop es
                popa
                RETF                    ; FAR RETURN


; ** |PALGREY - CONVERT A PALETTE INTO SHADES OF GRAY **
PalGrey:
                pusha
                mov bx,0                ; first index
                mov cx,256              ; number of colors to process
                mov ax,0101Bh           ; //BIOS//FUNCTION: Convert multiple DAC color
                                        ;                   registers to shades of gray
                INT 010h                ; CALL BIOS INTERRUPTION 010H
                popa
                RETF                    ; FAR RETURN


end start
