;    s.ModeExBody
;
;******************************************************************************
;
;    This file is assembled with ObjAsm to an object file. This is linked with
;    another object file containing the header of ModeEx to form a relocatable
;    module providing an extra 'soft' screen mode: Mode 63.
;
;    Points demonstrated here include:
;        - Constructing a relocatable module using assembly language
;        - ObjAsm directives
;        - Implementing soft screen modes
;        - GETting header files
;

; Use the GET directive to include a list of SWI names as if typed here

        GET     ^.AsmHdrs.h.SWINames

; EXPORTs and AREA directive

        AREA    |ModeEx$$Code|, CODE, READONLY

        EXPORT  |ModeEx_Service|
        EXPORT  |ModeEx_FastService|


Service_ModeExtension * &50

MonitorType_Normal * 0
MonitorType_MultiSync * 1
MonitorType_HiResMono * 2
MonitorType_VGA * 3
MonitorType_DontCare * -1

Normal          *       1 :SHL: MonitorType_Normal
MultiSync       *       1 :SHL: MonitorType_MultiSync
HiResMono       *       1 :SHL: MonitorType_HiResMono
VGA             *       1 :SHL: MonitorType_VGA

;******************************************************************************
;
;       ModeEx_Service - Service call handler
;
; in:   r1 = service reason code
;       r2 = screen mode in question
;       r3 = monitor type
;

|ModeEx_Service|

        TEQ     r1, #Service_ModeExtension  ; correct service call?
        TEQEQ   r2, #63                     ; screen mode added here?
        MOVNE   pc, lr                      ; no, so don't claim call

; Fast service call entry point. RISC OS 4 and above will enter here
; only for service calls listed in the fast service call table.
|ModeEx_FastService|
        TEQ     r3, #MonitorType_HiResMono  ; unsuitable monitor?
        MOVEQ   pc, lr

        ADR     r3, vidc_list               ; all OK, so point at VIDC data
        ADR     r4, workspace_list          ; and workspace list
        MOV     r1, #0                      ; claim service
        MOV     pc, lr


;******************************************************************************
;
;   Now for the mode data
;
;   To experiment with your own modes, change the next two parameters...
;

H_Characters    *       96                  ; max value, no border
V_Characters    *       36                  ; max value, no border

; Altering the following really requires a VIDC datasheet...

Base_Mode       *       12
Bits_PerPixel   *       4

H_Sync          *       76                  ; must be even
H_BackPorch     *       121                 ; must be odd
H_Display       *       8 * H_Characters    ; must be even
Left_Border     *       (768 - H_Display)/2 ; must be even
Right_Border    *       Left_Border         ; must be even
H_FrontPorch    *       59                  ; must be odd

V_Sync          *       3
V_BackPorch     *       21
V_Display       *       8 * V_Characters
Top_Border      *       (288 - V_Display)/2
Bottom_Border   *       Top_Border
V_FrontPorch    *       0


vidc_list

        DCD     0
        DCD     Base_Mode

; Horizontal VIDC registers

        DCD     (&80:SHL:24) :OR: (((H_Sync+H_BackPorch+Left_Border+H_Display+Right_Border+H_FrontPorch -2)/2) :SHL: 14)
        DCD     (&84:SHL:24) :OR: (((H_Sync -2)/2) :SHL: 14)
        DCD     (&88:SHL:24) :OR: (((H_Sync+H_BackPorch -1)/2) :SHL: 14)
        DCD     (&8c:SHL:24) :OR: (((H_Sync+H_BackPorch+Left_Border -7)/2) :SHL: 14)
        DCD     (&90:SHL:24) :OR: (((H_Sync+H_BackPorch+Left_Border+H_Display -7)/2) :SHL: 14)
        DCD     (&94:SHL:24) :OR: (((H_Sync+H_BackPorch+Left_Border+H_Display+Right_Border -1)/2) :SHL: 14)

; Vertical VIDC registers

        DCD     (&a0:SHL:24) :OR: ((V_Sync+V_BackPorch+Top_Border+V_Display+Bottom_Border+V_FrontPorch -1) :SHL: 14)
        DCD     (&a4:SHL:24) :OR: ((V_Sync -1) :SHL: 14)
        DCD     (&a8:SHL:24) :OR: ((V_Sync+V_BackPorch -1) :SHL: 14)
        DCD     (&ac:SHL:24) :OR: ((V_Sync+V_BackPorch+Top_Border -1) :SHL: 14)
        DCD     (&b0:SHL:24) :OR: ((V_Sync+V_BackPorch+Top_Border+V_Display -1) :SHL: 14)
        DCD     (&b4:SHL:24) :OR: ((V_Sync+V_BackPorch+Top_Border+V_Display+Bottom_Border -1) :SHL: 14)

        DCD     -1

; See the description of SWI OS_ReadModeVariable in the Programmer's
; Reference Manual to understand the following.

workspace_list

        DCD     0
        DCD     Base_Mode

        DCD     1
        DCD     H_Characters - 1

        DCD     2
        DCD     V_Characters - 1

        DCD     6
        DCD     H_Characters * Bits_PerPixel

        DCD     7
        DCD     H_Characters * Bits_PerPixel * V_Display

        DCD     11
        DCD     H_Display - 1

        DCD     12
        DCD     V_Display - 1

        DCD     -1


        END
