Extended screen “Profi”, what is it and how to work with it. Workshop 001. Loading a picture. GRF

Continuation of the article series on working with the extended computer screen “Profi”. First practical lesson.

Where does learning something new begin? Correctly, with the “base”. As a rule, the base is loading and the simplest output of test information. That's why here we'll start with loading and outputting an image. We'll learn not only to output data to the screen, but also to read it from media.

The article was published in 2019 in Issue 26 of the ZX Spectrum magazine “ZaRulem Printed Word”.

The article was co-authored with Vadim Chertkov.


Last time we looked at the structure of the extended screen of the Profi computer, with this material we open the section “Workshop” in which we will consider the main (basic) tasks that arise when working with it. I do not plan to give a detailed analysis or universal solutions. The task of this material is to overcome the fears and uncertainty “like – it's difficult, it's long, I can't figure it out, etc.” in those who decide to work with this wonderful machine.

All material will be focused on working in the CP/M OS using the M80 assembler. Despite its venerable age, the M80 assembler is quite good and copes with its tasks quite successfully. If you have any questions about setting up the CP/M OS or the M80 assembler, please contact us, we will answer you personally. Perhaps in the future, material will be prepared on these topics. But now these questions are beyond the scope of the task.

Despite the orientation of the material on the CP/M OS, it will also be useful for working with an extended screen in Spectrum mode. The differences between the CP/M and Spectrum modes will be discussed separately in more detail. There is no difference in these modes directly when working with an extended screen.

One of the most common tasks when working with any screen is loading an image onto it from an external drive. Currently, such drives can be (regarding Profi 5.06): FDD drive, HDD hard drive, CD-ROM, SD Card, CompactFlash card, RAM disk. When working in CP/M OS, from a programming point of view, there is no difference where the information is loaded from, the system takes on all the headaches. Only the data loading speed will differ.

The main graphic format in the CP/M OS is the GRF format, and we will enter it on the screen.

A GRF file consists of a header (1 or more sectors) and graphic data. The header format is as follows:

+0

Word

DW

HSIZE

horizontal size of the image in dots, pixels

+2

Word

DW

VSIZE

vertical size in lines of the picture, pixels

+4

Byte

DB

BPP

bits per dot or dots per byte (depending on AMOD)

+5

Byte

DB

AMOD

1 – color for each point,

0 – attribute byte per dot byte

+6

Word

DW

BPS

length of one raster line image in bytes

+8

Byte

DB

HLE

header length in records is 128 bytes (both 0 and 1 correspond to 128 bytes)

+9

Byte

DB

0 – standard format flag (if the format changes, this byte will change too)

19 (#13) – file with palette GGGRRRBB

+10

DB

Reserve 118 x DB 0

or palette (with +9=19(#13)). 16 bytes, 1 byte per color in GGGRRRBB format, followed by zeros.

As you can see, the image size can be up to 65535 pixels in width and height, and the color up to 256 colors per pixel, which is significantly higher than the capabilities of “Profi”. But so far there are no known cases where anyone has seen files of a format other than PROFI-color and PROFI-mono. Of course, this does not mean that they do not exist.

For simplicity, we will assume that we are outputting a picture with a size of 512×240 pixels in the extended “Profi” screen, and the height can be any (in this case, the first 240 lines will be output). We assume that we are working on a “Profi” computer with a palette of 16 out of 256 colors. And we will distinguish only the “Profi” format black and white, color (standard 16 colors) and with a palette.

Let's start with a quick analysis (a detailed analysis, again, is beyond the scope of the current material) of how files are handled in the CP/M OS.

File operations (and all other operations) are performed by calling BDOS functions, which use the standard BDOS operation calling conventions. Access is via the entry point at cell 0005H. When entering BDOS, register C contains the BDOS operation number, and register pair DE contains the byte, word, or address of the information. BDOS returns a 1-byte result in register A, and 2-bytes in register pair HL. Also, on return, register A=L, B=H.

BDOS does not save the input values ​​of the calling program's registers, so the required values ​​must be saved by the program itself.

For ease of access to BDOS functions, the macro “.bdos” was written (see appendix). When calling it, the first parameter specifies the operation number, and the second an additional parameter, if any.

In order not to remember the numbers of all the functions, we assign them names. Here I will give only those that will be used in the examples. The full list can be seen in the file “BIOSK.INC” located in the archive with practical materials. We will consider the functions themselves as the article progresses.

bdExit       equ 0   ; Сброс системы
bdWrite      equ 9   ; Вывод последовательности символов
bdOpen       equ 15  ; Открытие файла
bdReadCon    equ 20  ; Последовательное чтение
bdPDPInst    equ 26  ; Установка адреса буфера ПДП
bdBSVV       equ 50  ; Вызов операции БСВВ или операций расширенной BDOS

The palette installation subroutine also uses BIOS resources.

BIOS (Basic Input/Output System) – Basic Input/Output System (BIOS). The word “Concurrent” in the name was apparently chosen by analogy with the names of the systems of the Digital Research company: Concurrent DOS and Concurrent DOS/86. The first version of CBIOS was written by Krestyanikov A.A. (KiiA) in 1992.

The kernel, i.e. a group of entry points, is located from address F800h. Drivers are connected at the boot stage via the CONFIG.SYS file. This is a more flexible scheme than in CP/M systems, where all drivers are “hardwired” into the BIOS body and to change any driver, the entire module must be recreated.

We will use two BIOS subroutines: SETCMRS and GETADR, as well as the TIME vector (table).

SETCMRS – set CMRS values. At the input DE=CMRS. Register D is the value for CMR0 (7FFDh), register E is the value for CMR1 (DFFDh). The function outputs values ​​to the ports and saves DE in the MCMRS variable. On Profi, two registers are used to manage memory, and the peripheral control bits are also set in them. That is, this function is used to change access to the peripherals, enable/disable ROM, and connect pages. In this program, we will use it to access the pages of the screen area. Additionally, we will say that all utilities and drivers under SP-DOS & CBIOS use this procedure, since the CMR0 & CMR1 registers are available only for writing. If all programs leave the last output values ​​in a variable in RAM, you can easily find out these values.

GETADR – Get the vector (table) address. At the input to reg. C is the vector number (CBIOS table), at the output the procedure returns the address of the vector (table) start to HL.

TIME – a vector (table) consisting of TIK, SEC, MIN, HOUR, DAY, MONTH, YEAR-1980. In addition, at offset -1 is BORD – the current contents of the border, sound and tape recorder register, and at offset -2 is INTRFLAG, equal to 0FFH during interrupt processing, and 0 the rest of the time.

Let's start the program by setting the address of the direct access buffer to the PDP memory. This is the place where data will be read from the disk. It is set by the BDOS operation “26. Setting the address of the PDP buffer”, which was given the name “bdPDPInst”. In our case, we will read data from the disk by 1 sector (128 bytes). We write the buffer at the end of the listing “PDP_SCR: ds 128” and set “.bdos bdPDPInst, PDP_SCR”.

The multiselector counter is responsible for the number of sectors read from the disk at one time; its value can be changed by the BDOS operation “44. Setting the multiselector counter” within the range of 1…128 sectors. The default value is 1, so in our case, nothing needs to be changed.

Files are accessed through the File Control Block (FCB). This is a data structure that is organized and initialized by the transit program and is used by the file system when accessing files through the table of contents. All file operations access the FCB for initial information. The system stores the current state of the file in the FCB during file operations.

When calling operations that access files or the table of contents, the DE register pair must contain a BUF pointing to the file or files with which the operation is to be performed. For most operations, the BUF length is 33 bytes, and for random access operations, calculating the file size and free disk space, the BUF size is 36 bytes.

You can create a BUF using the special BDOS function “152. Preparing a BUF”, but in our case this is not required. To simplify the task, we will pass the name of the output file as a parameter when calling our program. In the “Base Memory Page” there is a BUF area 1 (005Ch-0068h), after running programs with a parameter, the file name that immediately follows the name of the called program will be entered into it. Which in this case suits us more than well. For convenience, we will assign the buffer a symbolic name “scr_buf EQU 005CH”.

Now we are ready to work with the file. Open it for access. Use the BDOS operation “15. Opening a file” “.bdos bdOpen, scr_buf”. The operation activates the specified BUF.

In case of an error, the operation “15. Open file” returns the value 255 in the A register, and the error code in the H register. For simplicity, we will assume that any return of the value 255 in the A register means that the file is not on the disk. So after executing the BDOS operation “15. Open file”, you need to check the A register for equality of the contents to 255, and if so, display an error message and exit the program.

To display the message, we will use the macro “say” (see the appendix), which displays the text string specified in the first parameter at the current coordinates. If the register name is specified as the second parameter, its value will be displayed in decimal format immediately after the string. The macro is universal and saves the main registers, which means it is not optimal in terms of speed and memory. But it saves you from many headaches and can be used when debugging together with the macro “pause” (see the appendix). Which waits for any key to be pressed; if Esc is pressed, it performs a cold restart of the system (i.e., exits the current program), and for any other key, it continues the program execution. The macro “pause” is not used in the current program, but it is very convenient for debugging, so I decided to provide it.

Now that we have verified that the file exists and opened it, we read the first sector from it. This is the file header. To read, we use the BDOS operation “20. Sequential reading”. As parameters, we pass the BUF of our file. The command looks like this “.bdos bdReadCon scr_buf”. After execution, the first 128 bytes of the file will be at the address “PDP_SCR”.

We will conduct a simplified analysis of the title. The text of the program with detailed comments is given at the end of the article, here I will simply describe the order and logic of actions.

First, we check the horizontal file size (in pixels) (word +0 from the beginning of the title) for equality to 512, i.e. the screen width. If they are not equal, we exit with an error message.

Next, we need to understand what file we are dealing with, for which we read byte +9 “File standardization flag”. If it contains the value 19 (#13), then the file contains the palette and we need to install it.

After that, we read byte +4 “BPP – number of dots in a byte”, if there are 8 here, then the file is black and white, if 4, then it is color 16 colors. At the same time, in the variable “FColor” we save the color of the file: 0 – no color; 1 – standard colors; 2 – palette 16 of 256 colors. This will be useful later.

Now we turn off the clock display on the screen so that it does not spoil our image. To do this, we will use the macro “.timeOFF” (see the appendix). Before exiting the program, you will need to use the macro “.timeON” (see the appendix) to return the clock to the screen.

Now with the command “ld de, 0207h or 08D8h; call 0f82dH” we turn on the screen in the lower 64 kb, graphics with #8000, color with #4000.

We read the second sector from the file, the subroutines for transferring data to the screen require that the beginning of the data be loaded before entering them.

To speed up the output, we use a table of addresses of the beginnings of lines by character cells. This will eliminate calculations when moving between character cells. In the register pair IX, we enter the beginning of the table.

We enter the beginning of the direct access buffer to the DMA memory into the HL register pair. And we enter the number of character cells to be output into the B register, in this case 30.

The installation work is finished. Let's proceed to the direct output of the image. For this we analyze the variable “FColor”, if it is 0, then we output a black and white image, otherwise a color one.

The color and black-and-white images will be output by different subroutines. This will allow the code to be optimized for speed by refusing to check a number of conditions. Let's first analyze the black-and-white output.

The output itself occurs within three nested cycles: by character cells, by pixel lines in a character cell, horizontally.

At the beginning of the cycle “by character place” in the register pair DE, we enter the address of the first pixel line in the character place from the table. The transition by lines within the character place will occur by increasing the contents of the register D by one.

The screen width is 64 bytes, which means that 2 lines fit in one sector. We enter the number 2 into register C as a counter of lines in the sector.

In the “horizontal” cycle, in one iteration we process two adjacent bytes on two half-screens, respectively, we set the number of cycle iterations equal to 32. We transfer the first byte through the A register “ld a, (hl); inc hl; ld (de), a”. Then we go to the second half-screen “res 5, d” and transfer the second byte, return to the first half-screen and shift to the character place “set 5, d; inc e”.

At the end of the “horizontal” cycle, we decrease the counter of the number of lines in the sector by 1. If we have reached zero, we load a new sector, enter 2 into the counter of the number of lines, and the beginning of the PDP buffer into the register pair HL. Here we need to control the return of the read operation to the end of the file. If the file suddenly ends, we exit the subroutine.

That's it! Once all the cycles are finished, the picture will be on the screen. You will need to wait for any button to be pressed, then turn on the watch and exit the program.

The difference in loading a color image is not significant. Now our pixel line has doubled to 128 bytes, that is, to a whole sector, which means we do not need a line counter. The information in the file alternates between a graphics byte and a color byte. After transferring the graphics byte, we move to color “ld a, 11000000B; xor d; ld d, a” and similarly transfer the color byte, after which we return to graphics in the same way.

Before exiting the program, if you displayed a picture with a palette, then restore the standard palette.

If anyone has any questions, they can always contact one of the following addresses.

And there is a lot of interesting stuff on the forum, in the VK group, and everything new will be posted there as well.

Follow this link (https://yadi.sk/d/GCBtRwywJSSmpw or https://vk.com/doc359059980_525959959) you can download the lzh archive, which contains:

  • m80.com, l80.com – main files of the m80 package.

  • LOADGRF.ASM – sources of the code described in this article.

  • BIOSK.INC – file for loading used macros.

  • LOADGRF.BAT – command files for assembling the example.

  • LOADGRF.COM – already assembled code, ready to run. Run from the command line with the first argument being the name of the GRF file to be output to the screen.

  • A set of black and white and color GRF files for testing.

Follow this link (https://yadi.sk/d/105vTeEIqrfbVA or https://vk.com/doc359059980_526413291) you can download a disk image in the “pro” format (working with it is similar to working with disk images in the “trd” format) with the described files. The disk image is bootable, so you can boot from it. On IBM PC, the most popular two emulators that can emulate Profi are ZXMAK2 (https://archive.codeplex.com/?p=zxmak2) and Unreal Speccy (https://sourceforge.net/projects/unrealspeccy/). Unreal Speccy has more features, but the settings are more complicated, while ZXMAK2 will do all the settings itself.

Unfortunately, both emulators currently display colors of the extended Profi palette with an error, which affects the quality of the picture. Although the situation is unpleasant, it is not critical. For now, I can only advise using real hardware to get the best result.


Below is the main text of the program located in the file “LOADGRF.ASM”.

          .Z80
          .RADIX 10
;-----------------------------------------------------------

          INCLUDE BIOSK.INC    ; Загрузка макросов.
;----------------------------------------------------------------

scr_buf   EQU 005CH            ;Блок управления файлом (БУФ).
BIOS      EQU 0F800H
GETADR    EQU BIOS+36H
SETCMRS   EQU BIOS+2DH
; Таблицы
TIME      EQU 7
;----------------------------------------------------------------

;Загружаем картинку.
          .bdos bdPDPInst, PDP_SCR ; установили буфер ПДП на нужный адрес
          .bdos bdOpen,    scr_buf
          inc a                ; if a<>255
          jp nz, grf.Title.ok  ; then
          ; else Если на диске нет такого файла
             say ' <!> Нет такого файла <!>'
             .bdos bdExit      ; <!> Выход <!>
grf.Title.ok:
          ;читаем заголовок
          .bdos bdReadCon scr_buf
          ld hl, (PDP_SCR+00)  ; HSize горизонтальный размер
          ld bc, 512           ;; if FHSize=512
          and a                ;;
          sbc hl, bc           ;;
          jr z, grf.Title.1    ;; then
          ;else
             say ' <!> Горизонтальный размер картинки не 512 пикселей <!>'
             .bdos bdExit      ; <!> Выход <!>
grf.Title.1:
          ld a, (pdp_scr+09)   ; признак стандартного файла
          and a                ; if a=0 проверка файла на стандартность
          jr z, grf.Title.std  ; then
          ;else файл не стандартный =19 - палитра 256; иное - ошибка.
             ld a, 02
             ld (FColor), a    ; палитра 256
             ld hl, pdp_scr+10 ; адрес палитры
             call PRGPAL       ; перенос палитры
          jp grf.Title.2
grf.Title.std:  ;файл стандартный
          ld a, (pdp_scr+04)   ; BPP бит на точку или точек в байте
          cp 8                 ; if BPP=8
          jr z,grf.Title.2     ; then картинка чб
          ld a, 01             ; else
          ld (FColor), a       ; BPP=04 стандартные цвета
grf.Title.2:

          .timeOFF             ; убрали часы
          ld de, 0207h or 08D8h ;; включили экран. Графика с #8000, цвет с #4000
          call 0f82dH           ;;

          .bdos bdReadCon, scr_buf ; первый сектор изображения
          ld ix, AdrZNgr       ; таблица адресов знакомест
          ld hl, pdp_scr       ; hl=адрес начала ПДП
          ld b, 30             ; число выводимых знакомест
          di
             ld a, (FColor)    ; a=наличие цвета (0 - чб, 1-стандартные цвета, 2-палитра)
             and a             ;; if a=0
             jp z, grf.chb     ;; then выводим чб картинку
             jp    grf.color   ;; else выводим цветную картинку
grf.endscr:
          ei
grf.pause:
             ld d, 0
             call 0F806H
          cp 0
          jp z, grf.pause
          ld d, 0
          call 0F809H
          .timeON              ; включили часы
          ld a, (FColor)       ; a=наличие цвета (0 - чб, 1-стандартные цвета, 2-палитра)
          ld hl, 0             ; стандартная палитра
          cp 2                 ;; if a=2
          call z, PRGPAL       ;; then устанавливаем стандартную палитру
          .bdos bdExit         ; <!> Выход <!>
;----------------------------------------------------------------------

grf.chb:
;Выводим черно-белую картинку шириною 512 пикселей.
;Портит регистры: hl, bc, de, af, ix, c'
;На входе:
;b  - число выводимых знакомест.
;ix - ссылка в таблице адресов знакомест со смещением на первое выводимое знакоместо.
;hl - адрес начала выводимого фрагмента в ПДП. Первый сектор должен быть уже загружен.
;c' - контроль выхода за переделы ПДП.

grf.chb.zn:                    ; цикл по знакоместам
          push bc
             ld e, (ix+0)      ;; de=адрес начала знакоместа
             ld d, (ix+1)      ;;
             inc ix            ; ix=ix+2 смещаем на следующее знакоместо
             inc ix            ;
             ld b, 8           ; число строк в знакоместе
             ld c, 2
grf.chb.x:                     ; цикл по пиксельным линиям в знакоместе
             .push <de, bc>
                ld b, 32       ; размер полуэкрана
grf.chb.y:                     ; цикл по выводимой ширине экрана
                   ;первый байт
                   ld a, (hl)  ; графика
                   inc hl
                   ld (de), a
                   res 5, d    ;; переходим на следующее знакоместо. выключили бит
                   ;второй байт
                   ld a, (hl)  ; графика
                   inc hl
                   ld (de), a
                   set 5, d    ;; переходим на следующее знакоместо. включили бит
                   inc e       ;;
                djnz grf.chb.y ; цикл по горизонтали
             pop bc
             dec c             ; c=c-1; if c=0
             jr nz, grf.chb.1  ; then
                push bc        ; else
                   .bdos bdReadCon, scr_buf ; последовательное чтение
                pop bc
                ld hl, pdp_scr ; начало ПДП
                ld c, 2
                and a            ; if a=0
                jr z, grf.chb.1  ; then операция завершена без ошибки.
                   .pop <de, bc> ; else
                   jp grf.endscr ; <!> Выход по ошибки
grf.chb.1:
             pop de
             inc d             ; опускаемся на следующую пиксельную линию в знакоместе
             djnz grf.chb.x    ; цикл по линиям
          pop bc
          djnz grf.chb.zn      ; цикл по знакоместам
       jp grf.endscr           ; <!> Выход <!>
;----------------------------------------------------------------------

grf.color:
;Выводим цветную картинку шириною 512 пикселей.
;Портит регистры: hl, bc, de, af, ix, c'
;На входе:
;b  - число выводимых знакомест.
;ix - ссылка в таблице адресов знакомест со смещением на первое выводимое знакоместо.
;hl - адрес начала выводимого фрагмента в ПДП. Первый сектор должен быть уже загружен.
;c' - контроль выхода за переделы ПДП.

grf.color.zn:                  ; цикл по знакоместам
          push bc
             ld e, (ix+0)      ;; de=адрес начала знакоместа
             ld d, (ix+1)      ;;
             inc ix            ; ix=ix+2 смещаем на следующее знакоместо
             inc ix            ;
             ld b, 8           ; число строк в знакоместе
grf.color.x:                   ; цикл по пиксельным линиям в знакоместе
             .push <bc, de>
                ld b, 32       ; размер полуэкрана
grf.color.y:                   ; цикл по выводимой ширине экрана
                   ;первый байт
                   ld a, (hl)      ; графика
                   inc hl
                   ld (de), a
                   ld a, 11000000B ; переходим на цвет
                   xor d           ;
                   ld d, a         ;
                      ld a, (hl)   ;; цвет
                      inc hl
                      ld (de), a
                   ld a, 11000000B ; переходим на графику
                   xor d           ;
                   ld d, a         ;
                   res 5, d        ;; переходим на следующее знакоместо. выключили бит
                   ;второй байт
                   ld a, (hl)      ; графика
                   inc hl
                   ld (de), a
                   ld a, 11000000B ; переходим на цвет
                   xor d           ;
                   ld d, a         ;
                      ld a, (hl)   ;; цвет
                      inc hl
                      ld (de), a
                   ld a, 11000000B ; переходим на графику
                   xor d           ;
                   ld d, a         ;
                   set 5, d        ;; переходим на следующее знакоместо. включили бит
                   inc e           ;;
                djnz grf.color.y   ;  цикл по горизонтали
                .bdos bdReadCon, scr_buf ; последовательное чтение
                ld hl, pdp_scr      ; начало ПДП
                and a               ; if a=0
                jr z, grf.color.end ; then операция завершена без ошибки.
                   .pop <de, bc, bc> ; else
                   jp grf.endscr    ; <!> Выход по ошибки
grf.color.end:
             .pop <de, bc>
             inc d                  ; опускаемся на следующую пиксельную линию в знакоместе
             djnz grf.color.x       ; цикл по линиям
          pop bc
          djnz grf.color.zn         ; цикл по знакоместам
       jp grf.endscr                ; <!> Выход <!>
;----------------------------------------------------------------------

;Программирование палитры.
;На входе: hl  - адрес новой палитры или 0 для установки стандартной [0].
;
;Портит: всё.

PRGPAL:
      di
         push hl
            ld c, TIME        ;; C=номер таблицы. 7 - TIME вектор TIK,SEC,MIN,HOUR, DAY,MONTH,YEAR-1980. Кроме того , со смещением -1 лежит BORD
            call getadr       ;; Получаем адрес таблицы
            dec hl            ;; смещением -1 на BORD
            ld a, (hl)        ;;
            ld (?BORD), a     ;; Что бы не расчитывать в цикле
            ld c, 0           ; C=номер таблицы. 0
            call getadr       ; Получаем адрес таблицы
            ld a, (hl)        ;
            ld e, a           ;
            inc hl            ;
            ld a, (hl)        ;
            ld d, a           ;
         pop hl
         push de
            push hl
               set 5, d
               call SETCMRS
            pop hl
            ld a, h           ; if hl<>0
            or l              ;
            jr nz, PRGPAL.P1  ; then
            ld hl, Palette.Std; else
PRGPAL.P1:
            push hl
               ld hl, (38h)
               ex (sp), hl    ; отправили на стек содержимое 38h в hl=hl с входа
               ld de, 0c9fbh  ; ei ret
               ld (38h), de
               ei
                  halt
               di
;порт палитры 7E, до выдачи данных в рег бордера задаем инверсный код номера ячейки 00..0F
;значение цвета задается в битах A15-A8 при выполнении записи в порт 7E,
;командой out (c),e
;а выводимое значение (E) запишется в порт BORDER для следующего цикла

; hl содержит адрес данных палитры
               ld a, (?BORD)
               or 0Fh         ; в А бит звука и код 0F для цвета (ячейка 0)
               ld e, a
               ld c, 7Eh      ; порт записи для данных палитры
               ld d, 16       ; всего 16 ячеек
               out (c), e     ; сейчас вывели в BORDER значение 0Fh
;конечно, произошло и программирование палитры той ячейки, какой BORDER был до этого, скорее всего
;BORD был равен 7, а это номер ячейки 8 (7 xor 0F) но так как потом мы зальём все 16 ячеек это не страшно
               dec e
PRGPAL.prg2:
                  ld a, (hl)  ; значение цвета 8 бит
                  cpl         ; инверитруем (так надо по схеме компа)
                  ld b, a
                  out (c), e  ; задали цвет и номер бордер для следующей ячейки
                  inc hl
                  dec e       ; следующий цвет
                  dec d
               jr nz, PRGPAL.prg2

               ld a, (?BORD)  ; восстановили BORDER
               out (0feh), a
            pop hl
            ld (38h), hl
         pop de
         call SETCMRS
         rst 38h
      ei
      ret
;----------------------------------------------------------------------

Palette.Std:
        DB      0            ; BLACK
        DB      00000010B
        DB      00010000B
        DB      00010010B
        DB      10000000B
        DB      10000010B
        DB      10010000B
        DB      10010010B    ; WHITE

        DB      0            ; gray
        DB      00000011B
        DB      00011000B
        DB      00011011B
        DB      11000000B
        DB      11000011B
        DB      11011000B
        DB      11011011B    ; WHITE (BRIGHT 1)
;----------------------------------------------------------------------

AdrZNgr:   ; Таблица адресов начала знакомест
          dw 0A000H, 0A020H, 0A040H, 0A060H, 0A080H, 0A0A0H, 0A0C0H, 0A0E0H
          dw 0A800H, 0A820H, 0A840H, 0A860H, 0A880H, 0A8A0H, 0A8C0H, 0A8E0H
          dw 0B000H, 0B020H, 0B040H, 0B060H, 0B080H, 0B0A0H, 0B0C0H, 0B0E0H
          dw 0B800H, 0B820H, 0B840H, 0B860H, 0B880H, 0B8A0H
AdrZNgr_end:
;----------------------------------------------------------------

;Информация о загружаемой картинке
FColor:   db 00      ;Наличие цвета. 0-нет;
                     ;grf 1-стандартные цвета; 2-палитра
FPallet:  ds 16      ;Палитра файла.

PDP_SCR:  ds 128
E_PDP_SCR:
          END

Appendix. Macros Used

.bdos     macro com, par
;Вызов операции BDOS.
;com  - код операции
;par  - параметр для передачи

             ifnb <par>
                ld de, par
             endif
             ld c, com
             call 0005h
          endm
;-----------------------------------------------------------

say       macro STR, REG
;Вывод строки на экран.
;Все регистры сохраняются.
;STR - строка для вывода. 
;REG - имя регистра (a, sp, hl, de, bc, ix, iy) для вывода в десятичном виде. []
;Сохраняет: af, hl, bc, de

             local BUFF, B_END
             ifnb <str>
                .push <af, hl, de, bc>
                .bdos bdWrite, buff
                jr B_END
BUFF:           db STR, '$'
B_END:
                .pop <bc, de, hl, af>
             endif
             ifnb <reg>
                .push <af, hl, de, bc>
                   .writed REG
                .pop <bc, de, hl, af>
             endif
          endm
;-----------------------------------------------------------

pause     macro
;Макрос ожидания нажатия любой клавиши.
;Если нажатие ECS – сброс системы, выход из текущей программы.
;Сохраняет: af, hl, bc, de

             local p0
             .push <af, hl, bc, de>
p0:             ld d, 0
                call 0F806H
                cp 0
                jp z, p0
                ld d, 0
                call 0F809H

                .pop <de, bc, hl>
                cp 1bh                ;ESC
                jp z, 0
             pop af
          endm
;-------------------------------------------------------------

.writed  macro REG, IND
;Операция 50/243.
;Вывод в десятичном формате.
;Если на входе:
;ING=0 печатаются регистры A,SP,HL,DE,BC,IX,IY. По умолчанию.
;ING=1 печатаются целые числа.
;Портит все регистры.

           local BUFF1
           if IND                    ;IND<>0
              ld de, REG             ;Передали цифру
              ld (BUFF1+1), DE
           else
              ld (BUFF1+1), REG      ;Передали регистр
           endif
           .bdos bdBSVV, buff1
           jr BUFF1+3
BUFF1:     db 0F3H
           dw 0000
        endm
;-----------------------------------------------------------

.timeOFF  macro
;Отключения вывода таймера.
;Используется процедуры BIOS'а. Для драйвера TIME2.DRV

            ld c,80H
            ld d,1BH
            call 0F80CH
            or 080H
            ld c,a
            ld d,01BH
            call 0F80CH
          endm
;-----------------------------------------------------------

.timeON   macro
;Включение вывода таймера.
;Используется процедуры BIOS'а. Для драйвера TIME2.DRV

            ld c,80H
            ld d,1BH
            call 0F80CH
            and 07FH
            ld c,a
            ld d,01BH
            call
          endm
;-----------------------------------------------------------

.Pop   Macro   Items
; (c) PSWsoft

          Irp x,<Items>
             POP x
          Endm
       EndM
;-----------------------------------------------------------

.Push  Macro   Items
; (c) PSWsoft

          Irp x,<Items>
             PUSH x
          Endm
       EndM

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *