-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathbuilder-hex0-mini.hex0
374 lines (299 loc) · 9.43 KB
/
builder-hex0-mini.hex0
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# Builder-Hex0 is a small bootable machine image which has
# the ability to compile hex0 code. It is also written in hex0
# and so it can build itself if provided with its own source code.
#
# hex0 is a "language" for binary encoding in hexadecimal
# with support for comments.
# Functions:
# _start
# get_drive_geometry
# next_sector
# read_sector
# write_sector
# read
# write
# compile
#------------------------------------------------------------
# Memory:
# 9FC00 - FFFFF BIOS
# 7C00 - 7E00 MBR/code
# 7A00 - 7BFF sector read buffer
# 7800 - 79FF sector write buffer
# < 7700 real mode stack
#------------------------------------------------------------
# ------------------------------------------------------------
# Stub Entry Point
#
# boot drive is in dl
#
#[7C00][15]
#:_start
# We cannot be sure the registers are initialized to zero so we
# do that first. We far jump to mbr_main in order to set CS.
31 C0 # xor ax, ax
8E D8 # mov ds, ax
8E C0 # mov es, ax
8E D0 # mov ss, ax
BC 00 77 # mov sp, 0x7700
FC # cld ; clear direction flag
88 16 15 7C # mov [boot_drive], dl
EA 1A 7D 00 00 # jmp compile
# ------------------------------------------------------------
# disk_geometry
#[7C15]
80 # boot_drive
0F # boot drive max_head 0..15
3F # boot drive max_sector / track (1..63)
#[7C18][18]
# ------------------------
#:get_drive_geometry(dl=boot_drive)
#
06 # push es
57 # push di
# https://en.wikipedia.org/wiki/INT_13H#INT_13h_AH=08h:_Read_Drive_Parameters
31 FF # xor di, di
8E C7 # mov es, di
B4 08 # mov ah, 8 ; get drive parameters
CD 13 # int 0x13
88 36 16 7C # mov [max_head], dh ; max_head
80 E1 3F # and cl, 0x3f
88 0E 17 7C # mov [max_sector], cl ; num_sectors
5F # pop di
07 # pop es
CB # retf
#[7C30]
# ------------------------
#:next_sector(cx=cylinder/sector, dh = head)
#
50 # PUSH_AX
88 C8 # mov al, cl ; get sector number
24 3F # and al, 0x3f
3A 06 17 7C # cmp al, [max_sector]; if sector_num == max_sector
74 04 # jz next_head ; goto next_head
FE C1 # inc cl ; else sector_num++;
EB 28 # jmp cleanup
#next_head:
3A 36 16 7C # cmp dh, [max_head] ; if head_num == max_head
74 09 # jz next_cylinder ; goto next_cyclinder
FE C6 # inc dh ; else head_num++
80 E1 C0 # and cl, 0xc0 ; sector_num = 1
FE C1 # inc cl ;
EB 19 # jmp cleanup
#next_cylinder:
80 FD FF # cmp ch, 0xff ; if cylinder_low == 255
74 0B # je next_cyl_high
#next_cyl_low:
30 F6 # xor dh, dh ; head_num = 0
80 E1 C0 # and cl, 0xc0 ; sector_num = 0
81 C1 01 01 # add cx, 0x0101 ; cylinder_low++, sector_num++
EB 09 # jmp cleanup
#next_cyl_high:
30 F6 # xor dh, dh ; head_num = 0
81 C1 C0 00 # and cx, 0x00C0 ; cylinder_low = 0, sector_num = 0
80 C1 41 # add cl, 0x41 ; cylinder_high++, sector_num++
#cleanup:
58 # pop ax
CB # retf
# ------------------------
#[7C69][ ]
#:read_sector(di = *dest_addr, cx=cylinder/sector, dh = head)
#
# returns: di - next byte to write to
# cx,dh - next disk sector to read from
#
50 # push ax
53 # push bx
89 FB # mov bx, di ; int 13 writes to bx
#:read_one_loop
8A 16 15 7C # mov dl, [boot_drive]
B4 02 # mov ah, 2 ; rw mode = 02 (read)
B0 01 # mov al, 1 ; num_sectors
CD 13 # int 0x13
72 F4 # jnc read_one_loop
3C 01 # cmp al, 1
75 F0 # jnz read_one_loop
# advance and maybe continue
9A 30 7C 00 00 # call next_sector
5B # pop bx
58 # pop ax
CB # retf
# ------------------------
#[7C85]
#:write_sector(si = *source_addr, cx=cylinder/sector, dh = head)
#
# returns: cx,dh - next disk sector to read from
#
50 # push ax
53 # push bx
52 # push dx
89 F3 # mov bx, si ; int 13 reads from [bx]
#:write_one_loop
8A 16 15 7C # mov dl, [boot_drive]
B4 03 # mov ah, 3 ; rw mode = 03 (write)
B0 01 # mov al, 1 ; num_sectors
CD 13 # int 0x13
72 F4 # jnc write_one_loop
3C 01 # cmp al, 1
75 F0 # jnz write_one_loop
# advance and maybe continue
9A 30 7C 00 00 # call next_sector
5A # pop dx
5B # pop bx
58 # pop ax
CB # retf
#----------------------------------------
# last_read_location
#[7CA3]
02 00 ; last_cylinder/sector
00 ; last_head
FF 01 ; last_byte
#[7CA8]
#:read()
53 # push bx
51 # push cx
52 # push dx
56 # push si
57 # push di
# get current position
BB A3 7C # mov bx, last_read_location
8B 0F # mov cx, [bx]
8A 77 02 # mov dh, [bx+2]
8B 47 03 # mov ax, [bx+3]
#end of sector?
3D FF 01 # cmp ax, 0x01ff
74 03 # je next sector
#nextchar:
40 # inc ax
EB 0F # jmp getchar
#read next sector
BF 00 78 # mov di, 0x7800
9A 69 7C 00 00 # call read_sector
# save new location and offset
89 0F # mov [bx], cx
88 77 02 # mov [bx+2], dh
31 C0 # xor ax, ax
#getchar:
89 47 03 # mov [bx+3], ax
BE 00 78 # mov si, 0x7800
89 C3 # mov bx, ax
8A 00 # mov al, [si+bx]
#finish:
5F # pop di
5E # pop si
5A # pop dx
59 # pop cx
5B # pop bx
CB # ret
#----------------------------------------
# next_write_location
#[7CDF]
01 00 ; next_cylinder/sector
00 ; next_head
00 00 ; next_byte
#[7CE4]
#:write(al)
53 # push bx
51 # push cx
52 # push dx
56 # push si
57 # push di
# get current position
BF 00 7A # mov di, 0x7A00
8B 1E E2 7C # mov bx, [next_byte]
88 01 # mov [di+bx], al ; store in write buffer
#nextchar:
43 # inc bx
81 FB 00 02 # cmp bx, 0x0200 ; end of sector?
75 17 # jne finish
#write sector
BE 00 7A # mov si, 0x7A00
BB DF 7C # mov bx, next_write_location
8B 0F # mov cx, [bx]
8A 77 02 # mov dh, [bx+2]
9A 85 7C 00 00 # call write_sector
89 0F # mov [bx], cx ; save new location and offset
88 77 02 # mov [bx+2], dh
31 DB # xor bx, bx ; start of sector
#finish:
89 1E E2 7C # mov [next_byte], bx
5F # pop di
5E # pop si
5A # pop dx
59 # pop cx
5B # pop bx
CB # ret
#----------------------------------------
# Compile hex0 to binary
# compile(dl=boot_drive):
#[7D1A]
9A 18 7C 00 00 # call get_drive_geometry
# this flag is set after the first digit is seen
31 DB # xor bx,bx
#:read_loop
9A A8 7C 00 00 # call read
84 C0 # test al, al
74 51 # jz finish
3C 23 # cmp al, '#'
74 28 # jz skip_comment
3C 3B # cmp ';'
74 24 # jz skip_comment
3C 66 # cmp al, 'f'
7F EB # jg read_loop
3C 61 # cmp al, 'a'
7C 04 # jl maybe_upper
# Handle a to f
2C 57 # sub al, 'a'-10 == 87 = 0x57
EB 23 # jmp maybe_store
#:maybe_upper
3C 46 # cmp al, 'F'
7F DF # jg read_loop
3C 41 # cmp al, 'A'
7C 04 # jl maybe_digit
# Handle A to F
2C 37 # sub al, 'A'-10 == 55 = x37
EB 17 # jmp maybe_store
#:maybe_digit
3C 39 # cmp al, '9'
7F D3 # jg read_loop
3C 30 # cmp al, '0'
7C CF # jl read_loop
# Handle 0 to 9
2C 30 # sub al, '0' == x30
EB 0B # jmp maybe_store
#:skip_comment
9A A8 7C 00 00 # call read
3C 0A # cmp al, '\n'
75 F7 # jnz skip_comment
EB C0 # jmp read_loop
# only store on second digit
#:maybe_store
84 DB # test bl, bl
75 09 # jnz second_digit
# If on first digit, record and keep going
#:first_digit
C0 E0 04 # shl al, 4
88 C7 # mov bh, al
FE C3 # inc bl
EB B3 # jmp read_loop
# If on second digit, store and clear state
#:second_digit
08 C7 # or bh, al
88 F8 # mov al, bh
9A E4 7C 00 00 # call write
31 DB # xor bx, bx
EB A6 # jmp read_loop
#:finish
EA F0 FF 00 F0 # ljmp $F000:FFF0 ; reboot
#[7D80]
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
#[7DC0]
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00
#[7DFE]
# This is the DOS/MBR identifier at offset 510:
55 AA