From 3ca4ce76f0e1700a136a9eb93fea10a3b4b35027 Mon Sep 17 00:00:00 2001 From: Tibo Date: Mon, 4 Oct 2021 17:59:48 +0200 Subject: [PATCH 1/2] add documentation --- messages.asm | 281 +++++++++++++++++++++++++++------------------------ 1 file changed, 150 insertions(+), 131 deletions(-) diff --git a/messages.asm b/messages.asm index 17f188c..6446158 100644 --- a/messages.asm +++ b/messages.asm @@ -1,9 +1,11 @@ -org 0x7C00 -bits 16 +org 0x7C00 ; The boot code on a drive always gets loaded at address 0x7C00 +bits 16 ; .bin defaults to 16 bits -WIDTH equ 0x50 -HEIGHT equ 0x18 -VIDEO_MODE equ 0x3 +;; FIXME: possible problem with HEIGHT being defined +;; as one less than what VIDEO_MODE implies? +WIDTH equ 0x50 ; 60 +HEIGHT equ 0x18 ; 24 (?) +VIDEO_MODE equ 0x3 ; 80x25 screen, text mode ;; see http://www.ctyme.com/intr/int-10.htm for interrupts @@ -13,173 +15,190 @@ mov ax, VIDEO_MODE int 10h ;; Clear screen -mov ah, 0x06 -mov al, 0x00 -mov bh, 0x0F -mov cx, 0x0000 -mov dh, HEIGHT -mov dl, WIDTH +mov ah, 0x06 ; scroll screen up +mov al, 0x00 ; lines to scroll (0 = clear) +mov bh, 0x0F ; bg/fg colour +mov cx, 0x0000 ; upper row number, left col number (both 0) +mov dh, HEIGHT ; lower row number (24) +mov dl, WIDTH ; right col number (80) int 0x10 ;; Set cursor to bottom of screen -mov dh, HEIGHT -mov dl, 0x00 -mov bh, 0x00 -mov ah, 0x02 +mov ah, 0x02 ; set cursor position +mov bh, 0x00 ; page number +mov dh, HEIGHT ; row (bottommost row) +mov dl, 0x00 ; col (leftmost col) int 0x10 -mov sp, 0x2000 + +mov sp, 0x2000 ; initialise stack pointer .loop: - ;; Read character - mov ah, 0x00 - int 0x16 + mov ah, 0x00 ; Read character + int 0x16 - cmp al, 0x0d ; newline - je .newline - cmp al, 0x08 ; delete character - je .change_color_mode - cmp al, 0x1b ; escape character - je .beep - jmp .nonewline + cmp al, 0x0d ; newline + je .newline + + cmp al, 0x08 ; delete character + je .change_color_mode + + cmp al, 0x1b ; escape character + je .beep + + jmp .nonewline .change_color_mode: - call .readbyte - mov [color_mode], al - jmp .loop + call .readbyte + mov [color_mode], al + jmp .loop .newline: - ;; Scroll up window - mov ah, 0x06 - mov al, 0x01 - mov bh, 0x0F - mov cx, 0x0000 - mov dh, HEIGHT - mov dl, WIDTH - int 0x10 + ;; Scroll up window + mov ah, 0x06 + mov al, 0x01 + mov bh, 0x0F + mov cx, 0x0000 + mov dh, HEIGHT + mov dl, WIDTH + int 0x10 - ;; Get current cursor position - mov bh, 0x00 - mov ah, 0x03 - int 0x10 + ;; Get current cursor position + mov bh, 0x00 + mov ah, 0x03 + int 0x10 - ;; Move cursor to beginning of screen - mov dl, 0x00 - mov ah, 0x02 - int 0x10 + ;; Move cursor to beginning of screen + mov dl, 0x00 + mov ah, 0x02 + int 0x10 - jmp .loop + jmp .loop .beep: - call .readduration - mov ah, 0 - push ax - mov al, 182 ; Prepare the speaker for the - out 43h, al ; note. - call .readbyte - mov ah, 0 - sal ax, 5 ; multiply by 32 - add ax, 1140 - out 42h, al ; Output low byte. - mov al, ah ; Output high byte. - out 42h, al - in al, 61h ; Turn on note (get value from - ; port 61h). - or al, 00000011b ; Set bits 1 and 0. - out 61h, al ; Send new value. - ;; mov bx, 50000 ; Pause for duration of note. - pop bx - push ax - mov ax, 3125 - mul bx - mov bx, ax - pop ax + call .readduration + mov ah, 0 + push ax + mov al, 182 ; Prepare the speaker for the + out 43h, al ; note. + call .readbyte + mov ah, 0 + sal ax, 5 ; multiply by 32 + add ax, 1140 + out 42h, al ; Output low byte. + mov al, ah ; Output high byte. + out 42h, al + in al, 61h ; Turn on note (get value from + ; port 61h). + or al, 00000011b ; Set bits 1 and 0. + out 61h, al ; Send new value. + ;; mov bx, 50000 ; Pause for duration of note. + pop bx + push ax + mov ax, 3125 + mul bx + mov bx, ax + pop ax .pause1: - mov cx, 65535 + mov cx, 65535 .pause2: - dec cx - jne .pause2 - dec bx - jne .pause1 - in al, 61h ; Turn off note (get value from - ; port 61h). - and al, 11111100b ; Reset bits 1 and 0. - out 61h, al ; Send new value. - jmp .loop + dec cx + jne .pause2 + dec bx + jne .pause1 + in al, 61h ; Turn off note (get value from + ; port 61h). + and al, 11111100b ; Reset bits 1 and 0. + out 61h, al ; Send new value. + jmp .loop .nonewline: - ;; Write character + ;; Write character mov ah, 0x09 - mov bh, 0x00 - mov bl, [color_mode] - mov cx, 0x01 + mov bh, 0x00 + mov bl, [color_mode] + mov cx, 0x01 int 0x10 - ;; Get current cursor position - mov ah, 0x03 - int 0x10 + ;; Get current cursor position + mov ah, 0x03 + int 0x10 - cmp dl, WIDTH - jge .eol - jmp .noeol + cmp dl, WIDTH + jge .eol + jmp .noeol .eol: - ;; Scroll up window - mov ah, 0x06 - mov al, 0x01 - mov bh, 0x0F - mov cx, 0x0000 - mov dh, HEIGHT - mov dl, WIDTH - int 0x10 + ;; Scroll up window + mov ah, 0x06 + mov al, 0x01 + mov bh, 0x0F + mov cx, 0x0000 + mov dh, HEIGHT + mov dl, WIDTH + int 0x10 - ;; Move cursor to beginning of screen - mov bh, 0 - mov dh, HEIGHT - mov dl, 0x00 - mov ah, 0x02 - int 0x10 - jmp .loop + ;; Move cursor to beginning of screen + mov bh, 0 + mov dh, HEIGHT + mov dl, 0x00 + mov ah, 0x02 + int 0x10 + jmp .loop .noeol: - ;; Move cursor forward - inc dl - mov ah, 0x02 - int 0x10 - jmp .loop - + ;; Move cursor forward + inc dl + mov ah, 0x02 + int 0x10 + jmp .loop +;; Reads two characters from the keyboard buffer and converts them into a single byte +;; +;; The conversion happens as follows: +;; ASCII 'a' is subtracted from each character (so 'a' = 0, 'b' = 1, ...) +;; the first character is shifted left by 4 +;; the shifted and non-shifted values are then or'ed together to form a byte +;; +;; CLOBBERS +;; - ax +;; - bl .readbyte: - ;; Read character - mov ah, 0x00 - int 0x16 - ;; Read character is in al - sub al, 'a' - mov bl, al - shl bl, 0x4 + mov ah, 0x00 ; Read character + int 0x16 - ;; Read character - mov ah, 0x00 - int 0x16 - ;; Read character is in al - sub al, 'a' - or al, bl - ret + ;; Read character is in al + sub al, 'a' ; Normalise + mov bl, al + shl bl, 0x4 ; First character is upper 4 bits + + mov ah, 0x00 ; Read character + int 0x16 + + ;; Read character is in al + sub al, 'a' ; Normalise + + or al, bl ; Combine both characters + + ret .readduration: - ;; Read duration (0-16 supported) - mov ah, 0x00 - int 0x16 - ;; Read character is in al - sub al, 'a' - ret + ;; Read duration (0-16 supported) + mov ah, 0x00 + int 0x16 + ;; Read character is in al + sub al, 'a' + ret halt: hlt color_mode: db 0x02 +;; Magic number must be in the last 2 bytes of the sector so +;; fill the binary with zeroes until it is 510 bytes in size +;; (magic number will use up the remaining 2) times 510 - ($ - $$) db 0 -dw 0xAA55 +dw 0xAA55 ;; Magic number to mark sector as bootable From 0a66a89beb48ef7296ae47fdf486e02f320a5fc8 Mon Sep 17 00:00:00 2001 From: Tibo Date: Mon, 4 Oct 2021 21:00:30 +0200 Subject: [PATCH 2/2] add documentation and minor refactoring --- messages.asm | 228 ++++++++++++++++++++++++++++++--------------------- 1 file changed, 136 insertions(+), 92 deletions(-) diff --git a/messages.asm b/messages.asm index 6446158..5b863c2 100644 --- a/messages.asm +++ b/messages.asm @@ -1,11 +1,12 @@ org 0x7C00 ; The boot code on a drive always gets loaded at address 0x7C00 bits 16 ; .bin defaults to 16 bits -;; FIXME: possible problem with HEIGHT being defined -;; as one less than what VIDEO_MODE implies? -WIDTH equ 0x50 ; 60 -HEIGHT equ 0x18 ; 24 (?) -VIDEO_MODE equ 0x3 ; 80x25 screen, text mode +WIDTH equ 0x4F ; 79 +HEIGHT equ 0x18 ; 24 +VIDEO_MODE equ 0x3 ; 80x25 screen, text mode + +PIT_MODECOMMAND_PORT equ 0x43 ; programmable interval timer mode/command port (used for speaker) +PIT_CH2_DATA_PORT equ 0x42 ; PIT channel 2 data port ;; see http://www.ctyme.com/intr/int-10.htm for interrupts @@ -33,128 +34,160 @@ int 0x10 mov sp, 0x2000 ; initialise stack pointer .loop: - mov ah, 0x00 ; Read character + mov ah, 0x00 ; Read a character int 0x16 - cmp al, 0x0d ; newline - je .newline + cmp al, 0x08 ; backspace + je change_color_mode - cmp al, 0x08 ; delete character - je .change_color_mode + cmp al, 0x1b ; esc + je beep - cmp al, 0x1b ; escape character - je .beep + cmp al, 0x0d ; enter + je .nl - jmp .nonewline + jmp nonewline ; all other characters -.change_color_mode: - call .readbyte - mov [color_mode], al +.nl: + call newline jmp .loop -.newline: - ;; Scroll up window - mov ah, 0x06 - mov al, 0x01 - mov bh, 0x0F - mov cx, 0x0000 - mov dh, HEIGHT - mov dl, WIDTH - int 0x10 +;; Update the color_mode variable with a byte from the keyboard +;; +;; CLOBBERS +;; - ax +;; - bl +change_color_mode: + call readbyte ; get byte from keyboard (in al) + mov [color_mode], al ; store byte in color_mode variable - ;; Get current cursor position - mov bh, 0x00 - mov ah, 0x03 + jmp start.loop + +;; Simulates going to a new line +;; +;; CLOBBERS +;; - ax +;; - bh +;; - cx +;; - dx +newline: + ;; Scroll up window + mov ah, 0x06 ; scroll screen up + mov al, 0x01 ; lines to scroll (1) + mov bh, 0x0F ; bg/fg colour + mov cx, 0x0000 ; upper row num/left col num (both 0) + mov dh, HEIGHT ; lower row num (24) + mov dl, WIDTH ; right col num (80) int 0x10 ;; Move cursor to beginning of screen - mov dl, 0x00 - mov ah, 0x02 + mov ah, 0x02 ; set cursors position + mov bh, 0x0 ; page number + mov dh, HEIGHT ; row + mov dl, 0x00 ; col int 0x10 - jmp .loop + ret -.beep: - call .readduration +;; Plays a note on the speaker for a given duration +;; +;; CLOBBERS +;; - ax +;; - bx +;; - cx +beep: + call read_duration ; get duration from keyboard (in al) mov ah, 0 - push ax - mov al, 182 ; Prepare the speaker for the - out 43h, al ; note. - call .readbyte - mov ah, 0 - sal ax, 5 ; multiply by 32 + push ax ; store on stack + + ;; move 182 (0b10 11 011 0) into al + ;; bit 7-6 = channel select (2, PC speaker) + ;; bit 5-4 = access mode (lobyte/hibyte) + ;; bit 3-1 = operating mode (square wave generator) + ;; bit 0 = BCD/binary mode (16-bit binary) + mov al, 0b10110110 + out PIT_MODECOMMAND_PORT, al ; write to PIT control port + + ;; Read byte and convert to a usable frequency + call readbyte ; read byte from keyboard (in al) + mov ah, 0 ; readbyte clobbers ax + sal ax, 5 ; multiply by 32 add ax, 1140 - out 42h, al ; Output low byte. - mov al, ah ; Output high byte. - out 42h, al - in al, 61h ; Turn on note (get value from - ; port 61h). - or al, 00000011b ; Set bits 1 and 0. - out 61h, al ; Send new value. + + out PIT_CH2_DATA_PORT, al ; Output low byte. + mov al, ah + out PIT_CH2_DATA_PORT, al ; Output high byte + + ;; Port 0x61 does a whole lot but only the bottom 2 bits are relevant here + ;; (speaker enable and speaker input select) + in al, 61h ; Preserve previous value + or al, 00000011b ; Set bits 1 and 0 (enable speaker, input = channel 2) + out 61h, al ; Send new value + ;; mov bx, 50000 ; Pause for duration of note. - pop bx - push ax + + ;; multiply duration by 3125 + pop bx ; pull duration value from stack into bx + push ax ; save ax (contains garbage?) mov ax, 3125 - mul bx - mov bx, ax - pop ax + mul bx + mov bx, ax ; move dur * 3125 into bx + pop ax ; restore ax +;; play note for a certain duration .pause1: - mov cx, 65535 + mov ecx, 65535 .pause2: - dec cx - jne .pause2 - dec bx - jne .pause1 - in al, 61h ; Turn off note (get value from - ; port 61h). - and al, 11111100b ; Reset bits 1 and 0. - out 61h, al ; Send new value. - jmp .loop + dec cx ; count down + jne .pause2 ; if not zero keep counting down + dec bx ; decrement duration counter + jne .pause1 ; keep doing that until it is 0 -.nonewline: + in al, 61h ; Preserve previous value + and al, 11111100b ; Clear bits 1 and 0 (disable speaker, clear channel select) + out 61h, al ; Send new value + jmp start.loop + +;; Handles all other characters by writing them to the screen +;; +;; CLOBBERS +;; - ah +;; - bx +;; - cx +;; - dx +nonewline: ;; Write character - mov ah, 0x09 - mov bh, 0x00 - mov bl, [color_mode] - mov cx, 0x01 - int 0x10 + mov ah, 0x09 ; write character with attribute + mov bh, 0x00 ; page number + mov bl, [color_mode] ; BIOS colour code + mov cx, 0x01 ; amount of times to print character + int 0x10 ;; Get current cursor position - mov ah, 0x03 + ;; dh = row, dl = col + mov ah, 0x03 ; get cursor position and shape int 0x10 + ;; if the cursor is at the edge of the screen go to the next line + ;; else move it forward once cmp dl, WIDTH jge .eol jmp .noeol .eol: - ;; Scroll up window - mov ah, 0x06 - mov al, 0x01 - mov bh, 0x0F - mov cx, 0x0000 - mov dh, HEIGHT - mov dl, WIDTH - int 0x10 + call newline - ;; Move cursor to beginning of screen - mov bh, 0 - mov dh, HEIGHT - mov dl, 0x00 - mov ah, 0x02 - int 0x10 - jmp .loop + jmp start.loop .noeol: - ;; Move cursor forward inc dl - mov ah, 0x02 + mov ah, 0x02 ; set cursor position, dh (row) already set, dl (col) updated on prev line int 0x10 - jmp .loop + + jmp start.loop ;; Reads two characters from the keyboard buffer and converts them into a single byte ;; @@ -163,10 +196,13 @@ mov sp, 0x2000 ; initialise stack pointer ;; the first character is shifted left by 4 ;; the shifted and non-shifted values are then or'ed together to form a byte ;; +;; RETURNS +;; A byte in al +;; ;; CLOBBERS ;; - ax ;; - bl -.readbyte: +readbyte: mov ah, 0x00 ; Read character int 0x16 @@ -185,16 +221,24 @@ mov sp, 0x2000 ; initialise stack pointer ret -.readduration: +;; Reads a duration from the keyboard +;; +;; RETURNS +;; A duration in al +;; +;; CLOBBERS +;; - ax +read_duration: ;; Read duration (0-16 supported) - mov ah, 0x00 + mov ah, 0x00 ; read keypress int 0x16 + ;; Read character is in al - sub al, 'a' + sub al, 'a' ; normalise + ret -halt: hlt - +;; Variable to store color mode information for writing to the screen color_mode: db 0x02 ;; Magic number must be in the last 2 bytes of the sector so