-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy pathci86.gnr
12109 lines (11866 loc) · 411 KB
/
ci86.gnr
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
_C{ ciforth : a generic I86 ISO FORTH by HCC FIG}
_C{ $Id: ci86.gnr,v 5.205 2024/04/21 11:27:32 albert Exp $}
_C{ Copyright (2012):} M4_SUPPLIER {by GNU Public License}
_C
_C{HCC FIG Holland : Hobby Computer Club, Forth Interest Group Holland}
PAGE 66,106
TITLE ciforth $Revision: 5.205 $
_C
_C{ For the generic system (to generate ciforth in an other configuration than this one):}
_C{ http://home.hccnet.nl/a.w.m.van.der.horst/ci86gnr.html}
_C
_C{ The following configuration information should agree with the configuration}
_C{ on the frontpage of your docmentation (texinfo, ps, pdf.)}
_C{ WITHOUT FITTING DOCUMENTATION YOU MIGHT AS WELL GIVE UP! }
_C
_C{ Configuration of this particular version:}
_C _BITS_{}-bits _REAL_({real mode })_PROTECTED_({protected mode })
_C _BOOTED_({standalone })_HOSTED_({running under _OS_ })dnl
_HOSTED_DPMI_({running under DPMI (OS/2 or MS-Windows)
_C _CLASSIC_({with classic figforth I/O })_MODERN_({with modern MSDOS I/O })_USEBIOS_({Using the BIOS for I/O })
})dnl
_HOSTED_MSDOS_({running under MSDOS
_C _CLASSIC_({with classic figforth I/O })_MODERN_({with modern MSDOS I/O })_USEBIOS_({Using the BIOS for I/O })
}) _LINUX_C_({_C with c-routines for I/O})_LINUX_N_({_C with native forth I/O})
_DLL_({_C with calls to shared libraries in MS-Windows})
_C Normally ciforth doesn't observe ISO >IN{}_ISO_IN_({{, but this one does}}).
_C{ Contains :}
_C{ (there may be no items here.)}
_SECURITY_({_C{ Security words}
})dnl
_LOAD_({_C{ Loadable words, i.e. all of ISO CORE, more than is needed}
_C{ for a self contained kernel.}
})dnl
_SOURCEFIELD_({_C{ A field in the header to point to source}
})dnl
_EXTRAFIELD_({_C{ An extra field in the header for double links or free use.}
})dnl
_FEWBLOCKS_({_C{ number of blocks limited to 256}
})dnl
_C
dnl It doesn't make sense to have duplicate code for 16/32/64 bits
dnl where m4 can handle it this easily.
dnl 16 bits was default for the startup code, now overrule.
dnl 16 bits is default for the boot code.
_BITS16_({include(width16.m4)})
_BITS32_({include(width32.m4)},{dnl})
_BITS64_({include(width64.m4)},{dnl})
_HEADER_ASM
_COMMENTED({
A generic version of ISO FORTH for IBM type standard PC's by
M4_SUPPLIER
in cooperation with
HCC Forth user group
The Netherlands
www.forth.hccnet.nl
with
direct contributions for OSX from Robert Spykerman.
based on
FIG-FORTH
implemented by: Charlie Krajewski
205 ( BIG ) Blue Rd.
Middletown, CT 06457
The listing has been made possible by the
prior work of:
Thomas Newman, Hayward, Ca.
: other_acknowledgements
John_Cassidy
Kim_Harris
George_Flammer
Robert_D._Villwock ;
: for tools
Richard M. Stallman
Linus Torvalds
No one who programs with FORTH can afford to be without:
"Starting Forth by Leo Brodie" and "Thinking Forth by Leo Brodie".
Both out of print.
This Forth is a descendant in the 300+ (RCS)- generations from fig-Forth.
For nostalgic reasons the following comment has never been removed:
Although there is much to be said for typing in your own
listing and getting it running, there is much to be said
not typing in your own listing. If you feel that 100+
pages of plinking is nutty, contact me for availability
of a disc with source & executable files. Obtainable at
a bargain basement price, prepare yourself for bargain
basement support.
All publications of the FORTH Interest Group are public domain.
They may be further distributed by the inclusion of this
credit notice:
This publication has been made available by:
FORTH Interest Group
P.O. Box 1105
San Carlos, Ca. 94070
[I feel obliged to keep this last one in (AH). Note that although it is
based on fig-Forth no stone is left unturned.]
})
PAGE
_C{ ########################################################################################}
_C{ PREPARATION (no code)}
_C{ ########################################################################################}
FIGREL EQU 5 _C{ FIG RELEASE #}
FIGREV EQU 0 _C{ FIG REVISION #}
USRVER EQU 0 _C{ USER VERSION NUMBER, a digit now}
_C
_C{ VERY ELEMENTARY .}
CW EQU M4_CELLWIDTH _C{ Size of a cell in Forth, not in the bootcode.}
ERRORSCREEN EQU M4_ERRORSCREEN _C{ Screen where the error messages start.}
_C
_C{ MEMORY LAYOUT.}
_C{ Normally this is specified at the m4 configuration level.}
_C{ For a configured system these values can be changed at this single place. }
dnl This is the index of the CONTEXT user variable.
define({M4_USUSED},39)dnl
NBUF EQU M4_NBUF _C{ No. of buffers, or screens }
KBBUF EQU 1024 _C{ Data bytes per disk buffer}
US EQU M4_US*CW _C{ User variable space, eats into next data stack, if any.}
EM EQU M4_EM _C{ Where the memory ends w.r.t. ORIG. 1) }
EMP EQU (EM-1)/0x1000+1 _C{ Number of pages.}
TAS EQU M4_RTS _C{Size of unitialised area per task.}
STACKSIZE EQU TAS/4 _C{For both stacks. }
dnl It seems that DLL cannot have this larger than about 4000H
TIBSIZE EQU TAS/4 _C{TIB size. }
_C
_C{ NOTE 1:}
_BITS64_({_C{Nothing tricky on 64 bits systems}},
{
_C{This trick to not have a round memory allocated convinces loaders}
_C{ on Linux 1.24 and following to load the elf header in memory}
_C{ in front of the executable, and not in some other place.}
_C{ ciforth relies on modifying the elf header in behalf of SAVE-SYSTEM.}
_C{This is more convenient than creating it from scratch. It also leaves}
_C{ alone the load address generated by ``ld'', and all other things we}
_C{ are not aware of.}
})
_FEWBLOCKS_({PMASK EQU 0x0FF _C{ Allow to access only 256 blocks from OFFSET}})
_C
_C{ ASCII CHARACTER EQUIVALENTS}
_C
ABL EQU ' ' _C{ SPACE}
ACR EQU {0x0D} _C{ CR}
AMS EQU '-' _C{ MINUS SIGN }
ASO EQU '[' _C{ SQUARE BRACKET OPEN }
ASC EQU ']' _C{ SQUARE BRACKET CLOSE }
ADOT EQU '.' _C{ PERIOD}
ALF EQU {0x0A} _C{ LINE FEED, USED INTERNALLY AS}
_C{ LINE ENDER}
AFF EQU {0x0C} _C{ FORM FEED}
BELL EQU 0x07 _C{ ^G}
BSIN EQU 0x08 _C{ INPUT DELETE CHARACTER}
BSOUT EQU 0x08 _C{ OUTPUT BACKSPACE ( ^H )}
_C
_C{ HEADER RELATED EQUATES}
B_DUMMY EQU 0x01 _C{ dea is dummy, from namespace link}
B_INVIS EQU 0x02 _C{ dea is invisible, "smudged".}
B_IMMED EQU 0x04 _C{ dea is a immediate.}
B_DENOT EQU 0x08 _C{ dea is a denotation.}
C_HOFFSET EQU 0 _C{ Offsets of code field in cells, w.r.t. dea}
D_HOFFSET EQU 1 _C{ Same for data field}
F_HOFFSET EQU 2 _C{ Same for flag field}
L_HOFFSET EQU 3 _C{ Same for link field}
N_HOFFSET EQU 4 _C{ Same for name field}
_SOURCEFIELD_({S_HOFFSET EQU 5 _C{ Same for source field}}, {dnl})
_EXTRAFIELD_({X_HOFFSET EQU _SOURCEFIELD_(S_HOFFSET,N_HOFFSET)+1_C{ Same for extra field}}, {dnl})
PH_OFFSET EQU M4_HS _C{ Past header field: Start of data area. }
BD_OFFSET EQU M4_HS+1 _C{ Start of BODY for CREATEd word.}
HEADSIZE EQU _CELLS(PH_OFFSET) _C{In cells, only to clean up source.}
_C
_EQULAYOUT_({
_HIGH_BUF_({
BUF1 EQU EM-(KBBUF+2*M4_CELLWIDTH)*NBUF _C{ FIRST DISK BUFFER}
TASKEND EQU BUF1 _C{ User area}
})_C{}_END_({ _HIGH_BUF_})
_LOW_BUF_({
TASKEND EQU EM _C{ User area at end }
_C
})_C{}_END_({ _LOW_BUF_})
STRUSA EQU TASKEND - US _C{ User area}
INITR0 EQU TASKEND - US _C{ Return stack, grows down}
TASKSTART EQU TASKEND - TAS
STRTIB EQU TASKSTART+STACKSIZE _C{ Start terminal input buffer}
INITS0 EQU TASKSTART+STACKSIZE _C{ Grows down,possibly out of task area}
_C
})_C{}_END_({ _EQULAYOUT_})
_CLASSIC_({
DRIVE EQU 0 _C{ Use floppy A for blocks.}
_C
})_C{}_END_({_CLASSIC_})
_USEBIOS_({
DRIVE EQU 0 _C{ Use floppy A for blocks.}
_COMMENTED({
DRIVE EQU 0x80 _C{ Use drive C for blocks.}
})
_C
})_C{}_END_({_USEBIOS_})
BPS EQU 512 _C{Bytes/sector, common to all of MSDOS}
SPB EQU KBBUF/BPS
_C
_RWLBA_({
_C{ PHYSICAL DISK PARAMETERS}
_C{Most of this makes no sense but it is required in a bootsector,}
NFAT EQU 0 _C{ Number of FATS}
SECROOT EQU 0x0 _C{ Sectors for root directory entry.}
MEDIA EQU 0x0F8 _C{ Descriptor byte. Anachronism.}
SECFAT EQU 0 _C{ Sectors per FAT}
SPT EQU 0 _C{Sectors/track}
HEADS EQU 0 _C{Number of heads }
TRKS EQU 0 _C{Number of tracks}
SPDRV EQU HEADS*TRKS*SPT _C{ sectors/drive}
_C
})_C{}_END_({_RWLBA_})
_RWSECTRK_({
_C{ PHYSICAL DISK PARAMETERS}
_C
_C{ Disk parameters: }
_C{ FD drive 3" }
TRKS EQU 80 _C{Number of tracks}
SPT EQU 18 _C{Sectors/track}
HEADS EQU 2 _C{Number of heads }
NFAT EQU 2 _C{ Number of FATS}
SECROOT EQU 0x0E _C{ Sectors for root directory entry.}
SECFAT EQU 9 _C{ Sectors per FAT}
MEDIA EQU 0x0F0 _C{ Descriptor byte. Used for selecting between A: and C:.}
_COMMENTED({
_C{ FD drive 5" }
TRKS EQU 80 _C{Number of tracks}
SPT EQU 15 _C{Sectors/track}
HEADS EQU 2 _C{Number of heads }
NFAT EQU 2 _C{ Number of FATS}
SECROOT EQU ? _C{ Sectors for root directory entry.}
SECFAT EQU 7 _C{ Sectors per FAT}
MEDIA EQU 0x0F0 _C{ Descriptor byte. Used for selecting between A: and C:.}
})
_COMMENTED({
_C{ Hard drive }
_C{This works supposedly with all reasonably modern drives. }
TRKS EQU 1 _C{Number of tracks, dummy}
SPT EQU 63 _C{Sectors/track}
HEADS EQU 255 _C{Number of heads }
NFAT EQU 2 _C{ Number of FATS}
SECROOT EQU 0 _C{ Sectors for root directory entry, dummy.}
SECFAT EQU 0 _C{ Sectors per FAT, dummy}
MEDIA EQU 0x0F8 _C{ Descriptor byte. Used for selecting between A: and C:.}
})
_C{ Bios specific equates.}
BOOTADDRESS EQU M4_BIOSBOOT _C{ PC jumps to 0:7C00 to boot}
_C{ Skip boot sector,fats and root dir and first sector of file.}
_RESPECTDOS_({
SECSTRT EQU 1+NFAT*SECFAT + SECROOT + 1
})_C{}_END_({_RESPECTDOS_})
_NO_RESPECTDOS_({
_C{ The disk needs not to be recognized by MSDOS}
_C{ Usable for generating a bootable floppy simple.}
_C{ Always used for hard disk.}
SECSTRT EQU 1
})_C{}_END_({_NO_RESPECTDOS_})
_C{ END OF PHYSICAL DISK PARAMETERS}
})_C{}_END_({_RWSECTRK_})
_BOOTLBA_({
_C{ The first gigabyte of the disk is divided into chunks, }
_C{ the size of the core memory to alternately boot from, as a backup.}
CHUNKSIZE EQU 0x80 * 0x100000 _C{ 128 Mb. }
_C{Size in sectors. }
MAXCHUNK EQU 1024 *0x100000 /CHUNKSIZE
_C
})_C{}_END_({_BOOTLBA_})
_HOSTED_DPMI_({
_C{DPMI segment defines.}
_C{We can't aim for better than level privilege level 3.}
BITS32_TOGGLE EQU 0x040 _C{ The Big (and Granularity, not yet) bits are complemented}
_C{ on switching to 32 bits mode in 6th byte.}
CODE_TOGGLE EQU 0x08 _C{ Toggle between code and data, in the 5th byte.}
})_C{}_END_({_HOSTED_DPMI_})
_SWITCH_({
_C{ Segments * Valid in real mode % Valid in protected mode }
_C{ Names starting in A_ are linear, physical (32 bit), absolute addresses }
RSTSIZE EQU 0x10000 _C{ For real mode stack. }
GDTSIZE EQU 0x8000 _C{ For GDT-table.}
IDTSIZE EQU 0x0800 _C{ For IDT-table. Not yet used. }
A_FORTH0 EQU M4_LOADADDRESS - M4_ORG _C{ Physical address of Forth's CS:0 = SS:0 = ES:0 . }
A_SWITCH EQU M4_SWITCHORG
A_RST EQU A_SWITCH + 0x10000
A_GDT EQU A_RST + RSTSIZE
A_IDT EQU A_GDT + GDTSIZE _C{ reserved but not yet used. }
A_LOWDP EQU A_IDT + IDTSIZE _C{ Must become this. }
_C{ * Real mode place for the stack.}
_C{ This is such that after switching to real mode an isolated }
_C{ Stack is available }
SS_RST EQU A_RST/0x10 _C
SWITCHSEGMENT EQU A_SWITCH/0x10 _C{ * DS and CS for real code }
_C{ Add this to go from GDT_CS addresses to GDT_SWITCH addresses.}
M4_SWITCHOFFSET EQU ( A_FORTH0 - M4_SWITCHORG)
_C{ The GDT_.. are offsets in the GDT table. They can be arbitrarily chosen }
_C{ as far as the GDT goes as long as they are a multiple of 0x08 }
_C{ Switching sometimes restricts these to a particular value.}
GDT_SWITCH EQU SWITCHSEGMENT _C{ % Switching segment, must be same for switching to work! }
GDT_CS EQU 0x10 _C{ % The protected mode code segment }
GDT_SS EQU SS_RST _C{ % The protected mode data segment}
GDT_DS EQU SS_RST _C{ % The protected mode data segment}
GDT_SEGMENT EQU A_GDT/0x10 _C{ * General descriptor table.}
IDENTIFY_16 EQU 0x008F _C{ Identification of 16 bit data/code segment, byte 6}
IDENTIFY_32 EQU 0x00CF _C{ Identification of 32 bit data/code segment, byte 6}
IDENTIFY_INT EQU 0x8E00 _C{ Identification of an interrupt descriptor, byte 5}
IDENTIFY_XR EQU 0x9A00 _C{ Identification of a code segment, execute read, byte 5}
IDENTIFY_RW EQU 0x9200 _C{ Identification of a data segment, read write, byte 5}
GDTLEN EQU GDTSIZE-1 _C{ Intel peculiarity.}
BOOTOFFSET EQU 0
})_C{}_END_({ _SWITCH_})
_HOSTED_LINUX_({
_BITS32_({include(constant_32.m4) })
_BITS64_({include(constant_64.m4) })
RAWIO EQU (ECHO _OR_ ICANON)
_LINUX_C_({Called from c. Remainder c-routines to be called from here.
extern c_type,c_expec,c_key,c_qterm
extern c_rslw, c_block_exit, c_block_init, c_debug
GLOBAL ciforth})
})_C{}_END_({ _HOSTED_LINUX_})
_HOSTED_OSX_({
include(constant_osx.m4)
RAWIO EQU (ECHO _OR_ ICANON)
})_C{}_END_({ _HOSTED_OSX_})
_PC_({
create EQU 0x3C00
open EQU 0x3D00
close EQU 0x3E00
read EQU 0x3F00
write EQU 0x4000
delete EQU 0x4100
lseek EQU 0x4200
EPIPE EQU 38
})_C{}_END_({ _PC_})
_HOSTED_X_({
_C This applies to any elf-like binaries.
_TEXT_
PAGE
GLOBAL _start _C Entry point's guesses.
GLOBAL start _C Entry point.
GLOBAL _main _C Entry point.
_ORIG:
_start: _C Entry point.
})_C{}_END_({ _HOSTED_X_})
_DLL_({
EPIPE EQU 109 _C{ " broken pipe " }
_C
_IDATA_
dd 0,0,0,rva kernel_name,rva kernel_table
dd 0,0,0,0,0
kernel_table:
_ExitProcess@4 DC rva _ExitProcess
CreateFile DC rva _CreateFileA
_CreateProcessA@40 DC rva _CreateProcess
_ReadFile@20 DC rva _ReadFile
_WriteFile@20 DC rva _WriteFile
CloseHandle DC rva _CloseHandle
SetFilePointer DC rva _SetFilePointer
_GetCommandLineA@0 DC rva _GetCommandLineA
GetEnvironmentVariable DC rva _GetEnvironmentVariable
_DeleteFileA@4 DC rva _DeleteFileA
_GetConsoleMode@8 DC rva _GetConsoleMode
_GetProcAddress@8 DC rva _GetProcAddress
_GetStdHandle@4 DC rva _GetStdHandle
_LoadLibraryA@4 DC rva _LoadLibraryA
_GetLastError@0 DC rva _GetLastError
_PeekConsoleInputA@16 DC rva _PeekConsoleInputA
_ReadConsoleA@20 DC rva _ReadConsoleA
GetTickCount DC rva _GetTickCount
GetSystemTime DC rva _GetSystemTime
GlobalMemoryStatus DC rva _GlobalMemoryStatus
_SetConsoleMode@8 DC rva _SetConsoleMode
_Sleep@4 DC rva _Sleep
DC 0
kernel_name db _BITS64_({'KERNEL32.DLL'})_BITS32_({'KERNEL32.DLL'}),0
_ExitProcess dw 0
db 'ExitProcess',0
_CreateFileA dw 0
db 'CreateFileA',0
_CreateProcess dw 0
db 'CreateProcessA',0
_ReadFile dw 0
db 'ReadFile',0
_WriteFile dw 0
db 'WriteFile',0
_CloseHandle dw 0
db 'CloseHandle',0
_SetFilePointer dw 0
db 'SetFilePointer',0
_GetCommandLineA dw 0
db 'GetCommandLineA',0
_GetEnvironmentVariable dw 0
db 'GetEnvironmentVariableA',0
_DeleteFileA dw 0
db 'DeleteFileA',0
_GetConsoleMode dw 0
db 'GetConsoleMode',0
_GetProcAddress dw 0
db 'GetProcAddress',0
_GetStdHandle dw 0
db 'GetStdHandle',0
_LoadLibraryA dw 0
db 'LoadLibraryA',0
_GetLastError dw 0
db 'GetLastError',0
_PeekConsoleInputA dw 0
db 'PeekConsoleInputA'
_ReadConsoleA dw 0
db 'ReadConsoleA'
_GetTickCount dw 0
db 'GetTickCount',0
_GetSystemTime dw 0
db 'GetSystemTime',0
_GlobalMemoryStatus dw 0
db 'GlobalMemoryStatus',0
_SetConsoleMode dw 0
db 'SetConsoleMode',0
_Sleep dw 0
db 'Sleep', 0
_ALIGN(_CELLS(1))
_TEXT_
_main:
_ORIG:
})_C{}_END_({ _DLL_})
dnl
_BOOTED_({ dnl
_C{ ########################################################################################}
_C{ BOOTCODE (optional, always real mode)}
_C{ ########################################################################################}
_C{ All bootcode must be relocatable and its memory references absolute.}
_C{ Not for the sake of booting, but to allow MSDOS to start the program too. }
CSEG SEGMENT PARA PUBLIC 'CODE'
ASSUME CS:CSEG,DS:CSEG,SS:CSEG,ES:CSEG
})_C{}_END_({ _BOOTED_})
dnl
_ABSOLUTELOAD_({ ORG M4_ORG})
_BOOTED_(_REAL_({ORG 0x100
_C{ Accommodate also .exe files} }))
_BOOTSECTRK_({
_ORIG:
JMP SHORT BOOT
NOP
_C{ MSDOS programmers reference (thru 6, 3.9)}
DB "{DFW}--EXP"
BBPS DW BPS
DB 1
RESSECTORS DW 0x01
DB NFAT
DW BPS*SECROOT/32
DW HEADS*TRKS*SPT _C{ sectors/drive}
BDRIVE _C{ True meaning. BIOS drive id.}
BMEDIA DB MEDIA _C{ Temporary meaning, nS after booting.}
DB SECFAT, 0x0
BSPT DW SPT
BHEADS DW HEADS
HIDDENSECS DD 0x0
HUGESECS DD 0x000
_C{ BIOS parameter block ends here}
DB 0x000, 0x000, 0x029 _C{ Required magic.}
DB 0x004, 0x01C, 0x040, 0x00B
DB " "
DB "FAT12 "
_C{ Read the sector with number in CX (Counting from 0) to ES:BX.}
_C{ Keep BX, CX }
READSECTOR:
PUSH CX
PUSH BX
MOV AX,CX
MOV CL,[BSPT]
DIV CL
MOV CL,AH
INC CL _C{ Sectors counting from 1!}
XOR AH,AH _C{ Get rid of remainder}
MOV CH,[BHEADS]
DIV CH
MOV DH,AH _C{ Head number}
MOV CH,AL _C{ Only small disks <256 cylinders}
MOV DL,[BDRIVE]
MOV AX,0x0201 _C{ Read absolute one sector}
INT(0x13) _C{BIOS disk access.}
POP BX
POP CX
RET
RETRY:
CALL DISPLAYW
XOR AX,AX _C{ Reset}
MOV DL,[BDRIVE]
INT(0x13) _C{BIOS disk access.}
CALL DISPLAYW
MOV AL,' '
CALL DISPLAY
MOV AX,CX
CALL DISPLAYW
MOV AL,' '
CALL DISPLAY
BOOT:
_C{ Start with replacing braindamaged media byte drive id.}
MOV DL, 0x80 _C{ Hard disk, default.}
MOV AL, [BMEDIA]
CMP AL, 0x0F8 _C{ Fixed disk.}
JZ ENDIF1A
MOV DL, 0x0 _C{ Floppy.}
ENDIF1A:
MOV [BDRIVE],DL
MOV AL,'D'
CALL DISPLAY
MOV AX,CS
AND AX,AX _C{ Z = BOOTING ?}
JZ ENDIF1B
JMP NOBOOT
ENDIF1B:
MOV AL,'F'
CALL DISPLAY
MOV AH,00 _C{ Reset}
MOV DL,[BDRIVE]
INT(0x13) _C{BIOS disk access.}
JB RETRY
_C{ The first file copied to a freshly formatted floppy will}
_C{ be at SECSTRT (See also genboot.bat)}
MOV CX,SECSTRT _C{ Counting from zero}
MOV AX,BOOTADDRESS/0x10 _C{ Bootsegment}
MOV ES,AX
MOV BX,BPS
BEGIN1: CALL READSECTOR
INC CX
ADD BX,BPS
JB RETRY
CMP BX,RELATIVE_WRT_ORIG(TEXTEND)
JB BEGIN1
MOV AL,'{W}'
CALL DISPLAY
CALL DISPLAYCR
MOV AL, [BHEADS] _C{Copy from boot sector to Forth.}
MOV [LFHEADS],AL
MOV AL, [BSPT]
MOV [LFSPT],AL
MOV AL, [BDRIVE]
MOV [LFDRIVE], AL
JMP ENDBOOT
})_C{}_END_({ _BOOTSECTRK_})
_BOOTLBA_({
_ORIG:
JMP SHORT BOOT
NOP
_C{ MSDOS programmers reference (thru 6, 3.9)}
DB "{DFW}---HD"
BBPS DW BPS
DB 1
RESSECTORS DW 0x01
DB NFAT
DW BPS*SECROOT/32
DW SPDRV
DB MEDIA
DB SECFAT, 0x0
DW SPT
DW HEADS
HIDDENSECS DD 0x0
HUGESECS DD 0x000
_C{ BIOS parameter block ends here}
DB 0x000, 0x000, 0x029 _C{ Required magic.}
DB 0x004, 0x01C, 0x040, 0x00B
DB " "
DB "RAW "
BOOTLBA: DB 0x10, 0
_C{ Rounds down, we already have 1 sector. For HD always load 64K.}
_C{ Bootstrap for ci has to reside in this first part.}
DW 0x0FFFF/BPS
DW BPS _C{ OFFSET AND SEGMENT}
DW SWITCHSEGMENT
STARTSECTOR: _C{ HD Start sector, do be chosen by key press.}
DD 1 _C{ Start}
DD 0 _C{ M.S. 32 BITS}
HDREAD:
MOV AX,SWITCHSEGMENT
MOV DS,AX
MOV SI,RELATIVE_WRT_ORIG(BOOTLBA) _C{ DS:SI absolute address of lba.}
MOV AX,0x4200 _C{ Read extended }
MOV DX,0x0080 _C{ Disk C }
INT 0x13
RET
RETRY:
CALL DISPLAYW
MOV AL,' '
MOV AH,00 _C{ Reset}
MOV DL,80 _C{Drive 80 (hd C:)}
INT(0x13) _C{BIOS disk read function}
CALL DISPLAYW
MOV AL,' '
CALL DISPLAY
MOV AX,CX
CALL DISPLAYW
MOV AL,' '
CALL DISPLAY
BOOT:
MOV AL,'D'
CALL DISPLAY
MOV AX,CS
AND AX,AX _C{ Z = BOOTING ?}
JNZ NOBOOT
MOV AL,'F'
CALL DISPLAY
MOV AH,00 _C{ Reset}
MOV DL,80 _C{Drive 80 (hd C:)}
INT(0x13) _C{BIOS disk read function}
JB RETRY
CALL GETKEY
JNB ENDIF
PUSH AX
CALL DISPLAY
POP AX
SUB AL, '0'
JB ENDIF
CMP AL, MAXCHUNK
JNB ENDIF
AND EAX, 0x0FF
MOV ECX, CHUNKSIZE/BPS
MUL ECX
INC EAX
MOV [STARTSECTOR],EAX
ENDIF: CALL HDREAD
JB RETRY
MOV AL,'{W}'
CALL DISPLAY
CALL DISPLAYCR
JMP ENDBOOT
})_C{}_END_({ _BOOTLBA_})
_BOOTED_({
_C{ Debug code, could be dispensed with in an ideal world.}
DISPLAYCR:
MOV AL,ACR
CALL DISPLAY
MOV AL,ALF
JMP DISPLAY
DISPLAYPC: POP AX
PUSH AX
DISPLAYW: PUSH AX _C{ Display AX in hex }
MOV AL,AH
CALL DISPLAYHEX
POP AX
_C{ CALL DISPLAYHEX _C{ RET}}
DISPLAYHEX: PUSH AX _C{ Display AL in hex }
MOV CL,4
SAR AL,CL
CALL DISPLAYHD
POP AX
_C{ CALL DISPLAYHD _C{ RET}}
DISPLAYHD: AND AL,0x0F _C{ Display AL as one hex digit}
DAA
MOV AH,AL
MOV CL,5
SHR AH,CL
ADC AL,0x30
_C{ CALL DISPLAY _C{ RET}}
DISPLAY:XOR BH,BH _C{ Display AL as an ASCII char}
MOV AH,0x0E
INT(0x10)
RET
GETKEY: MOV AH, 0x01 _C{ If CARRY, a key sits in AL. }
INT(0x16)
JNB ENDIF1
MOV AH, 0x00 _C{ Consume the key. }
INT(0x16)
ENDIF1: RET
})_C{}_END_({ _BOOTED_})
NOBOOT: _C{ Skip till here if not booting.}
_ABSOLUTELOAD_({
_C{ Apparently we may have to move the code, e.g. if started from MSDOS.}
_C{ Prepare return to MSDOS using the original code segment.}
MOV AX,CS
MOV DS,AX
CALL HERE1
HERE1: POP BX
MOV CX,BX
ADD BX,RETDOSV-HERE1+1 _C{ Independant of load address.}
ADD CX,RETDOS-HERE1
MOV [BX],CX
INC BX
INC BX
MOV [BX],AX
JMP ENDBOOT _C
_C{ Returns to DOS, provided we started from dos as a .COM.}
_C{ Use far jump restoring CS to .COM value. }
RETDOS:
MOV AX,CS
MOV DS,AX
MOV ES,AX
MOV SS,AX
MOV AH,0x4C
INT 0x21 _C{ Only works if cs is the same as while starting.}
})_C{}_END_({ _ABSOLUTELOAD_})
ENDBOOT:
_HOSTED_MSDOS_({
_C{ ########################################################################################}
_C{ ADJUST CODE SEGMENT REGISTER (still real mode)}
_C{ ########################################################################################}
_C{ Required start of .COM program.}
_REAL_(
{ ORG 0x100
_ORIG: _C{ Accommodate also .exe files} })
_MODERN_(
{ MOV BX, (EM-1)/0x10+1
MOV AH,0x4A _C{Modify memory allocation}
INT 0x21})
})
_ABSOLUTELOAD_({
_C{ ########################################################################################}
_C{ MOVE CODE TO ITS PLACE (still real mode)}
_C{ ########################################################################################}
_C{ Take care of the situation where booting code is actually started up by }
_C{ MSDOS. This is no problem as long as the code is moved to where it would }
_C{ be if booted. If the code is at its place, nothing really happens here. }
_C{ Furthermore all protected code started by MSDOS must be at an absolute address.}
STD _C{ Start at the end going back.}
MOV CX,TEXTEND-HERE5 _C{ Amount to move}
CALL HERE6
HERE6: POP AX _C{ Calculate address of the first byte to move}
ADD AX,TEXTEND-HERE6-1
MOV SI,AX _C{ Relocatable address, w.r.t code segment.}
MOV AX,CS
MOV DS,AX
MOV AX, A_FORTH0/0x10 _C{ Destination segment}
MOV ES, AX
MOV DI, TEXTEND-1
REPNZ
MOVSB
PUSH ES _C{ Corrected code segment}
MOV BX, HERE5
PUSH BX _C{ Correct program counter}
RETF _C{ Returning to here5 now}
HERE5:
MOV AX,CS
MOV DS,AX
MOV ES,AX
MOV SS,AX
CLD _C{ Reset direction to going up.}
})_C{}_END_({_ABSOLUTELOAD_})
_SWITCH_({
_C{ ########################################################################################}
_C{ FILL GDT AND SWITCH TO PROTECTED MODE/32 BITS (optional)}
_C{ ########################################################################################}
JMP PROTECT
GDTLOAD DW GDTLEN
DD A_GDT
PROTECT:
_C{Prepare. Remember STOSW uses ES:DI }
MOV AX,GDT_SEGMENT _C{ GDT segment}
MOV ES,AX
MOV DI,0
MOV AX,GDTLEN
STOSW
_C{ The switch segment. }
_C{ Switch between real and (16-bit) protected mode is done,}
_C{ while using this segment (Relocatable code only).}
_C{ GDT_SWITCH can to an extent be chosen arbitrarily,}
_C{ as long as here we ensure that the real mode address }
_C{ is equal to the protected mode address. }
_C{ You can only switch while staying at the same physical address}
_C{ when you are currently executing in the range GDT_SWITCH:[0:FFFFH] }
MOV BX,GDT_SWITCH
MOV DI,BX
MOV AX,0x0FFFF
STOSW
SHL BX,4 _C{ Turn segment register into IP}
MOV AX,BX
STOSW
MOV AX,IDENTIFY_XR
STOSW
MOV AX,IDENTIFY_16
STOSW
_C
_C{ GDT_DS/GDT_SS to an extent be chosen arbitrarily,}
_C{ The real mode view of GDT_SS is valid, isolated and reserved for real stack.}
_C{ DS is reset after switching anyway.}
_C{ Accommodate a 24 bit start address, a maximal limit, large pages. }
MOV DI,GDT_SS _C{Identical to GDT_DS}
MOV AX,0x0FFFF
STOSW
MOV EAX,A_FORTH0
STOSW _C{ Only 16 bits}
SHR EAX,8
ADD AX,IDENTIFY_RW
STOSW
MOV AX,IDENTIFY_PROT
STOSW
_C{ PREPARE-CS 16/32 BITS }
MOV DI,GDT_CS
MOV AX,0x0FFFF
STOSW
MOV EAX,A_FORTH0
STOSW _C{ Only 16 bits}
SHR EAX,8
ADD AX,IDENTIFY_XR
STOSW
MOV AX,IDENTIFY_PROT
STOSW
LEA BX,[GDTLOAD]
LGDT [BX]
})_C{}_END_({ _SWITCH_})
_HOSTED_MSDOS_({
PUSH DS
MOV AX,0
MOV DS,AX
LEA AX,[WARM_ENTRY]
LEA BX,[4*0x23]
MOV [BX],AX _C{Jump to WARM_ENTRY on <CTRL-BREAK>}
INC BX
INC BX
MOV AX,CS
MOV _CELL_PTR[BX], AX
POP DS
ENDREADJUST:
})_C{}_END_({ _HOSTED_MSDOS_})
_BOOTED_({
JMP ENDREADJUST
_NEW_ORG(0x01FE)
_C{ Signature. Last piece of boot sector. }
DB 0x055, 0x0AA
ENDREADJUST:
})_C{}_END_({ _BOOTED_})
_SWITCH_({
_C{ Remember: we are now in the real mode for a protected model.}
_C{ Make sure we are in the switch segment, such that we can switch.}
MOV BX,CS _C{ Reality.}
MOV AX, GDT_SWITCH _C{ Dream.}
PUSH AX _C{ Correct code segment}
SUB AX,BX _C{ Discrepancy between dream and reality}
MOV CX,0x10 _C{ How much units would that be for the IP?}
CWD
MUL CX
CALL HERE3
HERE3: POP BX _C{ Reality.}
SUB BX,AX _C
ADD BX,THERE4-HERE3
PUSH BX _C{ Corrected program counter}
RETF _C{ Returning to THERE4 now}
_BITS16_({THERE4:})
_BITS32_({
_C{ 32 bit protected mode is no good unless the A20 address line works.}
_C{ The following tedious code is copied from the nuni startup code}
_C{ for linux. }
KB_WAIT:
IN AL,0x64
AND AL,2
JNZ KB_WAIT
RET
THERE4:
CALL KB_WAIT
MOV AL,0x0D1
OUT 0x064,AL _C{ Enable a20}
CALL KB_WAIT
MOV AL,0x0DF
OUT 0x060,AL
})_C{}_END_({ _BITS32_})
})_C{}_END_({ _SWITCH_})
dnl
_HOSTED_DPMI_({
_C{ ########################################################################################}
_C{ PREPARE FOR USING DPMI (OPTIONAL)}
_C{ ########################################################################################}
_C{ Required start of .COM program.}
ORG 0x100 _C{ Accommodate also .exe files}
_ORIG:
_C{ These are real mode descriptors !}
MOV WORD[SaveCS],CS _C{ Once and for all}
MOV WORD[SaveDS],DS
MOV WORD[SaveES],ES _C{ Still pointing to PSP (!?)}
})_C{}_END_({_HOSTED_DPMI_})
_MODERN_({
MOV [LOADEXEC+4], DS
MOV [LOADEXEC+8], DS
MOV [LOADEXEC+12], DS
_C{Must be done before switching to protected mode.}
MOV AX, [ES:0x2C]
MOV [USINI+_CELLS(31)],AX _C{Remember ENV pointer.}
MOV [LOADEXEC], AX
})_C{}_END_({_MODERN_})
_HOSTED_DPMI_({
_C{ Do a double precision shift to find number of paragraphs. }
MOV BX, [DPA]
MOV CL,4
SHR BX,CL
MOV AX, [DPA+2]
MOV CL,12
SHL AX,CL
OR BX,AX
OR BX, 0x0FFF _C{Minimum is 64 K for RW-BUFFER .}.
INC BX
MOV AH,0x4A _C{Modify memory allocation to what is needed.}
INT 0x21
_C
_C{ Check to see if DPMI is available, and make the switch if it is}
_C{ If one is, the stat info is stored.}
MOV BL,1
MOV AX,0x1687 _C{Get DPMI host address}
INT 0x2F _C{Multiplex interrupt}
CMP AX,0 _C{Was it there?}
JNE ERRMSG _C{Nope, so exit}
AND BL,1 _C{Test bit 1 (32-bit OK?)}
MOV [DPMIentry+0],DI
MOV [DPMIentry+2],ES
PUSH SI _C{Allocation.}
MOV AX,0 _C{In case no memory needed}
POP BX _C{Get number of paragraphs needed by host}
CMP BL,0 _C{Any allocation needed?}
JE Plunge _C{No, so continue}
MOV AH,0x48 _C{Allocate memory}
INT 21h
MOV BL,2
JC ERRMSG _C{Could not allocate}
Plunge: MOV ES,AX
_C{Setting this bit, doesn't mean you arrive in a 32 bit segment!}
MOV AX, _BITS16_(0) _BITS32_(1)
_CALL_FAR_INDIRECT(DPMIentry) _C{Switch to protected mode}
_C{ From here to where the assembler switches to protected mode,}
_C{ code must be 16/32 bit independant.}
MOV BL,3
JC ERRMSG _C{still in real mode}
JMP SHORT DPMISUCCESS
_C{ Data used by DPMI.}
DPMIentry DW 0000,0000
_C{Error-- called from diverse places.}
ERRMSG:
MOV AL, BL _C{ Use the infamous errorlevel.}
MOV AH,0x4C
INT 0x21
_C{ If we reach this point, we are operating in protected mode}
DPMISUCCESS:
_C{ -------------- First and for all: save --------}
MOV WORD[Save_CS_PR],CS
MOV WORD[Save_DS_PR],DS
MOV WORD[Save_ES_PR],ES
_C{ -------------- Get a new segment for our Forth to ES --------}
MOV AX,0x0000 _C{A new selector.}
MOV CX,1
INT 0x31
MOV BL,4
MOV ES,AX
JC ERRMSG
MOV AX,0x0501 _C{Allocate memory}
MOV BX, WORD[LEM+_CELLS(D_HOFFSET)+2] _C{Split into two words}
MOV CX, WORD[LEM+_CELLS(D_HOFFSET)]
INT 0x31