diff --git a/io.asm b/io.asm index f740efb..aba830c 100644 --- a/io.asm +++ b/io.asm @@ -22,7 +22,7 @@ data ends iogroup group code, constants, data code segment -assume cs:iogroup, ds:iogroup, es:iogroup +assume cs:iogroup org 0 ; Jump table @@ -36,9 +36,9 @@ jmp unimplemented ; 0012 Serial write jmp near ptr diskread ; 0015 jmp diskwrite ; 0018 jmp near ptr diskchange ; 001b -jmp setdate ; 001e -jmp settime ; 0021 -jmp gettime ; 0024 +jmp near ptr setdate ; 001e +jmp near ptr settime ; 0021 +jmp near ptr gettime ; 0024 jmp near ptr flush ; 0027 jmp near ptr mapdev ; 002a @@ -99,11 +99,11 @@ init: int 10h ; Set random record field 0 - mov word ptr command_fcb+33, 0 - mov word ptr command_fcb+35, 0 + mov word ptr iogroup:command_fcb+33, 0 + mov word ptr iogroup:command_fcb+35, 0 ; Set record size to 1 byte - mov word ptr command_fcb+14, 1 + mov word ptr iogroup:command_fcb+14, 1 ; Read command.com into memory mov ah, 27h @@ -326,7 +326,7 @@ chs proc ; cylinder = LBA / sectorspertrack / heads ; head = LBA / sectorspertrack % heads ; sector = LBA % sectorspertrack + 1 - div cs:sectorspertrack + div iogroup:sectorspertrack ; ax = LBA / sectorspertrack ; dx = LBA % sectorspertrack @@ -335,7 +335,7 @@ chs proc inc cl xor dx, dx - div cs:heads + div iogroup:heads ; ax = LBA / sectorspertrack / heads ; dx = LBA / sectorspertrack % heads @@ -374,15 +374,132 @@ diskchange proc far ret diskchange endp -setdate: - mov al, 'd' - jmp error -settime: - mov al, 't' - jmp error -gettime: - mov al, 'T' - jmp error +; IN: +; ax = days since 1980-01-01 +setdate proc far + mov iogroup:days_since_epoch, ax + ret +setdate endp + +; IN: +; ch = hour +; cl = minute +; dh = second +; dl = 1/100 second +settime proc far + push ax + push bx + push cx + push dx + push si + push di + + ; Save second & 1/100 second in bx + mov bx, dx + + ; Hour + mov al, ch + cbw + mul iogroup:doubleticks_per_hour + shl ax, 1 + rcl dx, 1 + ; Store the partial sum in si:di + mov di, ax + mov si, dx + + ; Minute + mov al, cl + cbw + mul iogroup:ticks_per_minute + add di, ax + adc si, dx + + ; Second + mov al, bh + cbw + mul iogroup:ticks_per_second + add di, ax + adc si, dx + + ; 1/100 second + mov al, bl + cbw + div iogroup:cs_per_tick + xor ah, ah + add di, ax + adc si, 0 + + ; Move result to cx:ds and set timer + mov cx, si + mov dx, di + mov ah, 01h + int 1ah + + pop di + pop si + pop dx + pop cx + pop bx + pop ax + ret +settime endp + +; OUT: +; ax = days since 1980-01-01 +; ch = hour +; cl = minute +; dh = second +; dl = 1/100 second +gettime proc far + ; TODO: Use RTC if available + push bx + + ; Get ticks since midnight and day rollover flag + xor ah, ah + int 1ah + + ; al is nonzero if day has changed + test al, al + jz same_day + inc iogroup:days_since_epoch + + same_day: + + ; Divide the ticks by 2, to keep all our arithmetic within bounds + shr cx, 1 + rcr dx, 1 + + ; int 1ah / ah=00 returns the ticks in cx:dx, div operates on dx:ax + mov ax, dx + mov dx, cx + div iogroup:doubleticks_per_hour + mov ch, al ; Hour + + ; Remainder in dx, range [0,doubleticks_per_hour[ represents an hour + ; Multiply by 60, divide by doubleticks_per_hour to get the minute + mov ax, dx + mul iogroup:sixty + div iogroup:doubleticks_per_hour + mov cl, al ; Minute + + ; Do same again to get seconds + mov ax, dx + mul iogroup:sixty + div iogroup:doubleticks_per_hour + mov bl, al ; Save seconds in bl, since dh gets destroyed by next muldiv + + ; For 1/100th of a second, multiply by 100 instead + mov ax, dx + mul iogroup:hundred + div iogroup:doubleticks_per_hour + mov dh, bl ; Second + mov dl, al ; 1/100 second + + mov ax, iogroup:days_since_epoch + + pop bx + ret +gettime endp flush proc far push ax @@ -444,6 +561,14 @@ parameters_320k: dw 112 ; Number of directory entries dw 320*2 ; Number of sectors +doubleticks_per_hour dw 32772 ; 1800B0h / 2 / 24 +ticks_per_minute dw 1092 ; 1800B0h / 24 / 60 +ticks_per_second dw 18 ; 1800B0h / 24 / 60 / 60 +cs_per_tick db 5 ; 24 * 60 * 60 * 100 / 1800B0h + +sixty dw 60 +hundred dw 100 + constants ends data segment @@ -453,6 +578,8 @@ command_fcb: db "COMMAND COM" db 25 dup (?) +days_since_epoch: dw 0 + data ends code segment