sábado, 29 de setembro de 2012

Beta Boot Menu 4.0

O disco AY Demos v. 9 contém uma nova versão do programa de menu que desenvolvi, o Beta Boot Menu 4.0.



Este sistema é um interpretador de linhas de comandos que, a partir dos dados armazenados a partir do endereço 50000 da RAM, constrói menus controlados pelo teclado ou joystick. Os comandos para especificar um menu podem ser digitados num PC com um editor de textos plano, desde que o arquivo seja salvo em codificação ISO 8851-1 (Latin-1). Depois este arquivo pode ser inserido na RAM do TK90X emulado através de carregamento de arquivo binário (no Fuse, use a opção do menu File > Load binary data...). Futuramente irei escrever com detalhes os comandos disponíveis.

O programa foi feito nas linguagens BASIC e assembly. A listagem BASIC é:
  10 CLEAR 65367
  20 LET dos=15363: IF PEEK dos<>195 THEN LET dos=15619
  30 RANDOMIZE USR dos: REM : LOAD "BOOT"CODE
  40 RANDOMIZE USR dos: REM : LOAD "MENUDATA"CODE 5E4
 100 LET lm=62000
 200 LET arg=USR lm
 210 LET lm=62003
 220 LET c$=CHR$ PEEK arg
 230 LET a$="": FOR n=1 TO 8: LET a$=a$+CHR$ PEEK (arg+n): NEXT n
1000 IF c$="O" OR c$="o" THEN RANDOMIZE USR (dos-3)
2000 IF c$<>"D" AND c$<>"d" THEN GO TO 3000
2010 RANDOMIZE USR dos: REM : CAT
2020 GO TO 9000
3000 IF c$<>"R" AND c$<>"r" THEN GO TO 4000
3010 POKE 23693,56: BORDER 7: CLS : RANDOMIZE USR dos: REM : LOAD a$
3020 GO TO 4020
4000 IF c$<>"G" OR c$<>"g" THEN GO TO 5000
4010 RANDOMIZE USR dos: REM : GO TO a$CODE
4020 BEEP 1,5: GO TO 9000
5000 IF c$<>"V" AND c$<>"v" THEN GO TO 200
5010 RANDOMIZE USR dos: REM : LOAD a$CODE 16384
9000 LET lm=62006: GO TO 200

e a listagem assembly:

;                Beta Boot Menu v. 4.0
;                =====================
;
;File: BootMenu4.0.asm
;Version: 4.0 - Sep/23/2012
;Author: Flávio
;        reikainosuke-tk@yahoo.com.br, http://cantinhotk90x.blogspot.com.br
;
;Description:
; Auto-executable program (boot) for Beta disk drive interface.
;
;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;    (at your option) any later version.
;
;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.
;
;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.
;
; Headers
;=========
            INCLUDE "Header_Basic.asm"
            INCLUDE "Header_Print.asm"
            INCLUDE "Header_Joystick.asm"
;
; Constants
;===========
; ROM routines.
PRINT_OUT:  EQU 2548
_PO_FETCH:  EQU 2819
_PO_ABLE:   EQU 2777
BEEPER:     EQU 949
;
; Entry Points
;=============
            ORG 62000
            JP Begin            ; Jump to beginning of the program, executed
                                ;only at first time.
            JP Entry2           ; Second entry point (62003) used to return
                                ;from BASIC.
            JP Entry3           ; Third entry point (62006), like Entry2 but
                                ;wait for user action on joystick/keyboard.
; Variables
;===========
;62009
MenuData:   DEFW 50000          ; Address of menu data (thus, address of first
                                ;menu too).
;620011
T_CHARS:    DEFW Latin1-256     ; PrLatin1: address of secondary
                                ;char set.
;62013
LastMenu:   DEFS 2              ; Address of last menu.
;62015
NumMenu:    DEFS 1              ; Number of menus.
;62016
CurMenu:    DEFS 1              ; Current menu number.
;62017
CurMAdd:    DEFS 2              ; Current menu address.
;62019
NumOpts:    DEFS 1              ; Number of options in a menu.
;62020
CurOpt:     DEFS 1              ; Current option.
;62021
            DEFB 0              ; Scroller: variable no longer in use.
;62022
PixCount:   DEFB 8              ; Scroller: counter, 8 pixels to be rotated.
;62023
Title:      DEFS 2              ; Pointer for the title string.
;62025
STitle:     DEFS 2              ; Pointer for the subtitle string.
;62027
OldErrsp:   DEFS 2              ; PrLatin1: temporary place to save ERR_SP.
;62029
KempWait:   DEFB 6              ; Number of repetitions before testing Kempston
                                ;joystick again.
;62030
KempCount:  DEFB 6              ; Counter.
;62031
JKAction:   DEFS 1              ; ReadJK: result of joystick/keyborad reading.
MsgIni:     DEFW Logo           ; Scroller: start of scroll message.
MsgPtr:     DEFW Logo           ; Scroller: pointer for scroll message.
;
; Main program
;==============
Entry3:
            HALT                ; Wait.
            CALL ReadJK         ; Read joystick/keyboard.
            LD A,(HL)           ; While user did not take any action
            AND 000111
            JR Z,Entry3         ;repeat this loop.
            JR Entry2           ; Jump to Entry2.
Begin:
; Define variables for the scroller. Only the first M command found will be
;considered.
            LD HL,(MenuData)    ; Seek inside MenuData.
GetScrMsg:
            CALL StrLen         ; Get a line.
            LD A,(DE)           ; A=Command.
            RES 5,A             ; Convert to upper case.
            JR Z,InitMenus      ; If end of data, jump forward.
            CP "E"
            JR Z,InitMenus
            CP "M"              ; If it's not M command, jump backward to
            JR NZ,GetScrMsg     ;analise next line.
            INC DE              ; Skip first character of the line.
            LD (MsgIni),DE      ; Define variables for the scroller.
            LD (MsgPtr),DE
            LD HL,ScrBuffer     ; Clear buffer used by scroller.
            LD B,0              ; Count 256 bytes.
ClrScrBuff:
            LD (HL),0
            INC HL
            DJNZ ClrScrBuff
InitMenus:
            XOR A               ; Number of menus=0.
            LD (NumMenu),A
            INC A               ; Current menu=1.
            LD (CurMenu),A
            LD HL,(MenuData)    ; HL points to first menu.
InitMenu1:
            CALL ScanMenu       ; Get menu data.
            EX AF,AF'           ; Save CARRY flag.
            LD A,(NumOpts)      ; Jump forward if menu is empty.
            AND A
            JR Z,InitMenu2
            LD (LastMenu),HL    ; Menu pointer is stored in LastMenu and the
            LD A,(NumMenu)      ;menu counter is incremented.
            INC A
            LD (NumMenu),A
InitMenu2:
            EX AF,AF'           ; Restore CARRY flag.
            JR NC,InitMenu1     ; While end of data was not found,repeat for the
                                ;next line.
; Main loop.
Main:
            LD HL,(MenuData)    ; HL points to the first menu.
            LD A,(CurMenu)      ; Get value of counter for menus.
SeekMenu:
            PUSH AF
            LD (CurMAdd),HL     ; Store current menu address.
            CALL ScanMenu       ; Get menu data.
            POP AF
            DEC A               ; Decrement menu counter.
            JR NZ,SeekMenu      ; Repeat until menu is found.
Entry2:
            CALL PrMenu         ; Print current menu at screen.
            LD A,1              ; Initialize current option to first option.
            LD (CurOpt),A
Main1:
            CALL SetCursor      ; Put cursor on screen.
Main2:
            CALL WaitJK         ; Wait for user action and update scroll.
            BIT 0,(HL)          ; If 'down' command was not activated then
            JR Z,Main3          ;jump forward
            CALL SetCursor      ;else remove cursor from screen.
            LD HL,CurOpt        ; HL will points to current option variable.
            INC (HL)            ; Increment current option value.
            LD A,(NumOpts)      ; If NumOpts+1<=CurOpt (there are NumOpts
            INC A               ;options plus "Menu anterior" and
            CP (HL)             ;"Menu seguinte")
            JR NC,Main1         ;then jump back to the loop
            LD (HL),0           ;else reset the CurOpt.
            JR Main1            ; Jump back to the loop.
Main3:
            BIT 1,(HL)          ; If 'up' command was not activated then
            JR Z,Main4          ;jump forward
            CALL SetCursor      ;else remove cursor from screen.
            LD HL,CurOpt        ; HL will points to current option variable.
            DEC (HL)            ; Decrement current option value.
            JP P,Main1          ; If CurOpt>=0 then jump back to the loop
            LD A,(NumOpts)      ;else CurOpt=NumOpts+1 ("Menu seguinte").
            INC A
            LD (HL),A
            JR Main1            ; Jump back to the loop.
Main4:
            BIT 2,(HL)          ; If fire button wasn't pressed
            JR Z,Main2          ;jump back to the loop.
            LD HL,CurMenu
            LD A,(CurOpt)       ; If CurOpt<>0 (not option 'Menu anterior') then
            OR A
            JR NZ,Main5         ;jump forward
            DEC (HL)            ;else decrement current menu number.
            JR NZ,Main          ; If first menu was passed
            LD A,(NumMenu)      ;then jump to last menu.
            LD (HL),A
            JR Main
Main5:
            PUSH HL
            LD HL,NumOpts       ; If CurOpt>NumOpts (not option 'Menu seguinte')
            DEC A
            CP (HL)
            POP HL
            JR C,Main6          ;then jump forward
            INC (HL)            ;else increment current menu number.
            LD A,(NumMenu)      ; If NumMenu>=CurMenu
            CP (HL)
            JR NC,Main          ;then repeat the loop
            LD (HL),1           ;else CurMenu=1.
            JR Main             ; Repeat the loop.
Main6:
            INC A               ; Restore CurOpt value and
            LD B,A              ;store in B (counter).
            LD HL,(CurMAdd)     ; HL points to current menu data.
Main7:
            PUSH BC             ; Save counter.
Main8:
            CALL StrLen         ; Advance to next command line.
            EX DE,HL            ; HL=address of previous command line.
            CALL TestOpt        ; Test if command is a menu option.
            EX DE,HL            ; HL=address of next command line.
            JR NZ,Main8         ; Repeat until menu option is found.
            POP BC              ; Restore counter.
            DJNZ Main7          ; Repeat until desired option is found.
            LD A,(DE)           ; A=command.
            RES 5,A             ; Convert to upper case letter.
            CP "L"              ; If command is 'Line', jump back to the loop,
            JR Z,Main2          ;since it has to do nothing.
            LD C,E              ; BC points to beginning of command line. This
            LD B,D              ;value is passed for the BASIC after returning.
            CP "N"              ; If command isn't 'New' then return to BASIC.
            RET NZ
            CALL ROM_CLS        ; Create new menu to check if the user really
            LD A,2              ;want to reset the computer. First screen is
            CALL CHAN_OPEN      ;cleared and "S" channel is opened.
            LD A,Pr_At          ; <PRINT AT 16,10;>;
            RST 16
            LD A,10
            RST 16
            XOR A
            RST 16
            LD HL,NoMsg         ; Print the option "not erase RAM".
            CALL PrCStr
            LD HL,YesMsg        ; Print the option "yes, erase RAM".
            CALL PrCStr
New1:
            CALL NewCurNo       ; Put the cursor on first option.
New2:
            CALL WaitJK         ; Wait for user action and update scroll.
            BIT 2,(HL)          ; If fire button was pressed at first option
            JP NZ,Main          ;then return to main loop
            BIT 0,(HL)          ;else if user didn't select 'down'
            JR Z,New2           ;then repeat the loop
            CALL NewCurNo       ;else remove cursor, put it at 11,0 and
            CALL NewCurYes      ;highlight second option.
New3:
            CALL WaitJK         ; Wait for user action and update scroll.
            BIT 1,(HL)          ; Test if user input is 'up'
            PUSH AF             ;and save the result.
            CALL NZ,NewCurYes   ; If user requested 'up' then remove cursor
            POP AF
            JR NZ,New1          ;and jump to first option.
            BIT 2,(HL)          ; If fire button wasn't pressed
            JR Z,New3           ;then repeat the loop
            RST 0               ;else reset computer.
;
NewCurNo:
            LD HL,22848         ; Put cursor at 10,0;
            JR NewCurNo1
NewCurYes:
            LD HL,22880         ; Put cursor at 11,0;
NewCurNo1:
            JP SetCurHL
;
NoMsg:
            DEFM "Não quero apagar a RAM."
            DEFB 0
YesMsg:
            DEFM "Sim, limpe a RAM."
            DEFB 0
;
; Sub-routines
;==============
; Wait Joystick/Keyboard (WaitJK)
;---------------------------------
; Description: WaitJK waits for any user intervention on joystick or keyboard.
;To prevent rapid repetitions, it waits until all controls are freed or the time
;is up. Scroll message is updated during sub-routine execution.
WaitJK:
            LD B,15             ; Initialize time up counter.
WaitJK1:
            PUSH BC             ; Save counter.
            CALL Scroller       ; Print scroll message.
            CALL ReadJK         ; Read joystick and keyboard.
            HALT                ; Pause.
            POP BC              ; Restore counter.
            DEC B               ; Decrement counter and jump forward if
            JR Z,WaitJK2        ;time is up.
            LD A,(HL)           ; If joystick or keyboard is activated then
            AND 000111
            JR NZ,WaitJK1       ;wait until it is released.
WaitJK2:
            CALL ReadJK         ; Read joystick and keyboard again.
            PUSH HL
            LD A,(HL)
            AND 000111
            LD HL,156           ; Play a tone in the beeper output.
            LD DE,46
            CALL NZ,BEEPER
            POP HL
            RET
;
; String Lenght (StrLen)
;------------------------
; Description: get length of a string terminated by one or two characters which
;codes are less than space (" ", 32 or #20). This routine can interpret text
;files from many modern operating systems.
; Input:  HL=start of string
; Output: DE=start of string, HL=next address after string, BC=length, A=31
;
StrLen:
            LD D,H              ; DE=address of string.
            LD E,L
            LD A,31             ; A=" "-1.
StrLen1:
            CP (HL)            
            INC HL              ; Increments pointer.
            JR C,StrLen1        ; If A<(HL) then jump to test next byte,
            CP (HL)             ;else verify next byte.
            JR C,StrLen2        ; If A<(HL) then jump forward,
            INC HL              ;else increments pointer again.
StrLen2:
            AND A               ; BC=HL-DE,
            SBC HL,DE           ;the result is string length.
            LD B,H
            LD C,L
            ADD HL,DE           ; Recover HL (next address after string).
            RET                 ; End.
;
; CaseA
;-------
; Description: implementation of CASE structure presents in high level
;languages. A is a character to be found in a table pointed by HL. The table 
;consists in 3 bytes elements, which first byte represents a character and the
;next 2 bytes an address to jump to. The end of the table is marked by 0.
; Input: A=character to be found, HL=address of the table.
CaseA:
            LD C,A              ; Store character to be searched.
CaseA1: 
            LD A,(HL)           ; Get character from the table.
            AND A               ; If it's 0, return.
            RET Z
            INC HL              ; Get address from the table and put into DE.
            LD E,(HL)
            INC HL
            LD D,(HL)
            INC HL              ; HL points to next table element.
            CP C                ; If the character was not found
            JR NZ,CaseA1        ;jump to try next table element.
            EX DE,HL            ; Otherwise, jump to the specified address.
            JP (HL)
;
; ScanMenu
;------------------
; Description: scan data of a menu and return its number of options. The commands
;Title, Subtitle, Paper, Ink, Border, borderinK are processed and the relevant
;variables are properly attributed.
; Input: HL=address of the menu
; Output: (NumOpts)=number of options of the menu, CARRY is set when HL reaches
;end of MenuData.
; AF, BC, DE, HL and IX are destroyed.
ScanMenu:
            XOR A               ; NumOpts=0
            LD (NumOpts),A
ScanMenu1:
            CALL StrLen         ; Get a line from menu data.
            LD A,(DE)           ; A=command.
            RES 5,A             ; Convert to upper case.
            PUSH AF             ; Save registers.
            PUSH HL
            INC DE              ; IX-1 points to start of command line and IX,
            PUSH DE             ;to the first byte of its argument.
            POP IX
            LD HL,ScanMTab      ; Table with commands and their addresses.
            CALL CaseA          ; Search for the command and execute it.
            POP HL              ; Restore registers.
            POP AF
            CP "C"              ; Repeat until command is 'Close' or
            JR Z,ScanMenu2
            CP "E"              ;command is End or
            JR Z,ScanMenu3
            CP 32               ;command is invalid (less than 32) or
            JR C,ScanMenu3
            LD A,(NumOpts)
            CP 18               ;NumOpts=18.
            JR NZ,ScanMenu1
            LD A,"C"            ; If 18 options were found and
            CP (HL)             ;next command is 'Close'
            CALL StrLen         ;then skip next line.
ScanMenu2:  AND A               ; CARRY=0 indicates that there are more lines
            RET                 ;in menu data.
ScanMenu3:  SCF                 ; CARRY=1 indicates end of menu data.
            RET
ScanMTab:
            DEFB "T"            ; Title.
            DEFW ScanMenuT
            DEFB "S"            ; Subtitle.
            DEFW ScanMenuS
            DEFB "P"            ; Paper.
            DEFW ScanMenuP
            DEFB "I"            ; Ink.
            DEFW ScanMenuI
            DEFB "B"            ; Border.
            DEFW ScanMenuB
            DEFB "K"            ; borderinK.
            DEFW ScanMenuK
            DEFB "R"            ; Run.
            DEFW ScanMInc
            DEFB "G"            ; Goto.
            DEFW ScanMInc
            DEFB "V"            ; View.
            DEFW ScanMInc
            DEFB "L"            ; Line.
            DEFW ScanMInc
            DEFB "D"            ; Dir.
            DEFW ScanMInc
            DEFB "N"            ; New.
            DEFW ScanMInc
            DEFB "O"            ; Out.
            DEFW ScanMInc
            DEFB 0              ; Table terminator.
ScanMenuT:
            LD (Title),IX       ; Title points to the string.
            RET
ScanMenuS:
            LD (STitle),IX      ; Title points to the string.
            RET
ScanMenuB:
            LD HL,BORDCR        ; Changes are applied to border attributes.
            JR ScanMenB1
ScanMenuP:
            LD HL,ATTR_P        ; Changes are applied to main screen attributes.
ScanMenB1:
            CALL ScanMColor     ; Get argument from command line.
            RLCA                ; Transfer to bits 3-5.
            RLCA
            RLCA
            LD B,A
            LD A,(HL)           ; Get current attributes.
            AND %11000111       ; Reset bits 3-5.
            OR B                ; Put color on the bits 3-5.
            LD (HL),A           ; Store the new attributes.
            RET                 ; End.
ScanMenuK:
            LD HL,BORDCR        ; Changes are applied to border attributes.
            JR ScanMenK1
ScanMenuI:
            LD HL,ATTR_P        ; Changes are applied to main screen attributes.
ScanMenK1:
            CALL ScanMColor     ; Get argument from command line.
            LD B,A
            LD A,(HL)           ; Get current attributes.
            AND %11111000       ; Reset bits 0-2.
            OR B                ; Put color on the bits 0-2.
            LD (HL),A           ; Store the new attributes.
            RET                 ; End.
           
ScanMColor:
            LD A,(IX+0)         ; Get argument from the command line.
            SUB "0"             ; Convert ASCII digit to number.
            AND 000111       ; Restrict range to 0-7.
            RET                 ; End.
ScanMInc:
            LD HL,NumOpts       ; Increment number of options of current menu.
            INC (HL)
            RET
;
; Print Menu (PrMenu)
;---------------------
; Description: PrMenu clears the screen and prints the titles and all current
;menu options.
; All registers are destroyed.
PrMenu:
            CALL ROM_CLS        ; Clear screen.
            LD A,2              ; Open "S" channel.
            CALL CHAN_OPEN
            LD A,(BORDCR)       ; Set same color attributes like border to
            LD (ATTR_T),A       ;print title and subtitle.
            AND 111000
            RRA
            RRA
            RRA
            OUT (254),A
            LD HL,(Title)
            CALL PrCStr
            LD HL,(STitle)
            CALL PrCStr
            LD A,(ATTR_P)       ; Restore main screen attributes.
            LD (ATTR_T),A
            LD A,Pr_At
            RST 16
            LD A,(NumOpts)      ; {PRINT AT 11-NumOpts/2,0;}
            SRL A
            NEG
            ADD 11
            RST 16
            XOR A
            RST 16
            LD A,Pr_Inverse     ; {INVERSE 1}
            RST 16
            LD A,1
            RST 16
            LD HL,PrMMsg1       ; Print "Menu anterior"
            CALL PrCStr
            LD A,Pr_Inverse     ; {INVERSE 0}
            RST 16
            XOR A
            RST 16
            LD HL,(CurMAdd)     ; HL is pointer of current menu.
            LD A,(NumOpts)      ; CurOpt is counter of menu options.
            LD (CurOpt),A
PrMenu1:
            CALL TestOpt        ; Test if the command is menu option and
            EX AF,AF'           ;save Flags.
            CALL StrLen         ; Advance to next command line.
            EX AF,AF'           ; Recover Flags and
            JR NZ,PrMenu1       ;jump backward if wasn't menu option.
            PUSH HL             ; Save address of next line.
            EX DE,HL            ; HL=DE+1, pointer for string to be printed.
            CALL PrOpt          ; Print option description.
            LD HL,CurOpt        ; Decrement counter of menu options.
            DEC (HL)
            POP HL              ; Recover address of next line.
            JR NZ,PrMenu1       ; Repeat until counter is 0.
            LD A,Pr_Inverse     ; {INVERSE 1}
            RST 16
            LD A,1
            RST 16
            LD HL,PrMMsg2       ; Print "Menu seguinte".
            CALL PrCStr
            LD A,Pr_Inverse     ; {INVERSE 0}
            RST 16
            XOR A
            RST 16
            RET                 ; End.
PrMMsg1:
            DEFM "<< Menu anterior <<"
            DEFB 0
PrMMsg2:
            DEFM ">> Menu seguinte >>"
            DEFB 0
;
; Print Option (PrOpt)
;----------------------
; Description: PrOpt prints a menu option description. The command letter and,
;for Run and View, the TR-DOS file name are skipped.
PrOpt:
            CALL TstOptFile
            JR NZ,PrOpt1
            LD BC,8
            ADD HL,BC
PrOpt1:     INC HL
            JP PrCStr
;
; Test Option with File name (TstOptFile)
;----------------------------------------
; Description: TstOptFile reads command line pointed by HL and tests if it
;represents a menu option with TR-DOS file name embedded in it (Run, Goto and
;View).
; Input: HL=address of the line
; Output: ZERO=1 if line is menu option; A=code of command.
TstOptFile:
            LD A,(HL)
            RES 5,A             ; Convert to upper case.
            JR TstOptF1
;
; TestOption (TestOpt)
;-----------------------------
; Description: TestOption reads command line pointed by HL and tests if it
;represents a menu option.
; Input: HL=address of the line
; Output: ZERO=1 if line is menu option; A=code of command.
TestOpt:
            LD A,(HL)
            RES 5,A             ; Convert to upper case.
            CP "L"              ; Line command.
            RET Z
            CP "D"              ; Dir command.
            RET Z
            CP "N"              ; New command.
            RET Z
            CP "O"              ; Out command.
            RET Z
TstOptF1:
            CP "R"              ; Run command.
            RET Z
            CP "G"              ; Goto command.
            RET Z
            CP "V"              ; View command.
            RET                 ; End.
;
; SetCursor
;-----------
SetCursor:
            LD A,(NumOpts)
            SRL A
            LD C,A
            LD A,(CurOpt)
            ADD A,11
            SUB A,C
            LD L,0
            RRCA
            RR L
            RRCA
            RR L
            RRCA
            RR L
            AND 000011
            OR %01011000
            LD H,A
SetCurHL:
            LD B,32          
SetCurs1:
            LD A,%11000000
            XOR (HL)
            LD (HL),A
            INC HL
            DJNZ SetCurs1
            RET
;
; Read Joystick and Keyboard (ReadJK)
;-------------------------------------
ReadJK:
            LD BC,0             ; BC initial value.
            LD HL,JKAction
            LD (HL),0
            LD A,(KempCount)    ; Test if Kempston was active.
            OR A
            JR Z,KempsOn        ; If active then jump forward
            DEC A               ;else decrement counter
KempsOff:
            LD (KempCount),A    ;for new trying.
            JR NoKempston       ; Jump to proceed without Kempston.
KempsOn:
            IN A,(KEMPS_PORT)   ; Read Kempston port and store in E.
            LD E,A
            AND %11100000       ; Test if Kempston is active.
            LD A,(KempWait)     ; Initialize KempCount.
            JR NZ,KempsOff      ; If Kempston if off, jump to reset KempCount.
            BIT 4,E             ; Test fire button.
            JR Z,KempNoF        ; If not pressed then jump ahead
            SET 2,(HL)          ;else set the fire button flag.
KempNoF:
            LD A,KEMPS_UP+KEMPS_RGHT
            AND E               ; If 'up' or 'right' was pressed then set the
            JR Z,KempNoUR       ;up flag, else jump forward.
            SET 1,(HL)
KempNoUR:
            LD A,KEMPS_DOWN+KEMPS_LEFT
            AND E               ; If 'down' or 'left' was pressed the set the
            JR Z,NoKempston     ;down flag, else jump forward.
            SET 0,(HL)
NoKempston:
            LD BC,$0FFE         ; Read all rows of 5 rightmost keys.
            IN E,(C)            ; E=XXXLRDUF (Left, Right, Down, Up, Fire).
            LD A,E
            RRCA                ; Now CARRY=F and A=FXXXLRDU.
            JR C,I2J1_NoF       ; If fire was not pressed then jump ahead
            SET 2,(HL)          ;else set the fire flag.
I2J1_NoF:
            OR %11111010        ; Test 'right' or 'up' bits. If both were set,
            INC A               ;incrementing A will be 0.
            JR Z,I2J1_NoRU      ; Then jump forward,
            SET 1,(HL)          ;else, set the up flag.
I2J1_NoRU:
            LD A,E
            OR %11101011        ; Test 'left' and 'down' bits. If both were set,
            INC A               ;incrementing A will be 0.
            JR Z,I2J2           ; Then jump forward,
            SET 0,(HL)          ;else set the down flag.
I2J2:
            LD B,%11110111      ; Read keys 1-5.
            IN E,(C)            ; A=XXXFUDRL.
            BIT 4,E             ; If 'fire' bit is high        
            JR NZ,I2J2_NoF      ;then jump forward,
            SET 2,(HL)          ;else set the fire flag.
I2J2_NoF:
            LD A,%11110101      ; Test 'up' and 'right' bits. If both were high,
            OR E
            INC A               ;incrementing A will be 0.
            JR Z,I2J2_NoUR      ; Then jump forward,
            SET 1,(HL)          ;else set the up flag.
I2J2_NoUR:
            LD A,%11111010      ; Test 'down' and 'left' bits. If both were
            OR E
            INC A               ;high, incrementing A will be 0.
            JR Z,Keys_CapsB     ; Then jump forward,
            SET 0,(HL)          ;else set the down flag.
Keys_CapsB:
            LD B,%11111110      ; Read row of keys Caps-shift to B.
            IN A,(C)
            OR %11100000
            INC A
            JR Z,Keys_QT
            SET 2,(HL)
Keys_QT:
            LD B,%11111011      ; Read row of keys Q to T.
            IN A,(C)
            OR %11100000
            INC A
            JR Z,Keys_AG
            SET 1,(HL)
Keys_AG:
            LD B,%11111101      ; Read row of keys A to G.
            IN A,(C)
            OR %11100000
            INC A
            RET Z
            SET 0,(HL)
            RET
;
; Print Char (PrChar)
;---------------------
; Description: print one character. All registers are preserved, except AF, BC'
;and DE'.
; Input: A=character code
PrChar:
            EXX                 ; Saves all general purpose registers and
            PUSH HL             ;HL'.
            CALL PrLatin1       ; Print character.
            POP HL              ; Restore saved registers.
            EXX
            RET                 ; End.
;
; Print String (PrStr)
;----------------------
; Description: prints a string pointed by HL. The end of string is marked by
;byte value lesser than 32 (space).
; Input: HL=address of string.
; Output: HL=address of last byte of string, A=code of end of string marker.
PrStr:
            LD A,(HL)           ; Get character.
            CP 32               ; If its code is lesser than 32
            RET C               ;returns.
            CALL PrChar         ; Print character.
            INC HL              ; Point to next address.
            JR PrStr            ; Repeat the loop.
;
; Print Centered String (PrCStr)
;--------------------------------
; Description: PrCStr prints strings pointed by HL, centered at screen line.
;String longer than 30 character will be truncated.
PrCStr:
            PUSH HL             ; Saves pointer.
            LD B,30             ; Max. string length counter.
; Measure string length.
PrCStr1:
            LD A,(HL)           ; Get character.
            INC HL              ; Increment pointer.
            CP 32               ; Jump forward if end mark was found.
            JR C,PrCStr3
            DJNZ PrCStr1        ; Repeat until max. length is found.
; Print one space, 30 characters and one space.
            POP HL              ; Recover pointer initial value.
            LD A,32             ; Prints space.
            RST 16
            LD B,30             ; Counter for 30 characters.
PrCStr2:
            LD A,(HL)           ; Get character and print it.
            CALL PrChar
            INC HL              ; Increment pointer and
            DJNZ PrCStr2        ;repeat.
            LD A,32             ; Print space.
            RST 16
            RET                 ; End.
; Calculate tabulation and print
PrCStr3:    SRL B               ; B=B/2-1, number of print positions to be
            INC B               ;skipped.
            LD A,Pr_Tab         ; {PRINT TAB B;}.
            RST 16
            LD A,B
            RST 16
            XOR A
            RST 16
            POP HL              ; Recover pointer initial value.
            CALL PrStr          ; Print the string.
            LD A,Comma_Tab      ; Print until the end of the line with
            RST 16              ;{PRINT ,}.
            RET                 ; End.
;
; Print Latin 1 (PrLatin1)
;--------------------------
; Description: print character code contained in the accumulator at upper video
;area. The characters within 0-159 range are printed by the ROM routine
;PRINT_OUT; above ;this value (160-255), corresponding Latin-1 character
;(ISO8859-1) are printed.
; Input: A=character code (0-255)
PrLatin1:
            RES 1,(IY+1)        ; Reset flag to print to screen instead printer.
            RES 0,(IY+2)        ; Reset flag to print at upper video area.
            CP 160              ; If character code<160
            JP C,PRINT_OUT      ;jump to ROM routine.
            LD HL,(ERR_SP)      ; Preserve ERR_SP.
            LD (OldErrsp),HL
            LD HL,PrLatRet      ; Store sub-routine return address in the
            PUSH HL             ;stack.
            LD (ERR_SP),SP      ; Even when an error occurs, return to PrLatRet.
            CALL ExChars        ; Select Latin1 character set.
            RES 7,A             ; The character code gamma is changed from
                                ; Convert characters from range 160-255 to 32-127.
            CALL _PO_FETCH      ; Parts of PRINT_OUT where different treatments
            JP _PO_ABLE         ;for <32 or >127 characters are omitted, to make
                                ;possible printing in full 7 bit codes (0-127).
PrLatRet:
            CALL ExChars        ; Select normal character set.
            LD HL,(OldErrsp)    ; Restore old ERR_SP value.
            LD (ERR_SP),HL
            BIT 7,(IY+0)        ; If ERR_NR signaled no error had been detected
            RET NZ              ;then return,
            LD SP,(ERR_SP)
            RET                 ;else jump to error handling routine of BASIC.
;
; Exchange CHARS
;----------------
; Exchange contents of CHARS and T_CHARS (temporary CHARS). Swap between
;alternate character sets.
ExChars:
            LD HL,(CHARS)
            LD DE,(T_CHARS)
            LD (CHARS),DE
            LD (T_CHARS),HL
            RET
;
; Scroller
;----------
; Description: Scroller prints message at two bottom lines of the screen with
;double height characters. The scroller is synchronized with maskable interrupts
;that occurs 50 or 60 times per second. Thus, some interrupts must be skipped
;in order to make message visible for human eyes.
;
; Altered to scroll pixel by pixel.
;
; Input: MsgIni, MsgPtr
; Variables:
;   PixCount=counter, 8 pixels to be rotated
;   ChrBitmap=8 byte bitmap for rightmost character
;   ScrBuffer=array of 32x8 bytes to store bitmap of bottom lines
; Print at line=22 and column=0.
ScrPrnPos:  EQU 16384+(2*2048)+(6*32)

Scroller:
; Create bitmap for 32 characteres in screen buffer.
            LD DE,ChrBitmap     ; DE is pointer for first byte of character that
                                ;is hidden after rightmost position.
            LD HL,ScrBuffer+31  ; Rightmost postion of first line.
            LD BC,256*32+8      ; Counters: B=32 bytes, C=8 lines.
Scroller1:
            PUSH BC
            LD A,(DE)           ; Take byte from hidden character and rotate
            RLCA                ;1 bit leftwise.
            LD (DE),A
            INC DE              ; DE is now pointing to next byte.
Scroller2:
            RL (HL)             ; Rotate 1 bit leftwise.
            DEC HL              ; HL is pointing to previous position of buffer.
            DJNZ Scroller2      ; Repeat for 32 bytes of a line.
            LD C,64             ; BC=64.
            ADD HL,BC           ; Rightmost position of next line of buffer.
            POP BC
            DEC C               ; Repeat for 8 lines.
            JR NZ,Scroller1
; Copy bitmap to screen.
            LD HL,ScrBuffer     ; Address of screen buffer.
            LD DE,ScrPrnPos     ; Address of video RAM buffer to copy to.
            LD A,16             ; 16 pixel lines.
Scroller3:
            PUSH DE
            PUSH HL
            LD BC,32            ; Copy 32 bytes.
            LDIR
            POP HL
            POP DE
            INC D               ; Calculate adress of next line.
            DEC A               ; Decrement line counter.
            JR Z,Scroller5      ; Jump outside loop if last line was printed.
            BIT 0,A             ; Copy same line to screen if line number in the
            JR NZ,Scroller3     ;buffer is odd.
            LD C,32             ; Calculate address of next line of buffer.
            ADD HL,BC
            EX AF,AF'           ; Save line counter.
            LD A,D              ; Go to next pixel line if it is not the last
            AND 000111       ;one.
            JR NZ,Scroller4
            LD DE,ScrPrnPos+32  ; Adress of text line 7 and pixel line 0.
Scroller4:
            EX AF,AF'           ; Fetch line counter.
            JR Scroller3
; Verify if all bits were rotated.
Scroller5:
            LD HL,PixCount      ; Return if last pixel has been rotated.
            DEC (HL)
            RET NZ
            LD (HL),8           ; Reinitialize pixel counter.
            LD HL,(MsgPtr)      ; Get character from scrolling message
            LD A,(HL)           ;memory.
            INC HL
            CP 32               ; Initialize scrolling message pointer if
            JR NC,Scroller6     ;character code is less than 32 and
            LD HL,(MsgIni)
            LD A," "            ;print space.
Scroller6:
            LD (MsgPtr),HL      ; Update message pointer.
            LD HL,(CHARS)       ; HL is address of character model table.
            BIT 7,A             ; Use alternative table if character code is
            JR Z,Scroller7     ;greater or equal to 128.
            LD HL,(T_CHARS)
            RES 7,A             ; Adjust character code within 32-127 range.
Scroller7:
            LD D,0              ; Address of character model within table is
            LD E,A              ;given by following equation:
            EX DE,HL            ;HL=(table address)+8*(character code).
            ADD HL,HL
            ADD HL,HL
            ADD HL,HL
            ADD HL,DE
            LD DE,ChrBitmap     ; Copy 8 bytes of character model.
            LD BC,8
            LDIR
            RET
;
Latin1:

            INCLUDE "Latin1.asm"
                                ; Include bitmap models for Latin-1 charset.
;
; Default scroll message.
Logo:       DEFM "                               "
            DEFM "Beta Boot Menu "
Version:    DEFM "v4.0 "
            DEFM "                              "
            DEFB 0
;
ScrBuffer:  DEFS 256            ; 256 byte buffer for the scroller.
ChrBitmap:  DEFS 8              ; 8 bytes space for character bitmap model.
;
; End of program
            END


A novidade da  versão 4 é o rolamento (scroll) suave da mensagem que fica nas linhas inferiores da tela. Nas versões anteriores o rolamento ocorria em passos de 1 caractere de largura (8 pixels), mas nesta os passos são de 1 pixel.

Nenhum comentário:

Postar um comentário

Seu comentário é bem vindo, mas peço que use este espaço adequadamente.