;---------------------------------------------------------------------------
;  W A T K I N    T E C H N O L O G Y    S o f t w a r e  D i v i s i o n
;---------------------------------------------------------------------------
; PROGRAM: Bootable Mini Monitor for PC
; VERSION: 1.0                            PLATFORM: 8088+
; PROJECT: USB Pendrive Booting               FILE: MINIMON .ASM
;  AUTHOR: Neville Watkin                     DATE: 14 Jan 2011
;   NOTES: Assemble with fasm to MINIMON.IMG
;          Remove/replace DOS test code for bootsector version! See ****
;---------------------------------------------------------------------------
;                            Revision History
;14.01.11  initial release
;---------------------------------------------------------------------------
;                ORG     0100H           ;for pre-testing with DOS ****
                ORG     7C00H           ;boot version

                JMP     MINIMON
                NOP
MINIMON:
;                JMP     0000H:START     ;add later if room to ensure CS=0
;START:
                MOV     AX,3            ;could assume this to save 5 bytes?
                INT     10H

                PUSH    0
                POP     DS              ;ds=0 initially
; TIMES 9 DB 90H                              ;dummy code replaced below ****
                MOV     DWORD[14H],00007C00H ;set INT5 vector boot version
AGAIN:
                MOV     BX,WORD[CS:MEMADDR]  ;shift start offset to BX
                MOV     SI,BX           ;save a copy
                MOV     BL,0            ;low 8 bits of address = 0
                MOV     DX,0803H        ;start memory dump at line 8, col 3
                CALL    SETCURS

                PUSH    CX
                MOV     CX,10H          ;16 lines per dump
LINE:           PUSH    CX
;                MOV     CX,10H          ;16 bytes per line
                MOV     CL,10H          ;16 bytes per line - 1 byte!
                MOV     AX,DS           ;get MS high offset byte
                ROL     AX,4
                CALL    BYTE2ASC        ;convert to ascii hex
                MOV     AL,BH           ;get LS high offset byte
                CALL    BYTE2ASC
                MOV     AL,BL           ;get low offset byte
                CALL    BYTE2ASC
RDMEM:
                PUSH    BX
                MOV     BX,7
                MOV     AX,0E20H
                INT     10H
                POP     BX

                MOV     AL,[BX]        ;get byte from memory
                CALL    BYTE2ASC        ;convert to ascii-hex
                INC     BX
                LOOP    RDMEM           ;and repeat for 16 bytes

                POP     CX
                INC     DH              ;increase line number
                MOV     DL,03H          ;reset column (instead of CRLF)
                CALL    SETCURS
                LOOP    LINE            ;repeat for all lines
                POP     CX
                MOV     DX,[CS:CURLOC]  ;set cursor for editing
                CALL    SETCURS
GETBYTE:        PUSH    CX
                CALL    GETNYBL         ;get MS Digit
                JC      CMD             ;command key if c set
                MOV     CH,AL           ;save in ch
                CALL    HEXDIGIT        ;convert back to ascii
                MOV     AH,0EH
                INT     10H
                CALL    GETNYBL         ;get LS Digit
                JC      CMD
                MOV     CL,AL           ;save in cl
                CALL    HEXDIGIT        ;convert back to ascii
                MOV     AH,0EH
                INT     10H
                MOV     AL,CH           ;retrieve binary MSD
                SHL     AL,4            ;shift to bits 4-7
                OR      AL,CL           ;merge with bits 0-3
;                MOV     BX,WORD[CS:MEMADDR]  ;get start addr again
                MOV     BX,SI           ;get start addr again
                MOV     [BX],AL
                JMP     INCBYTE         ;and update curloc & edit address
CMD:            POP     CX
;                CMP     AL,01H          ;ESC? DOS test only +4 bytes ****
;                JZ      EXIT
                CMP     AL,51H          ;PgDn? LS low offset increase
                JZ      INCLSL
                CMP     AL,49H          ;PgUp? LS low offset decrease
                JZ      DECLSL
                CMP     AL,4FH          ;End key? Segment increase
                JZ      INCSEG
                CMP     AL,2DH          ;x or X?
                JZ      EXEC0100        ;execute from edit addr with IP=0100
                                        ;(so can also pre-test code in DOS)

                MOV     DX,[CS:CURLOC]  ;assume editing control command
                CMP     AL,4DH          ;next byte for editing ->
                JZ      INCBYTE
                CMP     AL,4BH          ;next byte for editing <-
                JZ      DECBYTE
                CMP     AL,50H          ;next para for editing <-
                JZ      INCPARA
                CMP     AL,48H          ;next para for editing <-
                JZ      DECPARA
                JMP     CMDDONE
INCLSL:         INC     BYTE[CS:MEMADDR+1]
                JMP     CMDDONE
DECLSL:         DEC     BYTE[CS:MEMADDR+1]
                JMP     CMDDONE
INCSEG:         PUSH    DS
                POP     AX
                ADD     AX,1000H
                MOV     DS,AX
                JMP     CMDDONE

;EXEC0100:       MOV     BX,WORD[CS:MEMADDR] ;get start addr again
EXEC0100:       MOV     BX,SI           ;get start addr again
                SUB     BX,100H         ;use offset 0000 to save these bytes?
                SHR     BX,4            ;must be on para boundary!
                MOV     AX,DS
                ADD     AX,BX           ;derive CS
                MOV     WORD[CS:EXECSEG],AX    ;setup CS
                JMP     EXECPROG        ;set CS,IP - see you later!

INCBYTE:        INC     WORD[CS:MEMADDR]
                ADD     DL,03H
                MOV     [CS:CURLOC],DX
                CMP     DL,37H
                JA      INCBYTE1
                JMP     CMDDONE
INCBYTE1:       MOV     DL,0AH
                INC     DH
                MOV     [CS:CURLOC],DX
                CMP     DH,17H
                JA      INCBYTE2
                JMP     CMDDONE
INCBYTE2:       MOV     DX,080AH
                MOV     [CS:CURLOC],DX
                JMP     CMDDONE
DECBYTE:        DEC     WORD[CS:MEMADDR]
                SUB     DL,03H
                MOV     [CS:CURLOC],DX
                CMP     DL,0AH
                JB      DECBYTE1
                JMP     CMDDONE
DECBYTE1:       MOV     DL,37H
                DEC     DH
                MOV     [CS:CURLOC],DX
                CMP     DH,08H
                JB      DECBYTE2
                JMP     CMDDONE
DECBYTE2:       MOV     DX,1737H
                MOV     [CS:CURLOC],DX
                JMP     CMDDONE
INCPARA:        ADD     WORD[CS:MEMADDR],10H
                INC     DH
                MOV     [CS:CURLOC],DX
                CMP     DH,17H
                JA      INCPARA2
                JMP     CMDDONE
INCPARA2:       MOV     DH,08H
                MOV     [CS:CURLOC],DX
                JMP     CMDDONE
DECPARA:        SUB     WORD[CS:MEMADDR],10H
                DEC     DH
                MOV     [CS:CURLOC],DX
                CMP     DH,08H
                JB      DECPARA2
                JMP     CMDDONE
DECPARA2:       MOV     DH,17H
                MOV     [CS:CURLOC],DX
CMDDONE:
                JMP     AGAIN           ;1 long jump, saves 10 bytes!
;EXIT:
;                INT     20H             ;DOS test only +2 bytes ****
;----------------------------------------------------------------------------
;Subroutines
;----------------------------------------------------------------------------
SETCURS:
                PUSH    AX              ;save reqd char
                PUSH    BX
                MOV     AH,02
                MOV     BX,7
                INT     10H
                POP     BX
                POP     AX              ;restore reqd char in al
                RET

GETNYBL:        CLC                     ;clear carry
                MOV     AH,0
                INT     16H
                CMP     AL,0            ;allow all cursor keys as commands
                JZ      CMDKEY
                CMP     AL,1BH          ;Esc?
                JZ      CMDKEY
                CMP     AL,30H          ;ignore if < "0"
                JB      GETNYBL
                CMP     AL,66H          ;allow all lowercase > "f" as cmds
                JA      CMDKEY
                CMP     AL,61H          ;valid lowercase if a - f
                JAE     LOWCASE
                CMP     AL,46H          ;allow all uppercase F-Z as commands
                JA      CMDKEY
                CMP     AL,41H          ;valid uppercase if A - F
                JAE     UPCASE
                CMP     AL,39H          ;ignore if between 9 and A
                JA      GETNYBL
                SUB     AL,30H          ;must be 0 - 9, convert to binary
                JMP     GOTNYBL
LOWCASE:        SUB     AL,57H          ;must be a - f. convert to binary
                JMP     GOTNYBL
UPCASE:         SUB     AL,37H          ;must be A - F, convert to binary
                JMP     GOTNYBL
CMDKEY:         STC                     ;set Carry flag for command key
                MOV     AL,AH           ;check scan codes using AL,
GOTNYBL:        RET                     ;saving 1 byte each time

BYTE2ASC:       PUSH    BX              ;save RAM pointer
                PUSH    AX              ;save binary data
                SHR     AL,4            ;get high nybble
                CALL    HEXDIGIT        ;and convert to ascii-hex
                MOV     BH,AL           ;save MSD in bh
                POP     AX              ;retrieve binary data
                AND     AL,0FH          ;get low nybble
                CALL    HEXDIGIT        ;and convert to ascii-hex
                MOV     AH,BH           ;restore MSD to ah
DBYTE:          PUSH    DX
                PUSH    CX
                MOV     BX,0007H        ;page 0, colour = white
                MOV     CX,AX           ;save data in cx
                MOV     AH,0EH
                MOV     AL,CH
                INT     10H
                MOV     AL,CL
                MOV     AH,0EH
                INT     10H
                POP     CX
                POP     DX
                POP     BX
                RET

HEXDIGIT:       ADD     AL,30H
                CMP     AL,3AH
                JB      HEXDIGID
                ADD     AL,07
HEXDIGID:       RET

MEMADDR: DW 7C00H
CURLOC: DW 080AH                ;cursor location for editing
EXECPROG: DB 0EAH               ;JMP command
EXECOFFS: DW 0100H              ;default offset always 0100H
EXECSEG: DW 07B0H               ;default seg    ) = 07B00100H this program!
 TIMES 7C00H+510-$ DB 0         ;4 bytes spare!
; DB 0
 DB 55H, 0AAH

