;CP/M Disk Sector Editor
;For my 8080 Computer
;
;Version 1.0
;08-19-2024
;Jerry Davis
;
   CPU 8080 ;Specify architecture
   PAGE 0   ;Turn off page breaks in listings
;
;
;CP/M Return Vector
;
ccp   equ   0de00h
;
;
;CPM Current Drive
cdrive equ 4
;
;
;BIOS Routines
;
wboot   equ   0f403h   ;warm start
const   equ   0f406h   ;console status
conin   equ   0f409h   ;console character in
conout  equ   0f40ch   ;console character out
seldsk  equ   0f41bh   ;select disk
settrk  equ   0f41eh   ;set track number
setsec  equ   0f421h   ;set sector number
setdma  equ   0f424h   ;set dma address
read    equ   0f427h   ;read disk
write   equ   0f42ah   ;write disk
;
;
;BIOS Write Types
wrall	equ 0		;write to allocated
wrdir	equ 1		;write to directory
wrual	equ 2		;write to unallocated
;
;
   org 0100h
;
;
start:
   lda cdrive          ;Start with the current drive
   sta current_drive   ;Save it in current drive
   mvi a, 0h           ;Start with default values
   sta current_track   ;Save it in current track
   sta current_sector  ;Save it in current sector
   sta current_emode   ;Save it in current edit mode
   lxi b, secbuf       ;Get sector buffer address
   call setdma         ;Set for sector buffer address
   call hide_cursor    ;Hide the cursor until needed
   call linewrap_off   ;Turn off auto line wrap
   call header_top     ;Print top app header lines   
   call print_nl       ;New line
;
;   
navmode:
   call hide_cursor     ;Hide the cursor until needed
   call print_navmode   ;Print nav mode controls
   call print_navfun    ;Print navigation function controls
   call print_navsubfun ;Print navigation sub-function controls
   jmp nav_exec         ;Get initial sector, display, and parse keys until exit
navkeys:
   call flush_console   ;Start with clean console
   call conin        ;Get a key from the keyboard
   cpi 1bh           ;Is it ESC?
   jnz navkeys_norm  ;If not, parse regular character
   call conin        ;Get rest of escape sequence
   cpi '['           ;Is it '['?
   jnz navkeys       ;If not, do input over again 
   call conin        ;Get last sequence character
   cpi 'A'           ;Nav key UP?
   jz nav_nextsec    ;Do next sector
   cpi 'B'           ;Nav key DN?
   jz nav_prevsec    ;Do previous sector
   cpi 'C'           ;Nav key RT?
   jz nav_nexttrk    ;Do next track
   cpi 'D'           ;Nav key LF?
   jz nav_prevtrk    ;Do previous track
   cpi '1'           ;Nav key HOM?
   jz nav_firstsec   ;Do first sector/track
   cpi '4'           ;Nav key END?
   jz nav_lastsec    ;Do last sector/track
   jmp navkeys       ;Start again
navkeys_norm:
   cpi 5h            ;Enter edit mode?
   jz editmode       ;Do edit mode
   cpi 18h           ;Exit to CPM?
   jz nav_exit       ;Do it
   ani 0dfh          ;Make upper case
   cpi 'D'           ;Change Disk?
   jz nav_chgdsk     ;Do it
   cpi 'T'           ;Change Track?
   jz nav_chgtrk     ;Do it
   cpi 'S'           ;Change Sector?
   jz nav_chgsec     ;Do it
   cpi 'B'           ;Change Sector?
   jz nav_chgblk     ;Do it
   jmp navkeys   
nav_nextsec:
   lda current_sector  ;Get current sector
   cpi 0ffh            ;Last sector?
   jz navkeys          ;no action
   inr a               ;Point to next sector
   sta current_sector  ;Save it
   jmp nav_exec        ;Execute key
nav_prevsec:
   lda current_sector  ;Get current sector
   cpi 0h              ;First sector?
   jz navkeys          ;no action
   dcr a               ;Point to next sector
   sta current_sector  ;Save it
   jmp nav_exec        ;Execute key
nav_nexttrk:
   lda current_track   ;Get current track
   cpi 0ffh            ;Last track?
   jz navkeys          ;no action
   inr a               ;Point to next track
   sta current_track   ;Save it
   jmp nav_exec         ;Execute key
nav_prevtrk:
   lda current_track   ;Get current track
   cpi 0h              ;First track?
   jz navkeys          ;no action
   dcr a               ;Point to next track
   sta current_track   ;Save it
   jmp nav_exec         ;Execute key
nav_firstsec:
   mvi a, 0h           ;Start with zero
   sta current_track   ;Save the track
   sta current_sector  ;Save the sector
   jmp nav_exec         ;Execute key
nav_lastsec:
   mvi a, 0ffh         ;Start with FF
   sta current_track   ;Save the track
   sta current_sector  ;Save the sector
   jmp nav_exec        ;Execute key
nav_exec:
   call print_params   ;Update param display
   lda current_track   ;Get current track
   mov c, a            ;Put it in C
   call settrk         ;Set for track 0
   lda current_sector  ;Get current track
   mov c, a            ;Put it in C
   call setsec         ;Set for track 0
   call read           ;Get sector
   call print_buffer   ;Print sector
   jmp navkeys         ;Get next command from console   
nav_chgdsk:
   lxi d, 0307h        ;Move to disk field
   call move_cursor    ;Move the cursor
   call show_cursor    ;Show the cursor
   call set_intense    ;Set to bright video
   call conin          ;Get one character
   ani 0dfh            ;Make upper case
   sui 'A'             ;Change to drive number
   mov c, a            ;Put drive number in C
   call seldsk         ;Select the disk
   mov a, h            ;valid drive?
   ora l               ;valid drive?
   jz nav_chgdsk01     ;Invalid.  Just do parameters.
   mov a, c            ;Put drive number in A
   sta current_drive   ;Save drive number
   call hide_cursor    ;Hide the cursor
   call print_params   ;Print parameters
   jmp nav_exec        ;Get disk sector
nav_chgdsk01:
   call hide_cursor    ;Hide the cursor
   call print_params   ;Print parameters
   jmp navkeys         ;Get next command from console 
nav_chgtrk:
   lxi d, 0317h        ;Move to track field
   call move_cursor    ;Move the cursor
   call show_cursor    ;Show the cursor
   call set_intense    ;Set to bright video
   call get_hexbyte    ;Get hex byte into A
   sta current_track   ;Save it
   call hide_cursor    ;Hide the cursor
   call print_params   ;Print parameters
   jmp nav_exec        ;Get disk sector
nav_chgsec:
   lxi d, 0329h        ;Move to sector field
   call move_cursor    ;Move the cursor
   call show_cursor    ;Show the cursor
   call set_intense    ;Set to bright video
   call get_hexbyte    ;Get hex byte into A
   sta current_sector  ;Save it
   call hide_cursor    ;Hide the cursor
   call print_params   ;Print parameters
   jmp nav_exec        ;Get disk sector
nav_chgblk:
   lxi d, 0340h        ;Move to block field MSB
   call move_cursor    ;Move the cursor
   call show_cursor    ;Show the cursor
   call set_intense    ;Set to bright video
   call get_hexbyte    ;Get hex byte into A
   mov h, a            ;Save it in B
   call get_hexbyte    ;Get hex byte into A
   mov l, a            ;Save it in C
   shld current_block  ;Save it
   ani 07h             ;Get sector count
   rrc                 ;Put lower 3 bits into upper 3 bits
   rrc                 ;aka, multiply by 32
   rrc
   sta current_sector  ;Save beginning sector number
   mov a, l            ;Get LSB of block
   ani 0f8h            ;Mask off lower 3 bits
   rrc                 ;Move upper 5 bits 3 places to the right
   rrc                 ;aka divide by 8
   rrc
   mov l, a            ;Save it in L
   mov a, h            ;Get MSB of block
   ani 07h             ;Mask off upper 5 bits
   rrc                 ;Move lower 3 bits 5 places to the left
   rrc
   rrc                 
   ora l               ;Bring in the lower bits
   inr a               ;Increment it
   sta current_track   ;Save track number
   call hide_cursor    ;Hide the cursor
   call print_params   ;Print parameters
   jmp nav_exec        ;Get first sector of block   
nav_exit:
   call clear_screen   ;Clean up the screen
   call show_cursor    ;Enable cursor
   call linewrap_on    ;Turn on auto line wrap
   jmp wboot           ;Hand control back CP/M
;
;   
editmode:
   call hide_cursor      ;Hide the cursor until needed
   call print_editmode   ;Print edit navigation controls
   call print_editsubfun ;Print edit sub-function controls
   call edit_statline    ;Update the hex/text edit mode
   lxi h, secbuf         ;Point to sector buffer
   shld current_buf      ;Save it
   lxi h, 0607h          ;Top left cursor position
   shld current_pos      ;Save cursor position
   lxi h, 0658h          ;Top left text cursor position
   shld current_tpos     ;Save cursor position
   xra a                 ;Hex edit mode
   sta current_emode     ;Save it
   jmp edit_firstbyte    ;Init editor
editkeys:
   call show_cursor      ;Show the cursor
   call flush_console    ;Start with clean console
   lda current_emode     ;Get current edit mode
   ana a                 ;Is it text mode?
   jnz editkeys01        ;If so then get text
   call edit_hex         ;Edit byte or get edit navigation gey
   jmp editkeys02        ;Check input
editkeys01:
   call get_char         ;Get text character
editkeys02:
   cpi 0h                ;Valid hex or ascii input?
   jz edit_nextcol       ;If so, move to next buffer byte
   cpi 1bh               ;Is it ESC?
   jnz editkeys_norm     ;If not, parse regular character
   call conin            ;Get rest of escape sequence
   cpi '['               ;Is it '['?
   jnz editkeys          ;If not, do input over again 
   call conin            ;Get last sequence character
   push psw
   call hide_cursor
   pop psw
   cpi 'A'               ;Nav key UP?
   jz edit_prevline      ;Do next sector
   cpi 'B'               ;Nav key DN?
   jz edit_nextline      ;Do previous sector
   cpi 'C'               ;Nav key RT?
   jz edit_nextcol       ;Do next track
   cpi 'D'               ;Nav key LF?
   jz edit_prevcol       ;Do previous track
   cpi '1'               ;Nav key HOM?
   jz edit_firstbyte     ;Do first sector/track
   cpi '4'               ;Nav key END?
   jz edit_lastbyte      ;Do last sector/track
   jmp editkeys          ;Start again
editkeys_norm:
   push psw
   call hide_cursor
   pop psw
   cpi 0eh               ;Enter navigation mode?
   jz navmode            ;Do edit mode
   cpi 18h               ;Exit to CPM?
   jz nav_exit           ;Do it
   cpi 13h               ;Save sector?
   jz edit_savesec       ;Do it
   cpi 12h               ;Reload sector?
   jz edit_rldsec        ;Do it
   cpi 09h               ;Text mode?
   jz edit_txtmode       ;Do it
   jmp editkeys   
edit_nextline:
   lhld current_pos    ;Get current cursor position
   mvi a, 13h          ;Max line position
   cmp h               ;Already at max?
   jz editkeys         ;Get next command from console
   call edit_clearattr ;Update the sector display
   lhld current_buf    ;Get the buffer pointer
   lxi d, 10h          ;Next 'row' buffer position
   dad d               ;Adjust buffer pointer
   shld current_buf    ;Save buffer pointer
   lhld current_pos    ;Get current hex position
   mov a, h            ;Move line value into A
   adi 1h              ;Increment it
   daa                 ;Decimal adjust it
   mov h, a            ;Put it back in line value
   shld current_pos    ;Save cursor position
   lhld current_tpos   ;Get current cursor text position
   mov h, a            ;Put it in text line value
   shld current_tpos   ;Save cursor text position
   call edit_setattr   ;Update the sector hex display
   jmp editkeys        ;Get next command from console
edit_prevline:
   lhld current_pos    ;Get current cursor position
   mvi a, 6h           ;Min row position
   cmp h               ;Already at max?
   jz editkeys         ;Get next command from console
   call edit_clearattr ;Update the sector display
   lhld current_buf    ;Get the buffer pointer
   lxi d, 0fff0h       ;Previous 'row' buffer position
   dad d               ;Adjust buffer pointer
   shld current_buf    ;Save buffer pointer
   lhld current_pos    ;Get current hex position
   mov b, h            ;Move line value into B
   mvi c, 1h           ;But decrement in C
   call sub_daa        ;Decimal subtract
   mov h, b            ;Put it back in line value
   shld current_pos    ;Save cursor position
   lhld current_tpos   ;Get current cursor text position
   mov h, b            ;Put it in text line value
   shld current_tpos   ;Save cursor text position
   call edit_setattr   ;Update the sector hex display
   jmp editkeys        ;Get next command from console
edit_nextcol:
   lhld current_pos    ;Get current cursor position
   mvi a, 54h          ;Max col position
   cmp l               ;Already at max?
   jz edit_wrapleft    ;Try wraparound
   call edit_clearattr ;Update the sector display
   lhld current_buf    ;Get the buffer pointer
   inx h               ;Next 'col' buffer position
   shld current_buf    ;Save buffer pointer
   lhld current_pos    ;Get current hex position
   mov a, l            ;Move col value into A
   adi 3h              ;Increment it
   daa                 ;Decimal adjust it
   cpi 31h             ;Center column break?
   jnz edit_nxcol01    ;Do normal increment
   adi 2h              ;Increment again
   daa                 ;Decimal adjust it
edit_nxcol01:
   mov l, a            ;Move new col value into L
   shld current_pos    ;Save cursor position
   lhld current_tpos   ;Get current text position
   mov a, l            ;Put test column in A
   adi 1h              ;Increment it
   daa                 ;Decimal adjust it
   mov l, a            ;Put it back in L
   shld current_tpos   ;Save cursor position
   call edit_setattr   ;Update the sector hex display
   jmp editkeys        ;Get next command from console
edit_prevcol:
   lhld current_pos    ;Get current cursor position
   mvi a, 7h           ;Min col position
   cmp l               ;Already at min?
   jz edit_wrapright   ;Try wraparound
   call edit_clearattr ;Update the sector display
   lhld current_buf    ;Get the buffer pointer
   dcx h               ;Previous 'col' buffer position
   shld current_buf    ;Save buffer pointer
   lhld current_pos    ;Get current hex position
   mov b, l            ;Move col value into B
   mvi c, 3h           ;Put decrement in C
   call sub_daa        ;Decimal subtract
   mvi a, 30h          ;Column spacer
   cmp b               ;Check it
   jnz edit_pvcol01    ;Move along if not
   mvi c, 2h           ;Additional decrement
   call sub_daa        ;Decimal subtract
edit_pvcol01:
   mov l, b            ;Move new col value into L
   shld current_pos    ;Save cursor position
   lhld current_tpos   ;Get current text position
   mov b, l            ;Put text column position in b
   mvi c, 1h           ;Put decrement in C
   call sub_daa        ;Decimal subtract
   mov l, b            ;Put new text column position in L
   shld current_tpos   ;Save cursor text position
   call edit_setattr   ;Update the sector hex display
   jmp editkeys        ;Get next command from console
edit_firstbyte:
   call edit_clearattr ;Update the sector display
   lxi h, secbuf       ;Point to the sector buffer
   shld current_buf    ;save buffer pointer
   lxi h, 0607h        ;Top left cursor position
   shld current_pos    ;Save cursor position
   lxi h, 0658h        ;Top left text cursor position
   shld current_tpos   ;Save cursor position
   call edit_setattr   ;Update the sector display
   jmp editkeys        ;Get next command from console
edit_lastbyte:
   call edit_clearattr ;Update the sector display
   lxi h, secbuf       ;Point to the sector buffer
   lxi b, 7fh          ;End of buffer
   dad b               ;Point to end of buffer
   shld current_buf    ;save buffer pointer
   lxi h, 1354h        ;Cursor end position in text sector display
   shld current_pos    ;Save cursor position
   lxi h, 1373h        ;Cursor end position in text sector display
   shld current_tpos   ;Save cursor position
   call edit_setattr   ;Update the sector display
   jmp editkeys        ;Get next command from console
edit_savesec:
   mvi c, wrdir        ;Write immediately to sector
   call write          ;Write sector
   call read           ;Get sector
   call print_buffer   ;Print sector
   jmp editmode        ;Start over
edit_rldsec:
   call read           ;Get sector
   call print_buffer   ;Print sector
   jmp editmode        ;Start at first byte
edit_txtmode:
   call edit_clearattr ;Update the sector display
   lda current_emode   ;Get edit mode
   xri 1               ;Flip it
   sta current_emode   ;Save new mode
   call edit_statline  ;Update the edit mode status line
   call edit_setattr   ;Update the sector display
   jmp editkeys        ;Do next key
edit_wrapleft:
   mvi a, 13h          ;Max line position
   cmp h               ;Already at max?
   jz edit_firstbyte   ;Start over at the top
   call edit_clearattr ;Update the sector display
   lhld current_pos    ;Get current hex position
   mvi l, 07h          ;Set to far left column   
   shld current_pos    ;Save current position
   lhld current_tpos   ;Get current text position
   mvi l, 58h          ;Set to far left column
   shld current_tpos   ;Save current text position   
   lhld current_buf    ;Get the buffer pointer
   lxi d, 0fff1h       ;Point to far left 'column' buffer position
   dad d               ;Adjust buffer pointer
   shld current_buf    ;Save buffer pointer
   jmp edit_nextline   ;Do next line
edit_wrapright:
   mvi a, 06h          ;Min line position
   cmp h               ;Already at min?
   jz edit_lastbyte    ;Move to the end
   call edit_clearattr ;Update the sector display
   lhld current_pos    ;Get current hex position
   mvi l, 54h          ;Set to far right column   
   shld current_pos    ;Save current position
   lhld current_tpos   ;Get current text position
   mvi l, 73h          ;Set to far left column
   shld current_tpos   ;Save current text position   
   lhld current_buf    ;Get the buffer pointer
   lxi d, 0fh          ;Point to far right 'column' buffer position
   dad d               ;Adjust buffer pointer
   shld current_buf    ;Save buffer pointer
   jmp edit_prevline   ;Do previous line
;
;
;Clear attributes from current hex and text cells
;according to current_pos and current_tpos
;Modifies a, c, hl, de 
edit_clearattr:
   call set_normal     ;Set normal intensity
   lhld current_pos    ;Get current hex position
   xchg                ;Put it in DE
   call move_cursor    ;Move cursor
   lhld current_buf    ;Point to sector buffer   
   mov c, m            ;Get buffer byte
   call print_hex      ;Write it
   lhld current_tpos   ;Get current text position
   xchg                ;Put it in DE
   call move_cursor    ;Move cursor
   lhld current_buf    ;Point to sector buffer   
   mov c, m            ;Put it in C
   call print_chr      ;Write it
   call edit_cursupd   ;Update the cursor position
   ret
;
;
;Set attributes from current hex and text cells
;according to current_pos and current_tpos
;and state of text edit mode
;Modifies a, c, hl, de 
edit_setattr:
   call set_normal     ;Set normal intensity
   lda current_emode   ;Get text edit mode
   ana a               ;Set flags
   jz edit_satr01      ;Print with normal video
   call set_reverse    ;Otherwise print with reverse video
edit_satr01:
   lhld current_pos    ;Get current hex position
   xchg                ;Put it in DE
   call move_cursor    ;Move cursor
   lhld current_buf    ;Point to sector buffer   
   mov c, m            ;Get buffer byte
   call print_hex      ;Write it
   lda current_emode   ;Get text edit mode
   ana a               ;Set flags
   jz edit_satr02      ;Change to reverse video
   call set_normal     ;Set normal video
   jmp edit_satr03     ;Print with normal video
edit_satr02:
   call set_reverse    ;Print with reverse video
edit_satr03:
   lhld current_tpos   ;Get current text position
   xchg                ;Put it in DE
   call move_cursor    ;Move cursor
   lhld current_buf    ;Point to sector buffer   
   mov c, m            ;Put it in C
   call print_chr      ;Write it
   call set_normal     ;Reset to normal intensity
   call edit_cursupd   ;Update the cursor position
   ret
;
;
;Update cursor position for hex or text display
;depending on edit mode
;Modifies a, c, hl, de
edit_cursupd:
   lda current_emode   ;Get text edit mode
   ana a               ;Check it
   jnz edit_csup01     ;Move to text position
   lhld current_pos    ;Get current hex cursor position
   jmp edit_csupex     ;Move and return
edit_csup01:
   lhld current_tpos   ;Get current text cursor position
edit_csupex:
   xchg
   call move_cursor    ;Move cursor
   ret
;
;
;Update the status line with HEX or TEXT mode
edit_statline:
   call set_reverse    ;Set to inverse video
   lxi d, 2533h        ;Point to edit mode status
   call move_cursor    ;move the cursor
   lda current_emode   ;Get edit mode
   ana a               ;Check it
   jnz edit_stln01     ;Text mode update
   lxi d, edit_stlnhex ;Point to HEX status
   call print_objects  ;Print it
   call set_normal     ;Set to normal text
   ret
edit_stln01:
   lxi d, edit_stlntext ;Point to HEX status
   call print_objects   ;Print it
   call set_normal     ;Set to normal text
   ret
edit_stlnhex:
   db 2h, 25h, 33h, 'HEX ', 0h, 0ffh
edit_stlntext:
   db 2h, 25h, 33h, 'TEXT', 0h, 0ffh
;
;
;
;Print the top header lines
;
header_top:
   call clear_screen    ;Clear the screen
   lxi d, header_objs   ;Point to object list
   call print_objects   ;Print it
   ret
header_objs:
   db 0h, 01h, 24h, 'JWD 8080 Disk Editor v1.0', 0h
   db 0h, 03h, 01h, 'DISK:    TRACK:     SECTOR:     BLOCK:       RELSEC:', 0h
   db 0h, 05h, 07h, '0  1  2  3  4  5  6  7    8  9  A  B  C  D  E  F   0123456789ABCDEF', 0h
   db 0ffh
;
;
;Print current disk, track, and sector
;
print_params:
   call set_intense   ;Set to bright video
   lxi d, 0307h       ;Point to disk field
   call move_cursor   ;Move the cursor
   lda current_drive  ;Get current drive
   adi 'A'            ;Make drive letter
   mov c, a           ;Put it in C
   call print_chr     ;Print it
   lxi d, 0317h       ;Point to track field
   call move_cursor   ;Move the cursor
   lda current_track  ;Get current drive
   push psw           ;Save A
   mov c, a           ;Put it in C
   call print_hex     ;Print it
   lxi d, 0329h       ;Point to track field
   call move_cursor   ;Move the cursor
   lda current_sector ;Get current drive
   mov c, a           ;Put it in C
   call print_hex     ;Print it
   lxi d, 0340h       ;Point to block field
   call move_cursor   ;Move the cursor
   pop psw            ;Restore A
   cpi 0              ;Is it track 0?
   jnz print_par01    ;Calculate and display block number
   lxi d, print_parnb ;Point to no block string
   call print_string  ;Print it   
   lxi d, 0354h       ;Point to relative sector field
   call move_cursor   ;Move the cursor
   lxi d, print_parrs ;Point to no block string
   call print_string  ;Print it   
   jmp print_parex    ;Exit
print_par01
   lda current_track  ;Get the track number
   dcr a              ;Subtract 1
   push psw           ;Save it
   ani 0e0h           ;Mask on upper 3 bits
   rlc                ;Put upper 3 bits into lower 3 bits
   rlc                ;aka, multiply by 8
   rlc                ;but call it MSB
   mov h, a           ;Save it in H
   pop psw            ;Restore A
   ani 01fh           ;Mask off upper 3 bits
   rlc                ;Put lower 5 bits starting at bit 7 
   rlc                ;aka, multiply by 8
   rlc                ;but call it LSB
   mov l, a           ;Save it in L
   lda current_sector ;Get the sector number
   ani 0e0h           ;Mask on upper 3 bits
   rlc                ;Put upper 3 bits into lower 3 bits
   rlc                ;aka, divide by 32 drop remainder
   rlc
   add l              ;Add it to initial block number
   mov l, a           ;Save it in L
   shld current_block ;Save current block
   mov c, h           ;Get MSB
   call print_hex     ;Print it
   mov c, l           ;Get LSB
   call print_hex     ;Print it
   lxi d, 0354h       ;Point to relative sector field
   call move_cursor   ;Move the cursor
   lda current_sector ;Get current sector
   ani 01fh           ;Mask off upper bits
   mov c, a           ;Put it in C
   call print_hex     ;Print it
print_parex
   call set_normal    ;Set to normal video
   ret
print_parnb:
   db '----', 0h
print_parrs:
   db '--', 0h
;
;
;Print function controls
;
print_navfun:
   call clear_nav_funzone  ;Clear the navigation function zone
   lxi d, navfun_objs      ;Point to object list
   call print_objects      ;Print it
   ret
navfun_objs:
   db 1h, 15h, 33h, '<Ctrl-N>', 0h
   db 0h, 15h, 42h, 'Sector Navigation', 0h
   db 1h, 16h, 33h, '<Ctrl-E>', 0h
   db 0h, 16h, 42h, 'Sector Edit', 0h
   db 1h, 17h, 33h, '<Ctrl-X>', 0h
   db 0h, 17h, 42h, 'Exit to CP/M', 0h
   db 0ffh
;
;
;Print navigation sub-function controls
;
print_navsubfun:
   call clear_nav_subfunzone  ;Clear the sub-function area
   lxi d, navsubfun_objs      ;Point to object list
   call print_objects         ;Print it
   ret
navsubfun_objs:
   db 1h, 19h, 38h, '<D>', 0h
   db 0h, 19h, 42h, 'Change Disk', 0h
   db 1h, 20h, 38h, '<T>', 0h
   db 0h, 20h, 42h, 'Change Track', 0h
   db 1h, 21h, 38h, '<S>', 0h
   db 0h, 21h, 42h, 'Change Sector', 0h
   db 1h, 22h, 38h, '<B>', 0h
   db 0h, 22h, 42h, 'Change Block', 0h
   db 0ffh
;
;
print_editsubfun:
   call clear_nav_subfunzone  ;Clear the sub-function area
   lxi d, editsubfun_objs     ;Point to object list
   call print_objects         ;Print it
   ret
editsubfun_objs:
   db 1h, 19h, 33h, '<Ctrl-S>', 0h
   db 0h, 19h, 42h, 'Save Sector', 0h
   db 1h, 20h, 33h, '<Ctrl-R>', 0h
   db 0h, 20h, 42h, 'Reload Sector', 0h
   db 1h, 21h, 36h, '<Tab>', 0h
   db 0h, 21h, 42h, 'Toggle Edit Mode', 0h
   db 0ffh
;
;
;Print navigation controls
;
print_navmode:
   call clear_navzone   ;Clear the nav control zone
   lxi d, navmode_objs  ;Point to object list
   call print_objects   ;Print it
   lxi d, nav_modestat  ;Point to status line message
   call print_statline  ;Print it
   ret
navmode_objs:
   db 0h, 15h, 08h, '+Sec', 0h
   db 0h, 19h, 08h, '-Sec', 0h
   db 0h, 17h, 15h, '+Trk', 0h
   db 0h, 17h, 01h, '-Trk', 0h
   db 0h, 15h, 23h, 'First', 0h
   db 0h, 19h, 23h, 'Last', 0h
   db 1h, 16h, 09h, 'UP', 0h
   db 1h, 18h, 09h, 'DN', 0h
   db 1h, 17h, 06h, 'LF', 0h
   db 1h, 17h, 12h, 'RT', 0h
   db 1h, 16h, 24h, 'HOME', 0h
   db 1h, 18h, 24h, 'END', 0h
   db 0ffh
nav_modestat:
   db 'MODE: Sector Navigation'
   db 0h
;
;
;Print editing controls
;
print_editmode:
   call clear_navzone
   lxi d, editmode_objs ;Point to object list
   call print_objects   ;Print it
   lxi d, edit_modestat ;Point to status line message
   call print_statline  ;Print it
   ret
editmode_objs:
   db 0h, 15h, 08h, '-Row', 0h
   db 0h, 19h, 08h, '+Row', 0h
   db 0h, 17h, 15h, '+Col', 0h
   db 0h, 17h, 01h, '-Col', 0h
   db 0h, 15h, 23h, 'First', 0h
   db 0h, 19h, 23h, 'Last', 0h
   db 1h, 16h, 09h, 'UP', 0h
   db 1h, 18h, 09h, 'DN', 0h
   db 1h, 17h, 06h, 'LF', 0h
   db 1h, 17h, 12h, 'RT', 0h
   db 1h, 16h, 24h, 'HOME', 0h
   db 1h, 18h, 24h, 'END', 0h
   db 0ffh
edit_modestat:
   db 'MODE: Sector Editing'
   db 0h
;
;
;Clear the navigation button area
;
clear_navzone
   mvi a, 15h            ;Start line of nav control area
   mvi e, 31h            ;Center screen column
print_nz01:
   push psw              ;Store it on the stack
   mov d, a              ;put it in D
   call move_cursor      ;Move cursor
   call clear_cursor_bol ;Clear line to left of cursor
   pop psw               ;Get line from stack
   adi 1h                ;Next line
   daa                   ;Decimal adjust it
   cpi 20h               ;End of nav section?
   jnz print_nz01        ;If not do again
   ret
;
;
;Clear the navigation function area
;
clear_nav_funzone
   mvi a, 15h            ;Start line of nav function area
   mvi e, 31h            ;Center screen column
print_fnz01:
   push psw              ;Store it on the stack
   mov d, a              ;put it in D
   call move_cursor      ;Move cursor
   call clear_cursor_eol ;Clear line to right of cursor
   pop psw               ;Get line from stack
   adi 1h                ;Next line
   daa                   ;Decimal adjust it
   cpi 18h               ;End of nav section?
   jnz print_fnz01       ;If not do again
   ret
;
;
;Clear the sub-function area
;
clear_nav_subfunzone
   mvi a, 19h            ;Start line of sub-function area
   mvi e, 31h            ;Start of screen area
print_sfz01:
   push psw              ;Store it on the stack
   mov d, a              ;put it in D
   call move_cursor      ;Move cursor
   call clear_cursor_eol ;Clear line to right of cursor
   pop psw               ;Get line from stack
   adi 1h                ;Next line
   daa                   ;Decimal adjust it
   cpi 23h               ;End of nav section?
   jnz print_sfz01       ;If not do again
   ret
;
;
;Print Status Line Message
print_statline
   call set_normal   ;Set normal intensity
   xchg              ;Swap DE and HL
   lxi d, 2501h      ;Point to mode text
   call move_cursor  ;Move cursor
   call set_reverse  ;Set for reverse video
   call clear_line   ;Clear the line
   xchg              ;Swap DE and HL
   call print_string ;Print it
   mvi b, 57
   call print_space  ;Print spaces
   call set_normal   ;Set normal intensity
   ret
;
;
;Print disk buffer
;
print_buffer:        ;Print the contents of the sector buffer
   call hide_cursor  ;Turn off the cursor
   lxi h, secbuf     ;Point to the sector buffer
   shld current_buf  ;save buffer pointer
   lxi h, 0601h      ;Row and column cursor start position
   shld current_pos  ;Save cursor row/col position
   mvi a,0h          ;Clear line counter
pb001:
   sta current_line  ;Save it in the line counter
   xchg              ;Put cursor position in DE   
   call move_cursor  ;Move to column header position
   call print_bufhex ;Print line of hex bytes from the sector buffer
   lhld current_pos  ;Get current position
   mvi l, 58h        ;Move cursor right
   shld current_pos  ;Save cursor row/col position
   xchg              ;Put cursor position in DE   
   call move_cursor  ;Move to column header position
   call print_buftxt ;Print line of ascii bytes from the sector buffer
   lhld current_buf  ;Get current buffer position
   lxi d, 10h        ;Get buffer offset
   dad d             ;Add to current buffer position
   shld current_buf  ;Store in current buffer position
   lhld current_pos  ;Get current screen position
   mov a, h          ;Put line number in A
   inr a             ;Point to next line
   daa               ;Decimal adjust it
   mov h, a          ;Put it back in H
   mvi l, 1          ;Point to first column
   shld current_pos  ;Save it
   lda current_line  ;Get current line
   inr a             ;Next line
   cpi 8h            ;Last line?
   jnz pb001         ;Do next line   
   ret
;
;
;Print one line of buffer in hex
;Depends on displayed row/col and buffer line variables
;
print_bufhex:
   mvi c, 0h         ;Get offset prefix
   call print_hex    ;Print it
   lda current_line  ;Get current line counter
   rlc               ;Move into high nibble
   rlc
   rlc
   rlc
   mov c, a          ;Put it in C
   call print_hex    ;Print it
   mvi c, ' '        ;Space
   call print_chr    ;Print it
   call print_chr    ;Again
   lhld current_buf  ;Get current buffer position
   mvi a, 10h        ;Set column counter
   sta current_col   ;Get column counter
pbh001:
   mov c, m          ;Get character from buffer
   call print_hex    ;Print hex byte
   lda current_col   ;Get column counter
   dcr a             ;Count down
   sta current_col   ;Save it
   cpi 8h            ;Time for extra space?
   jz pbh002         ;If so then print spacer
   cpi 0             ;End of line?
   rz                ;Exit
   mvi c, ' '        ;Spacer
   call print_chr    ;Print space
   jmp pbh003        ;Test for next
pbh002:
   lxi d, sector_spacer ;Point to spacer string
   call print_string ;Print it
pbh003:
   inx h             ;Point to next buffer character
   jmp pbh001        ;If not zero do it again
sector_spacer:
   db   ' - '
   db   0h
;
;
;Print one line of buffer in ascii
;Depends on displayed row/col and buffer line variables
;
print_buftxt:
   lhld current_buf  ;Get current buffer position
   mvi a, 10h        ;Set column counter
   sta current_col   ;Get column counter
pbt001:
   mov c, m          ;Get character from buffer
   call print_chr    ;Print ascii character
   inx h             ;Point to next buffer character
   lda current_col   ;Get column counter
   dcr a             ;Count down
   sta current_col   ;Save it
   cpi 0             ;End of line?
   jnz pbt001        ;If not do it again
   ret
;
;
;Print objects on screen
;DE points to object in RAM
;   db attribute (00 = normal, 01=intense, 02=reverse, 03=blink)
;   dw cursor_pos (row, col)
;   db string (....)
;   db 0
;   db ffh <End of list
;Modifies a, c, de, hl
print_objects:
   ldax d              ;Get attribute
print_obj01:
   cpi 0               ;Normal intensity?
   jz print_objnormal  ;Default.  Set it just in case
   cpi 1               ;High intensity?
   jz print_objhigh    ;Set it
   cpi 2               ;reverse video?
   jz print_objinv     ;Set it
   cpi 3               ;Blinking?
   jz print_objblink   ;Set it
   jmp print_objnormal ;If invalid, set normal  
print_objhigh:
   call set_intense    ;Set high intensity
   jmp print_objcursor ;Set cursor position
print_objinv:
   call set_reverse    ;Set high intensity
   jmp print_objcursor ;Set cursor position
print_objblink:
   call set_blinking   ;Set high intensity
   jmp print_objcursor ;Set cursor position
print_objnormal:
   call set_normal     ;Default intensity
print_objcursor:
   inx d               ;Point to cursor row
   ldax d              ;Get it
   mov h, a            ;Put it in H
   inx d               ;Point to cursor col
   ldax d              ;Get it
   mov l, a            ;Put it in L
   xchg                ;Swap DE and HL
   call move_cursor    ;Move the cursor
   xchg                ;Swap DE and HL
print_objtext:
   inx d               ;Point to text
   call print_string   ;Print it
   inx d               ;Point to next object (if exists)
   ldax d              ;Check for object terminator
   cpi 0ffh             ;Is it end of list
   jnz print_obj01     ;Do next object                
   ret
;
;
;Print number of spaces in B register
;Modifies a, b, c
print_space:
   mvi c, ' '        ;Space character
pspc001:
   call conout       ;Send it       
   dcr b             ;Decrement count
   jnz pspc001       ;Repeat until count is zero
   ret   
;
;
;Print message string pointed to by D
;Modifies: a, c, de
print_string:
	ldax d           ;Get char pointed to by D into A
	cpi 0            ;End of string?
	jz psend         ;Exit if end of string
	mov c, a         ;Move char into C for console out
	call conout      ;Print it
	inx d            ;Point to next character
	jmp print_string ;Repeat
psend:
	ret              ;And exit
;
;
;Print hex byte in C
;Modifies: a
print_hex:
    push b           ;Save BC on the stack
    mov a, c         ;Put character in A
    rrc              ;Shift upper digit to lower position
    rrc
    rrc
    rrc
    mov c, a         ;Put A in C
    call print_dig   ;Print hex digit
	pop b            ;Get BC from the stack
    call print_dig   ;Print hex digit
    ret              ;Exit
;
;
;Print single hex digit in low nibble of C
;Modifies: a
print_dig:
    mov a, c         ;Move C into A
    ani 0fh          ;Mask high bits
    cpi 0ah          ;Is it > 9?
    jnc ph_adig      ;Print A-F
    adi 30h          ;Make ascii 0-9
    jmp ph_ndig      ;Print hex digit
ph_adig
    adi 37h          ;Make ascii A-F
ph_ndig
    push b           ;Save BC
    mov c, a         ;Move A into C
    call conout      ;Print it
	pop b            ;Restore BC
    ret
;
;
;Print printable character in C with '.' for non-printable
;Modifies: a
print_chr:
   mov a, c          ;Move C into A
   cpi 20h           ;Is it lower non-print?
   jc pc_nonprint    ;Change it to a '.'
   cpi 7fh           ;Is it upper non-print?
   jnc pc_nonprint   ;Change it to a '.'
pc_print:
   push b            ;Save BC
   mov c, a          ;Move A into C
   call conout       ;Print it
   pop b             ;Restore BC
   ret
pc_nonprint:
   mvi a, '.'        ;Change it to printable
   jmp pc_print      ;Print it
;
;
;Print new line
;Modifies: c
print_nl:
   mvi c, 0dh        ;Carriage return
   call conout       ;Print it
   mvi c, 0ah        ;Line feed
   call conout       ;Print it
   ret               ;Exit
;
;
;Send CSI sequence to console
;Modifies: a, c 
print_csi:
   mvi c, 1bh        ;Escape character
   call conout       ;Print it
   mvi c, '['        ;Bracket character
   call conout       ;Print it
   ret               ;Exit
;
;
;Clear screen
;Modifies: a (other call), c
clear_screen:
   call print_csi    ;Print CSI sequence
   mvi c, '2'        ;First character
   call print_chr    ;Print it
   mvi c, 'J'        ;Erase display
   call print_chr    ;Print it
   call print_csi    ;Print CSI sequence
   mvi c, 'H'        ;Home cursor
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Clear from cursor to bottom of screen
;Modifies: a (other call), c
clear_screen_fromcursor:
   call print_csi    ;Print CSI sequence
   mvi c, '0'        ;First character
   call print_chr    ;Print it
   mvi c, 'J'        ;Erase display
   call print_chr    ;Print it
   call print_csi    ;Print CSI sequence
   mvi c, 'H'        ;Home cursor
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Clear from top of screen to cursor
;Modifies: a (other call), c
clear_screen_tocursor:
   call print_csi    ;Print CSI sequence
   mvi c, '1'        ;First character
   call print_chr    ;Print it
   mvi c, 'J'        ;Erase display
   call print_chr    ;Print it
   call print_csi    ;Print CSI sequence
   mvi c, 'H'        ;Home cursor
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Clear line
;Modifies c
clear_line:
   call print_csi    ;Print CSI sequence
   mvi c, '2'        ;First character
   call print_chr    ;Print it
   mvi c, 'K'        ;Erase display
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Clear line from cursor to end of line
;Modifies c
clear_cursor_eol:
   call print_csi    ;Print CSI sequence
   mvi c, 'K'        ;Erase display
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Clear line from beginning of line to cursor
;Modifies c
clear_cursor_bol:
   call print_csi    ;Print CSI sequence
   mvi c, '1'        ;First character
   call print_chr    ;Print it
   mvi c, 'K'        ;Erase display
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Move cursor to row/column in D
;Use BCD for row and column positions
;Modifies: a (other call), c
move_cursor:
   call print_csi    ;Print CSI sequence
   mov c, d          ;Move row position into C
   call print_hex    ;Print row position in ascii
   mvi c, ';'        ;Get row/col separator
   call print_chr    ;Print it
   mov c, e          ;Move col position into A
   call print_hex    ;Print col position in ascii
   mvi c, 'H'        ;Cursor move terminator
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Move cursor one line up
;Modifies c
move_cursor_up:
   call print_csi    ;Print CSI sequence
   mvi c, 'A'        ;Cursor move terminator
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Move cursor one line down
;Modifies c
move_cursor_down:
   call print_csi    ;Print CSI sequence
   mvi c, 'B'        ;Cursor move terminator
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Move cursor one place to the right
;Modifies c
move_cursor_right:
   call print_csi    ;Print CSI sequence
   mvi c, 'C'        ;Cursor move terminator
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Move cursor one place to the left
;Modifies c
move_cursor_left:
   call print_csi    ;Print CSI sequence
   mvi c, 'D'        ;Cursor move terminator
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Hide cursor
;Modifies c
hide_cursor:
   call print_csi    ;Print CSI sequence
   mvi c, '?'        ;Control char
   call print_chr    ;Print it
   mvi c, '2'        ;Control char
   call print_chr    ;Print it
   mvi c, '5'        ;Control char
   call print_chr    ;Print it
   mvi c, 'l'        ;Control char
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Show cursor
;Modifies c
show_cursor:
   call print_csi    ;Print CSI sequence
   mvi c, '?'        ;Control char
   call print_chr    ;Print it
   mvi c, '2'        ;Control char
   call print_chr    ;Print it
   mvi c, '5'        ;Control char
   call print_chr    ;Print it
   mvi c, 'h'        ;Control char
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Erase from cursor to end of screen
;Modifies c
erase_cursor:
   call print_csi    ;Print CSI sequence
   mvi c, 'J'        ;Control char
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Turn wraparound off
;Modifies c
linewrap_off:
   call print_csi    ;Print CSI sequence
   mvi c, '?'        ;Control char
   call print_chr    ;Print it
   mvi c, '7'        ;Control char
   call print_chr    ;Print it
   mvi c, 'l'        ;Control char
   call print_chr    ;Print it
   ret
;
;
;Turn wraparound on
;Modifies c
linewrap_on:
   call print_csi    ;Print CSI sequence
   mvi c, '?'        ;Control char
   call print_chr    ;Print it
   mvi c, '7'        ;Control char
   call print_chr    ;Print it
   mvi c, 'h'        ;Control char
   call print_chr    ;Print it
   ret
;
;
;Change to reverse video
;Modifies c
set_reverse:
   call print_csi    ;Print CSI sequence
   mvi c, '7'        ;reverse video attribute
   call print_chr    ;Print it
   mvi c, 'm'        ;Set attribute
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Change to intense video
;Modifies c
set_intense:
   call print_csi    ;Print CSI sequence
   mvi c, '1'        ;Intense video attribute
   call print_chr    ;Print it
   mvi c, 'm'        ;Set attribute
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Change to normal video
;Modifies c
set_normal:
   call print_csi    ;Print CSI sequence
   mvi c, '0'        ;Reset video attribute
   call print_chr    ;Print it
   mvi c, 'm'        ;Set attribute
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Change to underline video
;Modifies c
set_underline:
   call print_csi    ;Print CSI sequence
   mvi c, '4'        ;Underline video attribute
   call print_chr    ;Print it
   mvi c, 'm'        ;Set attribute
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Change to blinking video
;Modifies c
set_blinking:
   call print_csi    ;Print CSI sequence
   mvi c, '5'        ;Blink video attribute
   call print_chr    ;Print it
   mvi c, 'm'        ;Set attribute
   call print_chr    ;Print it
   ret               ;Exit
;
;
;Get printable character
get_char
   call conin        ;Get single character from console
   cpi ' '           ;Less than ' '?
   rc                ;Return if < ' ' with carry set
   lhld current_buf  ;Point to sector buffer position
   mov m, a          ;Store it in sector buffer
   xra a             ;Clear A before return
   ret               ;Exit
;
;
;Edit byte value and put in sector buffer
;Assumes cursor is at start position (far left) of byte to be edited
;Assumes current_buf is address of byte to be edited
edit_hex:
   call get_hexdigit ;Get hex digit
   rc                ;If invalid then exit
   rlc               ;Move digit into high bits
   rlc
   rlc
   rlc
   mov b, a          ;Save A in B
   call get_hexdigit ;Get hex digit (low bits)
   rc                ;If invalid then exit
   add b             ;Add in high bits
   lhld current_buf  ;Point to sector buffer position
   mov m, a          ;Store it in sector buffer
   xra a             ;Clear A before return
   ret               ;Exit
;
;
;Get hex byte from console with echo into A
;Modifies a, b, c
get_hexbyte:
   call get_hexdigit ;Get hex digit (high bits)
   jc get_hexbyte    ;If invalid try again
   rlc               ;Move digit into high bits
   rlc
   rlc
   rlc
   mov b, a          ;Save A in B
get_hexbyt01:
   call get_hexdigit ;Get hex digit (low bits)
   jc get_hexbyt01   ;If invalid try again
   add b             ;Add in high bits
   ret               ;Exit
;
;
;Get single hex digit from console with echo
;Convert from ascii to binary in A
;Modifies a, c
get_hexdigit:
   call conin        ;Get single character from console
   cpi '0'           ;Less than '0'?
   rc                ;Return if < 0 with carry set
   cpi ':'           ;Greater than '9'?
   jnc get_hexdig01  ;If so, check for A-F
   mov c, a          ;Put A into C
   call conout       ;Print it
   mov a, c          ;Put C into A
   sui '0'           ;Make ascii 0-9 into binary 0-9
   ret               ;Return hex character, no carry
get_hexdig01:
   ani 0dfh          ;Make it upper case
   cpi 'A'           ;Less than 'A'?
   rc                ;Return if less with carry set
   cpi 'G'           ;Greater than 'F'?
   jc get_hexdig02   ;If not convert to binary
   stc               ;Else, set carry
   ret               ;Return invalid key, carry set
get_hexdig02:
   mov c, a          ;Put C into A
   call conout       ;Print it
   mov a, c          ;Put C back in A
   sui 37h           ;Make ascii A-F into binary A-F
   ret               ;Return hex character, no carry
;
;
;Decimal adjust on subtraction
;Good for positive results only.  B=minuend, C=subtrahend
;Adjusted result in B
;Modifies a, b
sub_daa:
   mov a, b
   sub c
   mov b, a
   ani 0fh
   cpi 0ah
   jnc sub_daa01
   ret
sub_daa01:
   mov a, b
   sbi 6h
   mov b, a
   ret
;
;
;Flush Console
;Checks to see if a character is waiting on the console
;and if so dumps that character
flush_console:
   call const        ;Flush console if character present
   rz                ;Return if no character
   call conin        ;Get character but don't process it
   ret
;
;
;Program variables
;
current_line   ds 1   ;Line counter
current_col    ds 1   ;Column counter
current_pos    ds 2   ;Current hex displayed row/col
current_tpos   ds 2   ;Current text displayed row/col
current_buf    ds 2   ;Current displayed buffer line
current_drive  ds 1   ;Current displayed drive
current_track  ds 1   ;Current displayed track
current_sector ds 1   ;Current displayed sector
current_block  ds 2   ;Current displayed block
current_emode  ds 1   ;Current edit mode (0=hex, 1=text)
;
;
;Sector buffer
;
secbuf ds 128

