diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e69de29 diff --git a/lib/dump.asm b/lib/dump.asm new file mode 100644 index 0000000..5ad8cec --- /dev/null +++ b/lib/dump.asm @@ -0,0 +1,53 @@ +dump: + push ax + push cx + push dx + push bx + mov al, 0x0A + call putc + mov al, 0x0D + call putc + mov cx, 4 +.loop_line: + push cx + push bx + mov ax, bx + call print16 + mov al, ':' + call putc + mov al, ' ' + call putc + mov cx, 0x8 +.loop_bin: + mov ax, [bx] + xchg al, ah + inc bx + inc bx + call print16 + mov dl, ' ' + call CONOUT + loop .loop_bin + pop bx + mov cx, 0x10 +.loop_ascii: + mov dl, '.' + cmp byte [bx], 0x20 + jc .print + cmp byte [bx], 0x80 + jnc .print + mov dl, [bx] +.print: + inc bx + call CONOUT + loop .loop_ascii + pop cx + mov dl, 0x0A + call CONOUT + mov dl, 0x0D + call CONOUT + loop .loop_line + pop bx + pop dx + pop cx + pop ax + ret diff --git a/lib/earlymcb.asm b/lib/earlymcb.asm new file mode 100644 index 0000000..6a12438 --- /dev/null +++ b/lib/earlymcb.asm @@ -0,0 +1,65 @@ +%define mcb_first 0x5F + +; This alloc uses an MCB-like list always starting at a fixed offset. +; Boot components may use it to allocate space during early boot. +; The list ends with the most recently allocated arena at its end, +; contrary to how the MCBs work on DOS. + +; Memory Layout: +; 0000 Interrupt table +; 0400 BIOS data area +; 05F0 16 bytes Arena header 1 +; 0600 BX paragraphs Arena 1 +; .... 16 bytes Arena header 2 +; .... BX paragraphs Arena 2 +; ... +; .... 16 bytes Arena header n +; .... BX paragraphs Arena n +; Unmanaged memory + +; Take note that this mechanism works differently than under DOS - +; but this one is optimized for fast and small alloc. + +; Typical usecases: +; - Diskette Parameter Table (See interrupt 1Eh) +; - Partition table +; - Boot sector relocations +; - Boot sector data (FAT table, rootdir) + +; Allocate paragraphs in unmanaged memory +; IN BX requested memory in paragraphs +; OUT AX output segment +early_alloc: + push ds + push bx + push si + ; si is used as zero register + ; this allows the opcodes to use a byte as disp instead of word + xor si, si + mov ax, mcb_first +.next: + mov ds, ax + inc ax + ; DS is seg of arena header + ; AX is seg of arena + cmp BYTE [si], 0x4D + jne .here + add ax, WORD [si+3] + jmp .next +.here: + ; mark as item + mov BYTE [si], 0x4D + ; write segment length in paragraphs + mov WORD [si+3], bx + ; if allocation is higher than CS, then we are in managed memory + ; set ourself as owner then, otherwise use dummy value 8 + mov bx, cs + cmp ax, bx ; CF = CS in unmanaged memory + jnc .setup_owner + mov bx, 8 +.setup_owner: + mov WORD [si+1], bx + pop si + pop bx + pop ds + ret diff --git a/lib/fcbparse.asm b/lib/fcbparse.asm new file mode 100644 index 0000000..eee48d7 --- /dev/null +++ b/lib/fcbparse.asm @@ -0,0 +1,46 @@ +; Parse ASCIIZ string into FCB +; IN SI ptr to filename +; BX ptr to FCB +fcb_parse: + push di + push ax + mov di, bx + xor ax, ax + stosb +.cleanout: + push di + mov cx, 0x0A + mov al, 0x20 + rep stosb + pop di +.base_loop: + call .read + cmp al, 0x2E + je .ext_start + cmp al, 0x20 + je .ret + stosb + jmp .base_loop +.ext_start: + mov di, bx + add di, 9 +.ext_loop: + call .read + cmp al, 0x20 + je .ret + stosb + jmp .ext_loop +.read: + lodsb + test al, al + jz .eret + cmp al, 0x0D + je .eret + ret +.eret: + dec si + pop ax +.ret: + pop ax + pop di + ret diff --git a/lib/fdc.asm b/lib/fdc.asm new file mode 100644 index 0000000..dbb21e6 --- /dev/null +++ b/lib/fdc.asm @@ -0,0 +1,14 @@ +; FDC Descriptor / BIOS parameter block +fdc_ss: equ 0x0B ; WORD sector size +fdc_sc: equ 0x0D ; BYTE sectors per cluster +fdc_rsc: equ 0x0E ; WORD reserved sectors +fdc_fn: equ 0x10 ; BYTE FAT tables +fdc_rde: equ 0x11 ; WORD root directory entries +fdc_ts: equ 0x13 ; WORD total sector count + ; 0 if >65535, use lrgts then +fdc_mi: equ 0x15 ; BYTE media descriptor byte +fdc_sf: equ 0x16 ; WORD sectors per FAT +fdc_spt: equ 0x18 ; WORD sectors per track +fdc_nos: equ 0x1A ; WORD sides/heads +fdc_po: equ 0x1C ; DWORD partition offset +fdc_lrgts: equ 0x20 ; DWORD large sector count diff --git a/lib/log2.asm b/lib/log2.asm new file mode 100644 index 0000000..b61dbd9 --- /dev/null +++ b/lib/log2.asm @@ -0,0 +1,15 @@ +; Calculate dual logarithm (int) +; IN AX number +; OUT AX dual logarithm +log2: + push cx + mov cx, 15 +.loop: + rcl ax, 1 + jc .ret + loop .loop +.ret: + cmc + mov ax, cx + pop cx + ret diff --git a/lib/nasmcomp.asm b/lib/nasmcomp.asm new file mode 100644 index 0000000..4fbebf8 --- /dev/null +++ b/lib/nasmcomp.asm @@ -0,0 +1,124 @@ +; Pseudo-Instruction: fill bytes until offset +%macro pad 1.nolist +times (%1 - ($-$$)) nop +%endmacro + +; REGISTERS +%define a al +%define b ch +%define c cl +%define d dh +%define e dl +%define h bh +%define l bl +%define m byte [bx] + +; REGISTER PAIRS +%define bc cx +%define de dx +%define hl bx + +; INSTRUCTIONS +; data movement +; 'mov' can stay literal +%define mvi mov +%define lxi mov +%macro lda 1 + mov al, byte [%1] +%endmacro +%macro sta 1 + mov byte [%1], al +%endmacro +%macro lhld 1 + mov bx, word [%1] +%endmacro +%macro shld 1 + mov word [%1], bx +%endmacro +%macro ldax 1 + mov al, byte [%1] +%endmacro +%macro stax 1 + mov byte [%1], al +%endmacro +%macro xchg 1 + xchg dx, bx +%endmacro +; addition +%macro add 1 + add al, %1 +%endmacro +%macro adi 1 + add al, %1 +%endmacro +%macro adc 1 + adc al, %1 +%endmacro +%macro aci 1 + adc al, %1 +%endmacro +; subtraction +%macro sub 1 + sub al, %1 +%endmacro +%macro sui 1 + sub al, %1 +%endmacro +%macro sbb 1 + sub al, %1 +%endmacro +%macro sbi 1 + sub al, %1 +%endmacro +; increment / decrement +%define inr inc +%define dcr dec +%define inx inc +%define dcx dec +; pointer arithmetic +%macro dad 1 + add bx, %1 +%endmacro +; 'daa' stays literal + +;ANA S 10100SSS ZSCPA AND register with A +;ANI # 11100110 db ZSPCA AND immediate with A +;ORA S 10110SSS ZSPCA OR register with A +;ORI # 11110110 ZSPCA OR immediate with A +;XRA S 10101SSS ZSPCA ExclusiveOR register with A +;XRI # 11101110 db ZSPCA ExclusiveOR immediate with A + +;CMP S 10111SSS ZSPCA Compare register with A +;CPI # 11111110 ZSPCA Compare immediate with A + +;RLC 00000111 C Rotate A left +;RRC 00001111 C Rotate A right +;RAL 00010111 C Rotate A left through carry +;RAR 00011111 C Rotate A right through carry +;CMA 00101111 - Compliment A +;CMC 00111111 C Compliment Carry flag +;STC 00110111 C Set Carry flag +;JMP a 11000011 lb hb - Unconditional jump +;Jccc a 11CCC010 lb hb - Conditional jump +;CALL a 11001101 lb hb - Unconditional subroutine call +;Cccc a 11CCC100 lb hb - Conditional subroutine call +;RET 11001001 - Unconditional return from subroutine +;Rccc 11CCC000 - Conditional return from subroutine +;RST n 11NNN111 - Restart (Call n*8) +;PCHL 11101001 - Jump to address in H:L +;PUSH RP 11RP0101 *2 - Push register pair on the stack +;POP RP 11RP0001 *2 *2 Pop register pair from the stack +;XTHL 11100011 - Swap H:L with top word on stack +;SPHL 11111001 - Set SP to content of H:L +;IN p 11011011 pa - Read input port into A +;OUT p 11010011 pa - Write A to output port +;EI 11111011 - Enable interrupts +;DI 11110011 - Disable interrupts +;HLT 01110110 - Halt processor +;NOP 00000000 - No operation + +%macro cnz 1 + jz %%skip + call near %1 +%%skip: +%endmacro diff --git a/lib/opcode80.asm b/lib/opcode80.asm new file mode 100644 index 0000000..1334f61 --- /dev/null +++ b/lib/opcode80.asm @@ -0,0 +1,142 @@ +; BYTE name length +; n BYTES name +; BYTE opcode template (variable parts zero) +; +; BYTE operand 1 +; BYTE operand 2 + +; operand types: +; 0x00 none +; 0x1n reg8, opcode |= (reg8 << n) +; 0x2n reg16, opcode |= (reg8 << n) +; 0x3n reg16b, opcode |= (reg8 << n) +; 0x7n 3-bit number, opcode |= (num << n) +; 0x80 imm8, encoded as extra byte +; 0x81 imm16, encoded as extra word + +registers: +.reg8: + db "B", 0 + db "C", 0 + db "D", 0 + db "E", 0 + db "H", 0 + db "L", 0 + db "M", 0 + db 0 +.reg16: + db "BC", 0 + db "DE", 0 + db "HL", 0 + db "SP", 0 + db 0 +.reg16b: + db "BC", 0 + db "DE", 0 + db "HL", 0 + db "AF", 0 + db 0 +.end: + db 0 + +opcodes: + ; Data movement + db 3, "MOV", 0b01000000, 0x13, 0x10 + db 3, "MVI", 0b00000110, 0x13, 0x80 + db 3, "LXI", 0b00000001, 0x24, 0x81 + db 3, "LDA", 0b00111010, 0x81, 0x00 + db 3, "STA", 0b00110010, 0x81, 0x00 + db 4, "LHLD", 0b00101010, 0x81, 0x00 + db 4, "SHLD", 0b00100010, 0x81, 0x00 + db 4, "LDAX", 0b00001010, 0x24, 0x00 + db 4, "STAX", 0b00000010, 0x24, 0x00 + db 4, "XCHG", 0b11101011, 0x00, 0x00 + + ; Addition / Subtraction + db 3, "ADD", 0b10000000, 0x10, 0x00 + db 3, "ADI", 0b11000110, 0x80, 0x00 + db 3, "ADC", 0b10001000, 0x10, 0x00 + db 3, "ACI", 0b11001110, 0x80, 0x00 + db 3, "SUB", 0b10010000, 0x10, 0x00 + db 3, "SUI", 0b11010110, 0x80, 0x00 + db 3, "SBB", 0b10011000, 0x10, 0x00 + db 3, "SBI", 0b11011110, 0x80, 0x00 + db 3, "INR", 0b00000100, 0x13, 0x00 + db 3, "DCR", 0b00000101, 0x13, 0x00 + db 3, "INX", 0b00000011, 0x24, 0x00 + db 3, "DCX", 0b00001011, 0x24, 0x00 + db 3, "DAD", 0b00001001, 0x24, 0x00 + + ; BCD + db 3, "DAA", 0b00100111, 0x00, 0x00 + + ; Bitwise operations + db 3, "ANA", 0b10100000, 0x10, 0x00 + db 3, "ANI", 0b11100110, 0x80, 0x00 + db 3, "ORA", 0b10110000, 0x10, 0x00 + db 3, "ORI", 0b11110110, 0x80, 0x00 + db 3, "XRA", 0b10101000, 0x10, 0x00 + db 3, "XRI", 0b11101110, 0x80, 0x00 + db 3, "CMP", 0b10111000, 0x10, 0x00 + db 3, "CPI", 0b11111110, 0x80, 0x00 + + ; Rotate + db 3, "RLC", 0b00000111, 0x00, 0x00 + db 3, "RRC", 0b00001111, 0x00, 0x00 + db 3, "RAL", 0b00010111, 0x00, 0x00 + db 3, "RAR", 0b00011111, 0x00, 0x00 + + ; Complement + db 3, "CMA", 0b00101111, 0x00, 0x00 + db 3, "CMC", 0b00111111, 0x00, 0x00 + db 3, "STC", 0b00110111, 0x00, 0x00 + + ; Jump + db 3, "JMP", 0b11000011, 0x81, 0x00 + db 3, "JNZ", 0b11000010, 0x81, 0x00 + db 2, "JZ", 0b11001010, 0x81, 0x00 + db 3, "JNC", 0b11010010, 0x81, 0x00 + db 2, "JC", 0b11011010, 0x81, 0x00 + db 3, "JPO", 0b11100010, 0x81, 0x00 + db 3, "JPE", 0b11101010, 0x81, 0x00 + db 2, "JP", 0b11110010, 0x81, 0x00 + db 2, "JM", 0b11111010, 0x81, 0x00 + + ; Call + db 4, "CALL", 0b11001101, 0x81, 0x00 + db 3, "CNZ", 0b11000100, 0x81, 0x00 + db 2, "CZ", 0b11001100, 0x81, 0x00 + db 3, "CNC", 0b11010100, 0x81, 0x00 + db 2, "CC", 0b11011100, 0x81, 0x00 + db 3, "CPO", 0b11100100, 0x81, 0x00 + db 3, "CPE", 0b11101100, 0x81, 0x00 + db 2, "CP", 0b11110100, 0x81, 0x00 + db 2, "CM", 0b11111100, 0x81, 0x00 + + ; Return + db 3, "RET", 0b11001001, 0x00, 0x00 + db 3, "RNZ", 0b11000000, 0x00, 0x00 + db 2, "RZ", 0b11001000, 0x00, 0x00 + db 3, "RNC", 0b11010000, 0x00, 0x00 + db 2, "RC", 0b11011000, 0x00, 0x00 + db 3, "RPO", 0b11100000, 0x00, 0x00 + db 3, "RPE", 0b11101000, 0x00, 0x00 + db 2, "RP", 0b11110000, 0x00, 0x00 + db 2, "RM", 0b11111000, 0x00, 0x00 + + db 3, "RST", 0b11000111, 0x73, 0x00 + db 4, "PCHL", 0b11101001, 0x00, 0x00 + db 4, "PUSH", 0b11000101, 0x34, 0x00 + db 3, "POP", 0b11000001, 0x34, 0x00 + db 4, "XTHL", 0b11100011, 0x00, 0x00 + db 4, "SPHL", 0b11111001, 0x00, 0x00 + + db 2, "IN", 0b11011011, 0x80, 0x00 + db 3, "OUT", 0b11010011, 0x80, 0x00 + + db 2, "EI", 0b11111011, 0x00, 0x00 + db 2, "DI", 0b11110011, 0x00, 0x00 + db 3, "HLT", 0b01110110, 0x00, 0x00 + db 3, "NOP", 0b00000000, 0x00, 0x00 + + db 0 diff --git a/lib/popcnt.asm b/lib/popcnt.asm new file mode 100644 index 0000000..d03694a --- /dev/null +++ b/lib/popcnt.asm @@ -0,0 +1,30 @@ +popcnt: + push bx + push cx + + mov bx, ax + and ax, 0x5555 ; 8x 01 + and bx, 0xaaaa ; 8x 10 + shr bx, 1 + add ax, bx + + mov bx, ax + and ax, 0x3333 ; 4x 0011 + and bx, 0xcccc ; 4x 1100 + mov cl, 2 + shr bx, cl + add ax, bx + + mov bx, ax + and ax, 0x0f0f ; 2x 00001111 + and bx, 0xf0f0 ; 2x 11110000 + mov cl, 4 + shr bx, cl + add ax, bx + + add al, ah + xor ah, ah + + pop cx + pop bx + ret diff --git a/lib/print.asm b/lib/print.asm new file mode 100644 index 0000000..582e48d --- /dev/null +++ b/lib/print.asm @@ -0,0 +1,32 @@ +; important functions in this file: kprintf + +; print a word +; in: ax +print16: + xchg ah,al + call print8 + xchg ah,al + +; print a byte +; in: al +print8: + push ax ; avoid destroying ah + push bx + xor bx, bx + aam 16 ; high nibble moved into ah, low nibble into al + add ax, 0x3030 + push ax + xchg al, ah + call .nib + pop ax + call .nib + pop bx + pop ax + ret +.nib: + cmp al, 0x3a + jl .out + add al, 0x07 +.out: + call putc + ret diff --git a/lib/printf.asm b/lib/printf.asm new file mode 100644 index 0000000..9584c70 --- /dev/null +++ b/lib/printf.asm @@ -0,0 +1,105 @@ +printf: + cld + pop si + push bp + mov bp, sp +.loop: + mov al, [cs:si] + inc si + cmp al, 0x00 + je .end + cmp al, 0x25 + je .handle_25h +.literal: + call putc + jmp .loop +.end: + pop bp + push si + ret +.handle_25h: + mov al, [cs:si] + inc si + cmp al, 0x25 + je .literal + cmp al, 0x58 ; 'X' + je .printhex + cmp al, 0x55 ; 'U' + je .printdec + cmp al, 0x53 ; 'S' + je .printstr + mov al, 0x3F + jmp .literal +.printhex: + add bp, 2 + mov ax, [bp] + mov bx, 0x0010 + call print_number + jmp .loop +.printdec: + add bp, 2 + mov ax, [bp] + mov bx, 0x000A + call print_number + jmp .loop +.printstr: + add bp, 2 + mov ax, [bp] + call print_string + jmp .loop + +; converts a integer to ascii +; in ax input integer +; bx base +; cx minimum number of digits +; out bx garbled +; dx garbled +print_number_padded: + xor dx, dx + div bx + push dx + dec cx + jz .nopad + call print_number_padded + jmp print_number.end +.nopad: + call print_number + jmp print_number.end + +; converts a integer to ascii +; in ax input integer +; bx base +; out bx garbled +; dx garbled +print_number: + xor dx, dx + div bx ; ax = dx:ax / 10, dx = dx:ax % 10 + push dx + and ax, ax + jz .end + call print_number +.end: + pop bx + xor bh, bh + add bx, print_chars + mov al, [cs:bx] + call putc + ret + +; putc's a string +; in DS:AX null-terminated string +print_string: + push si + mov si, ax +.loop: + lodsb + cmp al, 0x00 + je .end + call putc + jmp .loop +.end: + pop si + ret + +print_chars: + db "0123456789ABCDEF" \ No newline at end of file