summaryrefslogtreecommitdiffstats
path: root/datetime.asm
blob: e95f01e5dd9cda61fbe8389b92b2f80f8ed719e1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
/* -*- asm -*- ----------------------------------------------------------- *
 *   
 *   Copyright 2013 H. Peter Anvin - All Rights Reserved
 *
 *   Permission is hereby granted, free of charge, to any person
 *   obtaining a copy of this software and associated documentation
 *   files (the "Software"), to deal in the Software without
 *   restriction, including without limitation the rights to use,
 *   copy, modify, merge, publish, distribute, sublicense, and/or
 *   sell copies of the Software, and to permit persons to whom
 *   the Software is furnished to do so, subject to the following
 *   conditions:
 *   
 *   The above copyright notice and this permission notice shall
 *   be included in all copies or substantial portions of the Software.
 *   
 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *   OTHER DEALINGS IN THE SOFTWARE.
 *
 * ----------------------------------------------------------------------- */

#include "v9fs.h"

	.code16
	.section ".rtext","ax"

	grblong	gmtoff		/* Seconds east of UTC */

/* ------------------------------------------------------------------------- *
 *  unix2dos
 *
 *  Convert a Unix timestamp to DOS format, assuming a fixed timezone
 *  offset.  Input & output in %eax, all other regs preserved.
 * ------------------------------------------------------------------------- */

GPROC(unix2dos)
	pushl %edx
	pushl %ecx
	pushw %bx		/* Accumulator for date */
	pushw %si		/* Accumulator for time */

	addl gmtoff,%eax	/* Convert to local time */

	shrl $1,%eax		/* DOS uses a fundamental unit of 2 seconds */

	xorl %ecx,%ecx
	movb $30,%cl
	cltd			/* Clear %edx */
	divl %ecx
	movw %dx,%si

	movb $60,%cl
	cltd
	divl %ecx
	shlw $5,%dx
	addw %dx,%si

	movb $24,%cl
	cltd
	divl %ecx
	shlw $11,%dx
	addw %dx,%si

	/*
	 * Now we have a day number in %(e)ax.  Converting a date is more
	 * complicated, however.  DOS timestamps technically go from
	 * 1980 to 2107, but DOS itself only accept dates to 2099-12-31
	 * so let's assume that we can ignore the fact that 2100 is a
	 * non-leapyear.  Note also we treat the incoming Unix date as
	 * unsigned, which gives a reach from 1970 to 2106.
	 *
	 * The day numbers for the DOS era range from 3652 to
	 * 47481 (for 2099) or 50402 (for 2107).
	 *
	 * However, most of the math below uses Christian Zeller's trick
	 * of treating January and February as months 13 and 14 of the
	 * previous year.
	 */
	cmpw $3652,%ax		/* 1980-01-01 = smallest possible date */
	jb 3f

	subw $2251,%ax		/* Convert to epoch 1976-03-01 */
	xorw %dx,%dx		/* Can't use cwtd, sign bit might be set */

	movw $(365*3+366),%cx	/* Days per 4-year cycle */
	divw %cx
	decw %ax		/* Convert to epoch 1980-03-01 */

	shlw $11,%ax		/* Number of 4-year cycles */
	movw %ax,%bx

	xchgw %dx,%ax
	cwtd
	movw $365,%cx
	divw %cx
	/*
	 * %ax is now in the range 0-4.  4 means Feb 29, move it back
	 * into the previous year as it should be.
	 */
	cmpb $4,%al
	adcb $-1,%al

	shlw $9,%ax		/* Years within each cycle */
	addw %ax,%bx

	imulw $5,%dx,%ax
	addw $461,%ax		/* 3 cycles (for 3=March) + 2 days */
	cwtd
	movw $153,%cx		/* Days in a 5-month 31,31,30,31,30 cycle */
	divw %cx

	/* %ax now is the month within year in the range 3-14 */
	cmpb $12,%al
	jna 2f
	/* January or February are months 1-2 of the subsequent year */
	addb $(16-12),%al
2:
	shlw $5,%ax
	addw %ax,%bx		/* Add, not or!  May be modifying the year! */

	xchgw %dx,%ax
	aam $5
	addb %ah,%bl
	xchgw %bx,%ax
	incw %ax		/* Day of month is 1-based */

4:
	/* Here %ax has the date component and %si the time component */
	shll $16,%eax
	xchgw %si,%ax

	popw %si
	popw %bx
	popl %ecx
	popl %edx
	retw

3:	/* Date underflow */
	movw $0x21,%ax		/* 1980-01-01 */
	xorw %si,%si		/* 00:00:00 */
	jmp 4b
END(unix2dos)