0x100 byte bare metal hex editor
return

One of the first remotely substantial things I wrote in 16-bit x86 assembly, happened to be exactly 256 bytes (minus the padding + boot signature). I would do things quite a bit differently now, but it’s fun to look back on..

Maybe I’ll rewrite it someday.

; nasm hexedit.asm -o hexedit
; qemu-system-i386 -drive format=raw,file=hexedit
;
; to measure file size without the signature, comment out the last two lines.
;
; controls:
; hjkl move cursor
; e edit at cursor (esc to exit)
; g move cursor to address
; x execute code at cursor

bits 16
org 7C00h

push 0x7c00
start:
pop si

; set vga 80x25 text mode
mov ax, 0x0002
int 0x10
; hide cursor
mov ah, 1
mov cx, 2607h
int 0x10

main_loop:
call draw_screen

; read key
xor ah, ah
int 0x16

; cursor left
cmp al, 'h'
jne .next_1
dec si
.next_1:
; cursor down
cmp al, 'j'
jne .next_2
add si, 16
.next_2:
; cursor up
cmp al, 'k'
jne .next_3
sub si, 16
.next_3:
; cursor right
cmp al, 'l'
jne .next_4
inc si
.next_4:
; edit memory
cmp al, 'e'
jne .next_5
call edit_mode
.next_5:
; goto addr
cmp al, 'g'
jne .next_6
call goto_addr
.next_6:
; execute code at cursor
cmp al, 'x'
jne .next_7
push si
push start
jmp si

.next_7:
; reset mode indicator
mov BYTE [es:79*2], ' '
jmp main_loop

; al - ascii hex digit -> nibble
x_digit:
sub al, '0'
x_digit_sub:
cmp al, 10
jl .is_not_x
add al, 10 - ('a' - '0')
.is_not_x:
ret

edit_mode:
mov WORD [es:79*2], (0xF << 8) | 'E'

.loop:
call read_hex_byte
test ah, ah
jz .continue

ret

.continue:
mov [si], al
inc si
call draw_screen
jmp .loop

goto_addr:
mov WORD [es:79*2], (0xF << 8) | 'G'
call read_hex_byte
xchg dh, al
call read_hex_byte
xchg dl, al
mov si, dx
ret

; ah - nonzero on fail
; al - byte read
read_hex_byte:
; read byte
xor ah, ah
int 0x16

sub al, '0'
jns .continue
ret
.continue:
call x_digit_sub
xchg bl, al

xor ah, ah
int 0x16
call x_digit

shl bl, 4
add al, bl
xor ah, ah
ret

; al - nibble
; ah - style
put_vga_nibble:
add al, '0'
cmp al, '0' + 10
jl .is_not_x
add al, 'A' - '0' - 10
.is_not_x:
stosw
ret

; al - byte
; ah - style
put_vga_byte:
mov bl, al

shr al, 4
call put_vga_nibble

xchg bl, al
and al, 0xF
call put_vga_nibble

ret

; si = src addr
draw_screen:
push 0xB800
pop es

mov bp, si
and si, 0xFFF0
sub si, 16*12

; vga dest ptr
mov di, 0
mov cx, 25

.draw_row:
mov dx, si
xchg al, dh
mov ah, 0x3
call put_vga_byte
xchg al, dl
call put_vga_byte

add di, 4

xchg cx, dx
mov cx, 16

.draw_char:
cmp bp, si
sete ah
add ah, ah

lodsb
add ah, 7

call put_vga_byte
add di, 2
loop .draw_char

add di, 52
xchg cx, dx
loop .draw_row

mov si, bp

ret

times 510-($-$$) db 0
dw 0xAA55