-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathIO.ASM
More file actions
1866 lines (1556 loc) · 53.8 KB
/
Copy pathIO.ASM
File metadata and controls
1866 lines (1556 loc) · 53.8 KB
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
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
; --------------------------------------------------------------------
; BrMSX v:1.32
; Copyright (C) 1997 by Ricardo Bittencourt
; module: IO.ASM
; --------------------------------------------------------------------
.386p
code32 segment para public use32
assume cs:code32, ds:code32
extrn blitbuffer: dword
extrn start_counter: near
extrn end_counter: near
extrn tape_pos: dword
extrn message_buffer: dword
extrn msxmodel: dword
include pmode.inc
include pentium.inc
include vdp.inc
include gui.inc
include z80.inc
include bit.inc
include blit.inc
include psg.inc
include mouse.inc
include vesa.inc
include v9938.inc
public printmsg
public printnul
public printasc
public printhex4
public printhex2
public printspace
public getchar
public toupper
public gethex4
public gethex2
public setgraphmode
public settextmode
public crlf
public testkbd
public turnon_irq
public turnoff_irq
public turnon_kb_irq
public turnoff_kb_irq
public exit_now
public open_file
public create_file
public close_file
public write_file
public read_file
public read_size_file
public framerate
public on_off
public set_border_color
public set_border_color_dark
public palette
public videomode
public measurespeed
public clockrate
public printdecimal
public bargraphmode
public set_cursor_position
public tmphex4
public tmphex2
public convhex4
public cpupaused
public gui_palette
public fill_palette
public palette
public wait_vsync
public find_first
public find_next
public set_correct_palette
public setkb
public noled
public savesnap
public greenflag
public pal_normal
public pal_filtered
public pal_gui
public palette_green
public filtered_palette_green
public gui_palette_green
public wait_next_vsync
public adjust_clock
public oldmode
public fastforward
public speaq
public sg1000_high_palette
public gui_palette_high
public border_changed
public set_palette_color
public vdplog_now
public palette_scr8
; DATA ---------------------------------------------------------------
align 4
include keyboard.inc
include keyext.inc
include palette.inc
include guipal.inc
include filpal.inc
include scr8pal.inc
include palgreen.inc
include guigreen.inc
include filgreen.inc
tmphex4 db '0000$' ; temp buffer for print routines
tmphex2 equ tmphex4+2
tmpasc equ tmphex2+1
tmpspace db ' $'
tmpdecimal db 20 dup (' ')
db '$'
irq_stub_buf db 21 dup (0)
oldpirqvect dd 0
oldrirqvect dd 0
kbd_stub_buf db 21 dup (0)
oldkbpirqvect dd 0
oldkbrirqvect dd 0
align 4
framerate dd 1
exit_now dd 0
on_off dd 1
videomode dd 0
cpupaused dd 0
key_extended dd 0
noled dd 0
savesnap dd 0
greenflag dd 0
speaq dd 1
speaker_counter dd 1
pal_normal dd offset palette
pal_filtered dd offset filtered_palette
pal_gui dd offset gui_palette
clockrate db 8 dup (0)
measurestatus dd 0
measureend dd 0
bargraphmode dd 0
oldmode dd 0
fastforward dd 0
forwardlock dd 0
border_changed dd 0
vdplog_now dd 0
palette_scr8 dd 0
msg00 db 13,10,'$'
; printmsg -----------------------------------------------------------
; print a dos message
; eax=address of message
printmsg:
push ebx eax edi esi
mov esi,eax
mov edi,message_buffer
print_msg_loop:
mov al,byte ptr [esi]
inc esi
mov byte ptr [edi],al
inc edi
cmp al,'$'
jne print_msg_loop
mov eax,message_buffer
mov ebx,0
add eax,_code32a
shld ebx,eax,28
and eax,0fh
mov v86r_ds,bx
mov v86r_dx,ax
mov v86r_ah,9
mov al,21h
int 33h
pop esi edi eax ebx
ret
; printasc -----------------------------------------------------------
; print a single ascii code
; al=code
printasc: push eax
mov tmpasc,al
mov eax,offset tmpasc
call printmsg
pop eax
ret
; printnul -----------------------------------------------------------
; print a NULL-terminated message
; eax=address of message
printnul:
push ebx
mov ebx,eax
printnul_loop:
mov al,[ebx]
or al,al
jz printnul_exit
call printasc
inc ebx
jmp printnul_loop
printnul_exit:
pop ebx
ret
; printspace ---------------------------------------------------------
; print a space
printspace:
push eax
mov eax,offset tmpspace
call printmsg
pop eax
ret
; set_cursor_postion -------------------------------------------------
; set the cursor position
; enter dh=row dl=column
set_cursor_position:
mov v86r_dx,dx
mov v86r_bh,0
mov v86r_ah,2
mov al,10h
int 33h
ret
; getchar ------------------------------------------------------------
; wait for key and return ascii code in al
getchar:
mov v86r_ah,0
mov al,16h
int 33h
mov ax,v86r_ax
ret
; testkbd ------------------------------------------------------------
; check if there is a char in the keyboard buffer
; return zero flag if char found
testkbd:
mov v86r_ah,1
mov al,16h
int 33h
ret
; gethex -------------------------------------------------------------
; get a hex digit from the kdb and return in al with echo
gethex:
call getchar
call toupper
push eax
mov tmpasc,al
mov eax,offset tmpasc
call printmsg
pop eax
cmp al,'A'
jae gethex1
sub al,'0'
ret
gethex1: sub al,'A'-10
ret
; gethex4 ------------------------------------------------------------
; get a four-digit hex from the kdb and return in ax (with echo)
gethex4:
call gethex
and eax,0fh
mov ecx,eax
shl ecx,4
call gethex
and eax,0fh
add ecx,eax
shl ecx,4
call gethex
and eax,0fh
add ecx,eax
shl ecx,4
call gethex
and eax,0fh
add ecx,eax
mov eax,ecx
ret
; gethex2 ------------------------------------------------------------
; get a two-digit hex from the kdb and return in al (with echo)
gethex2:
call gethex
and eax,0fh
mov ecx,eax
shl ecx,4
call gethex
and eax,0fh
add eax,ecx
ret
; wait_vsync ----------------------------------------------------------
; wait for vertical retrace
wait_vsync:
mov edx,03DAh
wait_vsync_loop:
in al,dx
test al,BIT_3
jz wait_vsync_loop
ret
; wait_next_vsync -----------------------------------------------------
; wait for the next vertical retrace
wait_next_vsync:
mov edx,03DAh
wait_next_vsync_loop:
in al,dx
test al,BIT_3
jnz wait_next_vsync_loop
jmp wait_vsync
; toupper -------------------------------------------------------------
; upcase a char
; in/out = al
toupper:
cmp al,'a'
jb toupper1
cmp al,'z'
ja toupper1
sub al,'a'-'A'
toupper1:
ret
; SET_VGA_REG ---------------------------------------------------------
; set a vga register
SET_VGA_REG macro reg,index,value
mov dx,reg
mov al,index
out dx,al
inc dx
mov al,value
out dx,al
endm
; fill_palette --------------------------------------------------------
; fill the palette with colors
; enter ebx = offset palette ecx = number of colors
fill_palette:
push eax edx
mov al,0
mov dx,03C8h
out dx,al
inc dx
lea ecx,[ecx+ecx*2]
setgraphmode1:
mov al,[ebx]
out dx,al
inc ebx
dec ecx
jnz setgraphmode1
pop edx eax
ret
; set_correct_palette -------------------------------------------------
; set the correct palette for the selected video mode/screen
set_correct_palette:
cmp msxmodel,0
jne set_correct_palette_msx2
cmp videomode,2
jne set_correct_palette_16
mov ebx,pal_filtered
mov ecx,256
jmp fill_palette
set_correct_palette_16:
mov ebx,pal_normal
mov ecx,16
jmp fill_palette
set_correct_palette_msx2:
cmp actualscreen,0
je set_correct_palette_scr0
cmp actualscreen,8
je set_correct_palette_scr8
mov edi,offset msx2palette
mov esi,offset dirty_palette
mov eax,0
set_correct_palette_msx2_loop:
movzx ecx,word ptr [edi]
; check the border color
cmp eax,0
jne set_correct_palette_msx2_check
test byte ptr [offset vdpregs+8],BIT_5
jnz set_correct_palette_msx2_check
movzx ecx,byte ptr [offset vdpregs+7]
and ecx,0Fh
movzx ecx,word ptr [offset msx2palette+ecx*2]
set_correct_palette_msx2_check:
cmp byte ptr [esi],1
jne set_correct_palette_msx2_next
or al,10h
call set_palette_color
and al,0EFh
set_correct_palette_msx2_next:
mov byte ptr [esi],0
inc esi
add edi,2
inc eax
cmp eax,16
jne set_correct_palette_msx2_loop
mov palette_scr8,0
ret
set_correct_palette_scr8:
cmp palette_scr8,1
je _ret
mov ebx,offset palette_screen8
mov ecx,256
call fill_palette
mov palette_scr8,1
ret
set_correct_palette_scr0:
cmp palette_scr8,1
jne set_correct_palette_scr0_now
cmp byte ptr [offset dirty_palette+0],1
je set_correct_palette_scr0_now
movzx ecx,byte ptr [offset vdpregs+7]
and ecx,0Fh
cmp byte ptr [offset dirty_palette+ecx],1
je set_correct_palette_scr0_now
movzx ecx,byte ptr [offset vdpregs+7]
shr ecx,4
cmp byte ptr [offset dirty_palette+ecx],1
je set_correct_palette_scr0_now
ret
set_correct_palette_scr0_now:
movzx ecx,byte ptr [offset vdpregs+7]
and ecx,0Fh
movzx ecx,word ptr [offset msx2palette+ecx*2]
mov eax,010h
call set_palette_color
movzx ecx,byte ptr [offset vdpregs+7]
shr ecx,4
movzx ecx,word ptr [offset msx2palette+ecx*2]
mov eax,011h
call set_palette_color
mov palette_scr8,0
ret
; setgraphmode --------------------------------------------------------
; set video mode 13h (320x200x256)
setgraphmode:
mov eax,01010101h
mov ecx,16/4
mov edi,offset dirty_palette
rep stosd
mov palette_scr8,0
cmp videomode,2
je setgraphmode_vesa
cmp videomode,6
je setgraphmode_vesa_512_15
cmp videomode,8
je setgraphmode_vesa_msx2
cmp videomode,9
je setgraphmode_vesa_msx2
cmp videomode,11
je setgraphmode_vesa_msx2
cmp videomode,12
je setgraphmode_vesa_512_15
mov v86r_ax,13h
mov al,10h
int 33h
mov ebx,pal_normal
mov ecx,16
call fill_palette
call set_mouse_range
cmp videomode,0
je _ret
cmp videomode,7
je setgraphmode_msx2
cmp videomode,3
je setgraph_256x192
mov edx,03D4h
mov al,11h
out dx,al
inc edx
in al,dx
and al,07Fh
out dx,al
;SET_VGA_REG 03D4h,0,77
;SET_VGA_REG 03D4h,1,63
;SET_VGA_REG 03D4h,2,64
;SET_VGA_REG 03D4h,3,128+3
;SET_VGA_REG 03D4h,4,68
;SET_VGA_REG 03D4h,5,0
;SET_VGA_REG 03D4h,013h,32
SET_VGA_REG 03D4h,0,04Eh
SET_VGA_REG 03D4h,1,03Fh
SET_VGA_REG 03D4h,2,040h
SET_VGA_REG 03D4h,3,091h
SET_VGA_REG 03D4h,4,042h
SET_VGA_REG 03D4h,5,000h
SET_VGA_REG 03D4h,013h,32
ret
setgraphmode_msx2:
mov eax,01010101h
mov ecx,16/4
mov edi,offset dirty_palette
rep stosd
ret
setgraphmode_vesa:
call set_vesa_mode
mov ebx,pal_filtered
mov ecx,256
call fill_palette
call set_mouse_range
ret
setgraphmode_vesa_msx2:
call set_vesa_mode
mov ebx,pal_normal
mov ecx,256
call fill_palette
call set_mouse_range
ret
setgraphmode_vesa_512_15:
call set_vesa_mode
call set_mouse_range
mov direct_color,1
ret
setgraph_256x192:
mov dx,3C2h
mov al,0E3h ; use 63h to stretch the display
out dx,al
mov dx,3D4h ; enable CRTC write access
mov al,11h
out dx,al
inc dx
in al,dx
and al,7Fh
out dx,al
dec dx
mov ax,05F00h
out dx,ax
mov ax,03F01h
out dx,ax
mov ax,04002h
out dx,ax
mov ax,08203h
out dx,ax
mov ax,04C04h
out dx,ax
mov ax,09805h
out dx,ax
mov ax,0BF06h
out dx,ax
mov ax,01F07h
out dx,ax
mov ax,00008h
out dx,ax
mov ax,04109h
out dx,ax
mov ax,09410h
out dx,ax
mov ax,08611h
out dx,ax
mov ax,07F12h
out dx,ax
mov ax,02013h
out dx,ax
mov ax,04014h
out dx,ax
mov ax,08615h
out dx,ax
mov ax,0B916h
out dx,ax
mov ax,0A317h
out dx,ax
mov ax,0FF18h
out dx,ax
ret
; set_border_color ----------------------------------------------------
; set color 0 of VGA as VDP border color
set_border_color:
cmp msxmodel,0
jne _ret
mov border_changed,1
cmp videomode,2
je set_border_color_512x384
push eax ebx edx
movzx eax,byte ptr [offset vdpregs+7]
and eax,0fh
mov ebx,pal_normal
add ebx,eax
add ebx,eax
add ebx,eax
mov al,0
mov dx,03C8h
out dx,al
inc dx
mov al,[ebx]
out dx,al
mov al,[ebx+1]
out dx,al
mov al,[ebx+2]
out dx,al
cmp lastscreen,0
jne set_border_color_ret
; screen 0
; must also set the color 2
movzx eax,byte ptr [offset vdpregs+7]
shr eax,4
mov ebx,pal_normal
add ebx,eax
add ebx,eax
add ebx,eax
dec edx
mov al,2
out dx,al
inc edx
mov al,[ebx]
out dx,al
mov al,[ebx+1]
out dx,al
mov al,[ebx+2]
out dx,al
set_border_color_ret:
pop edx ebx eax
ret
set_border_color_512x384:
cmp lastscreen,0
je set_border_color_512x384_scr0
push eax ebx edx
mov al,0
mov dx,03C8h
out dx,al
inc dx
; set the color 00h
movzx eax,byte ptr [offset vdpregs+7]
and eax,0Fh
mov ebx,eax
shl ebx,4
or eax,ebx
lea eax,[eax+eax*2]
mov ebx,pal_filtered
add ebx,eax
mov al,[ebx]
out dx,al
mov al,[ebx+1]
out dx,al
mov al,[ebx+2]
out dx,al
; set the first row of combined colors
movzx eax,byte ptr [offset vdpregs+7]
and eax,0Fh
lea eax,[eax+eax*2]
shl eax,4
mov ebx,pal_filtered
lea ebx,[ebx+eax+3]
mov ecx,15*3
set_border_color_512x384_loop1:
mov al,[ebx]
inc ebx
out dx,al
dec ecx
jnz set_border_color_512x384_loop1
; set the first column of combined colors
movzx eax,byte ptr [offset vdpregs+7]
and eax,0Fh
lea eax,[eax+eax*2]
shl eax,4
mov esi,10h
mov ebx,pal_filtered
lea ebx,[ebx+eax+3]
dec edx
mov ecx,15
set_border_color_512x384_loop2:
mov eax,esi
out dx,al
inc edx
mov al,[ebx]
out dx,al
mov al,[ebx+1]
out dx,al
mov al,[ebx+2]
out dx,al
add ebx,3
add esi,10h
dec edx
dec ecx
jnz set_border_color_512x384_loop2
pop edx ebx eax
ret
set_border_color_512x384_scr0:
push eax ebx edx
mov al,0
mov dx,03C8h
out dx,al
inc dx
; set the color 00h
movzx eax,byte ptr [offset vdpregs+7]
and eax,0Fh
mov ebx,eax
shl ebx,4
or eax,ebx
lea eax,[eax+eax*2]
mov ebx,pal_filtered
add ebx,eax
mov al,[ebx]
out dx,al
mov al,[ebx+1]
out dx,al
mov al,[ebx+2]
out dx,al
; set the color 01h
movzx eax,byte ptr [offset vdpregs+7]
and eax,0Fh
or eax,10h
lea eax,[eax+eax*2]
mov ebx,pal_filtered
add ebx,eax
mov al,[ebx]
out dx,al
mov al,[ebx+1]
out dx,al
mov al,[ebx+2]
out dx,al
; set the color 02h
movzx eax,byte ptr [offset vdpregs+7]
lea eax,[eax+eax*2]
mov ebx,pal_filtered
add ebx,eax
mov al,[ebx]
out dx,al
mov al,[ebx+1]
out dx,al
mov al,[ebx+2]
out dx,al
; set the color 10h
dec edx
mov al,10h
out dx,al
inc edx
movzx eax,byte ptr [offset vdpregs+7]
and eax,0Fh
or eax,10h
lea eax,[eax+eax*2]
mov ebx,pal_filtered
add ebx,eax
mov al,[ebx]
out dx,al
mov al,[ebx+1]
out dx,al
mov al,[ebx+2]
out dx,al
; set the color 12h
dec edx
mov al,12h
out dx,al
inc edx
movzx eax,byte ptr [offset vdpregs+7]
shr eax,4
or eax,10h
lea eax,[eax+eax*2]
mov ebx,pal_filtered
add ebx,eax
mov al,[ebx]
out dx,al
mov al,[ebx+1]
out dx,al
mov al,[ebx+2]
out dx,al
; set the color 20h
dec edx
mov al,20h
out dx,al
inc edx
movzx eax,byte ptr [offset vdpregs+7]
shr eax,4
mov ebx,eax
shl ebx,4
or eax,ebx
lea eax,[eax+eax*2]
mov ebx,pal_filtered
add ebx,eax
mov al,[ebx]
out dx,al
mov al,[ebx+1]
out dx,al
mov al,[ebx+2]
out dx,al
; set the color 21h
movzx eax,byte ptr [offset vdpregs+7]
shr eax,4
or eax,10h
lea eax,[eax+eax*2]
mov ebx,pal_filtered
add ebx,eax
mov al,[ebx]
out dx,al
mov al,[ebx+1]
out dx,al
mov al,[ebx+2]
out dx,al
; set the color 22h
movzx eax,byte ptr [offset vdpregs+7]
shr eax,4
mov ebx,eax
shl ebx,4
or eax,ebx
lea eax,[eax+eax*2]
mov ebx,pal_filtered
add ebx,eax
mov al,[ebx]
out dx,al
mov al,[ebx+1]
out dx,al
mov al,[ebx+2]
out dx,al
pop edx ebx eax
ret
; set_border_color_dark -----------------------------------------------
; set color 0 of VGA as VDP border color
set_border_color_dark:
push eax ebx edx
movzx eax,byte ptr [offset vdpregs+7]
and eax,0fh
lea ebx,[offset palette+eax+eax*2]
mov al,0
mov dx,03C8h
out dx,al
inc dx
mov al,[ebx]
shr al,2
out dx,al
mov al,[ebx+1]
shr al,2
out dx,al
mov al,[ebx+2]
shr al,2
out dx,al
cmp lastscreen,0
jne set_border_color_dark_ret
; screen 0
; must also set the color 2
dec edx
mov al,2
out dx,al
inc edx
movzx eax,byte ptr [offset vdpregs+7]
shr eax,4
lea ebx,[offset palette+eax+eax*2]
mov al,[ebx]
shr al,2
out dx,al
mov al,[ebx+1]
shr al,2
out dx,al
mov al,[ebx+2]
shr al,2
out dx,al
set_border_color_dark_ret:
pop edx ebx eax
ret
; settextmode ---------------------------------------------------------
; set text mode 3h (80x25 color)
settextmode:
mov v86r_ax,03h