Modified July 12, 2017                                                                                           May the FORTH be with you!

The 32-bit GFOS (Graphical Forth Operating System) was written entirely in assembly with NASM (Intel, minimum PENTIUM). It has been tested with emulators (BOCHS and QEMU) and on real hardware (an old desktop and on a laptop: Dell D820). The bochs-config file can be found in gfos.zip
This OS doesn't use the mouse (it's best to unplug it).
It has most of the words from ANSI Forth. The main things that are missing are the double cells, value, locals and ;code. The double-cells was a good idea in the 16-bit world.  GFOS is case insensitive. There is one dictionary and one hash-table (djb2 algorithm). The hash-table is 20000 long with a list in each slot (20000*16). This speeds up the search. forth.asm in the source is very well commented and the source of YForth should also be checked (it's written in C and can be downloaded from this page).
- Multitasking
- IDE HDD support
- Floating Point
- 1024*768*16
- USB (EHCI, UHCI; so USB2.0) pendrive support (sectors/files) 
- HD Audio driver               [currently ICHx only]
- Can play (uncompressed) wav, and can display bmp-s
- Boots from winchester(also from USB pen-drive), floppy, CD-with-floppyemulation (from floppy and disk also with Bochs)
A Bitmap Font Editor is also available (BFEditorTk.zip, written in python 3.5.1; install python3 and python3-tk packages on Debian or Ubuntu; start with python3 ./bfeditorapp.py) in order to facilitate the design of charsets for high resolution in GFOS (e.g. 16*24 fonts for 1024*768).
A Truetype-font reader can be downloaded (TTFTest.zip; written in python3 with tkinter). Start with:
python3 ./ttftestapp.py
and click on the window. 'A' will appear. Currently only simple-glyphs are supported (so no composite (or compound glyphs).
The Memory-map can be found at the beginning of forth.asm.


Large letter F from Starting Forth:

The best FORTH tutorial:
Can also be downloaded from this page.

YForth was written in C and it helped a lot (it's not an OS):

Planned features:
- xHCI
- Get USB working with most of the pendrives
- Minimal 3D pipeline (!?) [Cube, Pyramid and Sphere with clipping]
- Local filesystem (FAT32; 8.3 only, i.e. SFN); Blocks will also be available
- Rewrite everything that is possible in Forth
- 64-bit OS
- Move dictionary (and everything after it) to the longest continuous memory-region and everything goes to the dictionary (files from USB, blocks from disk!?) !? FORGET will remove them later.

There is a little difference currently between ANSI Forth (or FigForth) and GFOS. For example:
- PAD and SP0 needs @ (e.g. "pad @ .")
- TIB and #TIB is used in the code of GFOS but INPBUFF and #INPBUFF need to be used in GFOS because the source can be a file (maybe soon in GFOS) and not only the TIB:
is equivalent to "TIB #TIB @ TYPE" in SF chapter 10.
- The structure of a dictionary entry (a word):
BYTE(type) BYTE(length) BYTES(name with delimiter at the end).
CODE-PTR (or execution token, xt)
DPTOXT-OF-RuntimecodeOfSemiColon i.e. (EXIT)

The type-byte tells us whether the word is an IMMEDIATE, EXEC-ONLY, COMP-ONLY word or not and also shows if the word is a USER, VARIABLE, COLON, CONSTANT, CREATE, FCONSTANT, FVARIABLE word or not. Since IMMEDIATE, EXEC_ONLY and COMP_ONLY bits are in the type-byte and not in the length-byte, GFOS can read strings that are 255 charaters long (e.g. file-paths).
The DPTOXTs mean not the pointers to the runtime-codes of the words but the pointers to the xts of those words in their dictionary entries. So we need to apply an extra indirection. DPTOXT is dictionary pointer to xt (i.e. execution token).
This was necessary because e.g. a VARIABLE can be in a colon-definition and that variable needs to find its value.

- ' (TICK) (caddr -- dptoxt) and >BODY (dptolink -- dptoxt) in GFOS, so there is no need for >BODY in GFOS in the example in SF chapter 10:
FOS> : test ." Sample" ;
FOS> ' test cell+ cell+ 1+ 1+ 7 type

After tick our ptr points to dptoxt of test. Next the cell+ will point to the runtime-code of ." .
The next cell+ will point to the type-byte of the string (sample). 1+ will point to the length byte. 1+ will finally arrive to the first char of our string.
So WORD will create TYPE LENGTH CHARSofSTR bytes in the dictionary when reads a word.

- How to wait for a KEY:
FOS> : test  begin key 97 = until discard ;
Executing TEST will wait till we press 'a' then it discards the character.

- Number formatting:
FOS> : PrintDate  <# # # [char] / hold # # [char] / hold #s #> type space ;
FOS> 20001021 PrintDate
will print:

SEE currently only does a memdump:

The words between left  and right parenthesis are run-time codes, e.g. (EXIT) is the run-time code of EXIT or (VARIABLE) is the run-time-code for VARIABLE, it pushes the address of the variable on the parameter-stack.

There is an interrupt handler installed for every 255 interrupt, so we will immediately know which unwanted interrupt got fired.
Just remove the printing of a text and infinite loop in the handler in idt.inc and simply return with iret.

Floating Point

Extended precision is used (80-bits). Numeric(e.g. 31415.67) or scientific notation(e.g. 3.1415e+23) can be used. A dot ('.') is necessary in order the number to be treated as a float.
A float with an exponent of less or equal to 10 will be printed in numeric format, otherwise scientific notation will be used.
ABORT clears the stacks and inits FPU. And of course, there is REBOOT.
Most of the words beginning with letter 'f' are float-related and use the float-stack:
60.0 fradians fsin f.
0.86602540378443865 ok


Hard Disk

IDE hard disk driver and PCI-related words were added:
HDINFO ( -- )
HDWRITE ( MemAddr SectCnt LBAHi LBALo -- Flag )
HDREAD ( MemAddr SectCnt LBAHi LBALo -- Flag )
HDWRITEDMA ( MemAddr SectCnt LBAHi LBALo -- Flag )  // calls PAUSE
HDREADDMA ( MemAddr SectCnt LBAHi LBALo -- Flag )   // calls PAUSE
PCILS ( -- )
PCICFG ( bus device function -- )

and also the block-related words:
BLOCK (u -- addr )
BUFFER ( u -- addr)
FLUSH ( -- )
LIST ( u -- )
LOAD ( u -- )
RESTORE-INPUT ( xn ... x1 n -- flag )
SAVE-INPUT ( -- xn ... x1 n )
UPDATE ( -- )
BUFF ( -- u )
BLK ( -- addrofblocknumber)
SCR ( -- addressofbufferoffset)

HDINSTALL installs the bootloader and the kernel on the hard disk
It uses as many sectors of the hard disk as it can be seen in hdloader.asm.
So, if the boot is changed to "disk" in bochs-config then GFOS will boot from hard disk.
Note that old non-LBA winchesters (C, H, S)  weren't tested.

Write the first 512-bytes (1 sector) of the dictionary to the 10th sector of the winchester, then read it back to 0x20000000:

After boot GFOS tries to configure the PCI devices in order to support SATA winchesters that can be switched to legacy/compatibility mode too.
Currently only Intel(ICH7) and AMD(SB7) chipsets are supported (lspci on Linux will show it).
This means that the OS will do what BIOS does when we set it to "SATA as IDE" and "SATA Run Mode Configuration: Compatible".
In case the OS can't detect the winchester a "HD: Couldn't detect" text will be printed.
AHCI-only SATA winchesters are not supported, because there is no AHCI driver.

The code of the "Large letter F" can be entered:
1 LIST              // lists the content of Block 1 (1024 bytes)
Press F5          // Clears the screen i.e. fills the screen with spaces if there is garbage.
Enter the words
Press Esc
UPDATE           // Marks the current block as modified. The current-block is the one we last LISTed or the one we loaded into buffer with BUFFER or BLOCK.
SAVE-BUFFERS   // Saves the modified blocks to disk
1 LOAD           // Loads the words from block 1 into the dictionary

A block is two sectors (1024 bytes) and there are ten buffers, so ten blocks can be in memory at the same time.

The word LOADM ( addr length -- ) is also available. addr is the address of the code in RAM, length is its size in bytes.
It can be inconvenient to enter a long code in the editor of GFOS.
How to load vecmat.txt and cube.txt:
USBENUM  .      (the pendrive has devaddress 2)
2 USBFSINIT  .  .  .  .
20000000 USBFSREAD vecmat.txt"  .  .   
20000000 16F7 LOADM
HEX     ( the code in vecmat.txt switches to DECIMAL)
20000000 USBFSREAD cube.txt"  .  .   
20000000 16A8 LOADM

20000000 USBFSREAD rotcube.txt" . .
20000000 2901 LOADM



1024*768*16 is supported. The related words:
CIRCLE (x y r clr -- )
FCIRCLE (x y r clr -- )  filled circle
CLRSCR ( -- )  clears the screen
INVSCR ( -- ) invalidates screen, i.e. copies the screenbuffer to framebuffer
INVSCRRECT (x y w h -- )
LINE ( x1 y1 x2 y2 clr -- )  Cohen-Sutherland clipping
POLY (x1 y1 x2 y2 ... xn yn clr coordscnt -- ) polygon; Sutherland-Hodgeman clipping
FPOLY (x1 y1 x2 y2 ... xn yn clr coordscnt -- ) filled polygon; Sutherland-Hodgeman clipping
PAINT ( x y clr -- )
PIXEL (x y clr -- )
PUTCUR ( -- ) shows cursor
REMCUR ( -- ) hides cursor
BMPINFO (memaddr -- )
BMPVIEW (memaddr x y -- )
OUTP ( -- ) displays the output of the last word (max 20 screens) [displayed with current colors (fg, bkg)]
TXTVW (addr len -- ) displays text-file from addr and len bytes long (addr must be 64-byte aligned: last 6 bits zero)

See docs/fthsrc/cube.txt. It draws two cubes with different colors, rotations and translations.
Scaling, Shearing, Rotation and Translation are used.
docs/fthsrc/rotcube.txt creates two rotating cubes (one per task) with different colors, rotations, translations and speed.
Having stopped the two tasks, they can be restarted by:
Still missing is the visibility-algorithm(i.e. Painter's algorithm or BSP-trees).
See section on "Hard Disk" for a how-to load (or you can split the code to blocks).

-30 100 500 200 800 700 63488 3 POLY INVSCR
-30 100 500 200 800 700 63488 3 FPOLY INVSCR
FPOLY can fill concave polygons too.

Having loaded a bmp to 0x20000000:
20000000 BMPINFO
20000000 100 0 BMPVIEW INVSCR     (decimal x=256)
We don't need to execute BMPINFO before BMPVIEW.
- 8BPP (uncompressed or RLE8 compressed)
- 16BPP (with or without BITFIELDS)
- 24BPP, 32BPP (uncompressed)
An "Unsupported bmp format" message will be printed otherwise.

The control chars get displayed in the last line of the screen of OUTP and TXTVW: PGUP, PGDN, HOME, END, UP, Down.
It is only worth to use OUTP if part of the output of the last word gets scrolled out of the screen.

How to change system-colors:
63488 16 LSHIFT
2016 OR
changes the fg-color to red and the bkg-color to green

63488 16 LSHIFT
changes the color of the cursor to red

It is easy to switch to graphics.
In loader.asm the vga-related code should be uncommented:
- %include "vga.inc"
- the code after VGAInfo
- and the code after EnterStage3

After boot, still in real mode (16-bit), the info will be printed about the available screen resolutions (and if there is a linear-framebuffer) thanks to the code after VGAInfo.
The code after EnterStage3 switches to graphic-mode. So in real mode with BIOS we switch to graphics and only then will we switch to protected mode(PM) (BIOS is not available in PM). The linear framebuffer is e.g. from 0xE0000000, so that is where e.g. 1024*768*16 begins. We just need to write to that memory in order to put pixels.

Programming the VGA-card directly without BIOS:


The code that sets the memory-region of the LinearFrameBuffer to WriteCombined has been implemented (see kernel.asm for details).
Try to activate it in kernel.asm, because if it works, the graphics will be about 10 times faster. I could only test it on one computer.


Cooperative multitasking with Round-Robin scheduling.
Maximum 100 tasks can be executed at the same time.

ACTIVATE ( taskid -- ) Creates a new task and executes it immediately
TERMINATE ( -- ) Terminates the current task
PAUSE ( -- )  Switches tasks
KILL ( taskid -- ) Kills the taskid-task
SUSPEND ( taskid -- ) Suspends the taskid-task
RESUME ( taskid -- ) Resumes the taskid-task
TASK (  -- taskid ) Reserves the first UNUSED taskstruct, copies the name of the task to it, and creates a variable with this name and stores the taskid there. taskid is zero, if there is no free taskstruct. Maximum 31 chars of taskname will be saved. E.g. "TASK HelloWord".
GETTBUFF ( -- taskid taskbuff)
USER (<spaces>name -- ) Defines a USER variable. Execution of name will return the address of its data space from the user-table of the current task
FUSER (<spaces>name -- ) The same as USER but defines a float USER variable
INCUSER ( -- ) Increases the number of USER variables by CELL_SIZE. Usefull if we need an array in the user-table. It increases the offset in the user-table
INCFUSER ( -- ) The same as INCUSER but increases it by FLOAT_SIZE. Useful in case we need e.g. a 3dvector in the user-table
SLEEP ( ms -- )  Calls PAUSE
TASKS ( -- ) prints the list of the active tasks (id, parentid, name, counter, state). counter is in hex and milliseconds. The longest time of the task is stored in counter.
TASKCLRCNT ( taskid -- )   clears counter of task

There are real USER variables now (one instance of a variable for every task).
Ctrl-m stops (reinits the system, prints welcome message) the main-task.
Ctrl-c stops the currently running non-main-task. It is useful if a task is in a forever loop and calls PAUSE.
There is a counter in Pit-irq, which gets cleared in PAUSE. If this counter reaches 10-seconds, then the current task will be killed. This is useful if a task is in a forever-loop and doesn't call PAUSE, because no keyboard will be read. If the task is in a forever-loop but calls PAUSE, then it can be stopped by pressing Ctrl-c (or Ctrl-m for the Main-task).
The Main-task calls PAUSE in the loop it reads the keyboard (_accept function in forth.asm), so we don't need to call PAUSE from the command-line.
We only need to call PAUSE in the Main-task if we create a word that for example has a 1000000 DO-LOOP cycle and we want to switch tasks in this loop.

Currently only the MAIN-task can change the dictionary (':', LOAD and FORGET are EXEC_ONLY, and there is also DPW).
It would be possible to allow other tasks than the MAIN to change the dictionary, but because of Ctrl-C, we would need to save the current state (a task can add words, forget words, etc.) and restore in case of Ctrl-C.

Multitasking hasn't been thoroughly tested yet.
mt.txt is included in the zip-file. It creates two tasks, the first prints 'A'-s and the second one 'B'-s. By pressing ENTER the main task will print the prompt.
Reading/Writing from/to hard disk is done with polling (HDREAD, HDWRITE), and with DMA (HDREADDMA, HDWRITEDMA), and there is task switching with DMA.


USB-related words:

USBEHCI ( -- )         // makes the EHCI-driver active
USBXHCI ( -- )         // makes the XHCI-driver active
USBDRIVER ( -- n )  // n is 0, if the EHCI-driver is the active one, otherwise n is 1 (i.e. XHCI). Currently there is only EHCI-driver, so this value is not used.
USBENUM ( -- flag )
USBDEVINFO ( devaddr idx -- flag )
USBINITMSD ( devaddr -- lbaHI lbaLO sectorsize flag )
USBREAD ( lbaHI lbaLO memaddr sectorcnt -- flag )
USBWRITE ( lbaHI lbaLO memaddr sectorcnt -- flag )

USBFSINIT ( devaddr -- lbaHI lbaLO SectorSize flag )
USBFSLS ( flagIn -- flag )
USBFSCD (  "<spaces>name" -- flag )
USBFSPWD ( -- flag )
USBFSREAD ( memaddr "<spaces>name" -- lengthInBytes flag )
USBFSREADHD ( hdlba memaddr "<spaces>name" -- lengthInBytes flag )   // copies to winchester
USBFSWRITE (memaddr lenghtinbytes "<spaces>filename" -- flag )   // filename has to be <= 8.3 (gets converted to uppercase)
USBFSINFO ( -- flag) // prints info about the filesystem
USBFSINFOUPD (-- flag)  // updates the FSInfo structure (scans FAT and counts free clusters and writes it to disk)
USBFSREM ( -- flag) // writes FSInfo structure to disk (needs to be called if we wrote to the filesystem, before we unplug the disk)

USBDETECT only prints the USB-controllers (bus, dev, fun), so it's not important to call it.
First USBENUM needs to be called to get the device address of the pendrive.
USBDEVINFO needs to be called next (idx=0 don't print descriptors, idx=1 print device descriptor only, idx=2 print all the descriptors). This word saves the endpoint-numbers and max-packet-size of the device. Finally USBINITMSD need to be called which initializes the disk and retrieves the capacity of the usb-disk (MSD) and its sectorsize.
From now on, we can call USBREAD as many times as we want to read sectors from the disk to memaddr.
We use data-toggle in the QHs and transfer max. 0x5000 bytes per TD, so the memaddr need to be page-aligned (last 3 digits are zero). The code does it for us, if we don't do it (e.g. memaddr=0x200023 will be memaddr=0x201000).

Only high-speed devices will be found (EHCI), because the goal was to read sectors(files) from a pen-drive.
Currently external HUBs are not supported. USB-keyboards don't work, so only the built-in keyboard or a ps/2 keyboard will work.
The code was tested only on computers with EHCI-UHCI controllers (so no OHCI).
See docs/usb.txt for details.
Note that if you plug or unplug a device you need to do the whole sequence again (USBENUM ...).
In case of several USB-disks enumerated, we don't need to call USBENUM several times, just USBDEVINFO, USBINITMSD and then read or write.

Reading from a FAT32 filesystem on a USB-drive have also been added:
USBFSINIT fills the variables with the filesystem data (e.g. number of reserved sectors).
USBFSLS lists the current directory, if flagIn is TRUE, then a long list will be printed (name, date of last access, date of last modify, size in bytes).
USBFSCD changes to directory given by the name. USBFSCD  .."  goes to parent directory. USBFSCD /" goes to the root dir.
USBFSPWD prints the path to the current directory.
USBFSREAD reads the file given by name from the USB-drive to RAM at the given memory address.
USBFSREM needs to be called before we unplug the usb-disk, if we wrote to the filesystem. If we forgot to call it, then next time we plug in the usb-disk, we can call USBFSINFOUPD. USBFSINFOUPD scans the FAT and counts the free clusters. This may take some time depending on the size of your disk. However it is not that important to call this word, because it only updates the FreeClusterCnt field of the FSInfo structure.
The NextFreeCluster field won't get updated because it contains the number of the most recently allocated cluster, but we don't know that.
The search starts from NextFreeCluster if we write to the filesystem, so if it didn't get updated, then writing to the filesystem will take a little bit longer.

A name need to be ended with " and memaddr needs to be page-aligned (this way the filename can contain spaces, because the delimiter is a ").
Unicode characters will be substituted by 'X'. In comparisons the unicode chars will be skipped, so we can write any char there (e.g. HXz , the char in the middle was substituted and we can do USBFSCD HXz" or any kind of printable ASCII char (<127) instead of X will do, to enter the directory, if HXz is not a file).
Here is how to read a file from a FAT32 filesystem:
USBENUM  .      (the pendrive has devaddres 2)
2 USBFSINIT  .  .  .  .
USBFSCD Astronomy"  .
20000000 USBFSREAD astronomy.py"  .  .
20000000 100 DUMP

dp0 @ 4000 USBFSWRITE test.txt" .   ( name needs to be <=8.3, and will be converted to uppercase)
writes 16kb from the start of the dictionary to the given file.

Note that the datasheet of a Dell Inspiron 5559 (was bought in 2016) says that the laptop has one USB3 and two USB2 ports.
The lspci on Linux shows that there is only one USB-controller, an xHCI (i.e. USB3). This means that the EHCI-driver won't work.
The implementation of the xHCI-driver is already in progress.

Recommended reading:
Benjamin David Lunt - USB: The Universal Serial Bus
PrettyOS' and tatOS' code also helped

HD Audio

Audio related words:

AUINIT ( -- )                   // this also gets called right after boot
AUPLAY ( addr length format -- )
AUSTOP ( -- )
AUSETVOL ( muteandgain -- )
AUGETVOL ( -- muteandgain )
AUGETSUPPFMT ( -- format )  // see page 204 of HDAudio specs
AUPRINTFMT ( format -- )
AUPAUSE ( -- )
AUINFO ( -- )                  // for debugging
AUCODECSINFO ( -- )    // for debugging
AUWAV ( addrofwavheader -- flag )

The driver is capable of playing Wav(PCM) in a format the codec supports.
If we have the PCM-data from 0x20000000, the length is 0x1C131E8, and the format is 16bits, 44.1KHz, 2-channel, then:
2000002C 1C131E8 4011 AUPLAY
2C is decimal 44, so we skip Wav-header to get to the 'data'-chunk.
Note that, the 'data'-chunk doesn't always begin at 44. Other chunks e.g. 'LIST' can precede the 'data'-chunk.
The format can be read on page 58 and 147 of the HD Audio specification.

Of course, it is simpler to use AUWAV
20000000 AUWAV .

Adjusts volume:
F AUSETVOL                 // we are in HEX, so we set 15

Sets mute:
8F AUSETVOL               // also keeps volume setting

Tested on Dell D820.

Build (Linux)

Floppy (or CD)
If you want to boot from floppy (with Bochs or to create a CD-with floppy-emulation), then copy the files from GFOS/boot/floppy to GFOS/boot (the scripts to the GFOS folder). Some files will be overwritten.
Execute (in GFOS):

A file.img will be copied to your HOME directory. We will feed this to Bochs but first copy boot/floppy/bochsrc.txt to your HOME and rename it to ".bochsrc".
Just type (in your HOME):
in your HOME directory  (file.img is set in ".bochsrc").
Note that on a newer/faster laptop the pressed keys didn't appear on the screen of Bochs and there was "internal keyboard buffer full" message in the log.
Adding "keyboard_serial_delay: 300" to the config-file solved the problem (experiment with it). The original value was 200.
If it doesn't want to work, then try QEMU:
sudo apt-get install qemu
qemu-system-i386 -fda file.img -m 256

On linux a bootable CD can easily be created:
genisoimage -R -b file.img -o cdrom.iso cddir/

And write cdrom.iso to a CD.
The -b option means bootable CD and floppy-emulation will be done during boot.
file.img is our floppy-imagefile. The path to file.img is relative to the folder that will be burned to CD (cddir in this case). So now file.img is in cddir with all the other file we want to write to CD.

Hard Disk

If you want to boot with Bochs, then just boot with floppy/CD and execute HDINSTALL.
Copy boot/disk/bochs/bochsrc.txt to your HOME and rename it to ".bochsrc". This will change the boot sequence.
Copy boot/disk/bochs/boot.asm to the boot folder (this will read the first 7 sectors of the hard drive, where hdloader.bin is).
Copy the scripts from boot/disk/bochs to the GFOS-folder.
Note that on a newer/faster laptop the pressed keys didn't appear on the screen of Bochs and there was "internal keyboard buffer full" message in the log.
Adding "keyboard_serial_delay: 20" to the config-file solved the problem. The original value was 200.
If the keyboard still don't work, use QEMU (see above).
Create a hard-disk image in your HOME with bximage (Bochs). ".bochsrc" contains the values (cylinder, heads, spt) of a 10Mb image.

Execute (in GFOS-folder):
Just type ( in your HOME):
in your HOME directory  (hd.img is set in ".bochsrc").

Real computer:
Boot with floppy/CD/USB-drive on a real computer and execute HDINSTALL. This will copy the bootloader to the first sectors of the hard-disk, and the OS after it. Reboot computer and change boot-sequence if necessary.


First check if your BIOS supports booting from an USB. Only HDD-emulation has been implemented, so If there is an "Emulate HDD"-setting in BIOS, then that needs to be set.
Also, set "USB" or "USB HDD" or "Removable Media" to be the first in the BootSequence in BIOS.
The scripts for USB-boot are already in GFOS (otherwise they should be copied from boot/disk/usbdisk to GFOS; and the source files to GFOS/boot). buildAll2.sh builds everything and copies to our HOME.
We have a pendrive formatted to FAT32.
Get where the partition begins from the first(i.e. 0th) sector of the pendrive (from the partition-entry). In my case it is 00000800 (hex, i.e 2048 decimal). Next, we will write our boot.bin(Volume Boot Record, VBR) to the beginning of the partition. It's a good idea to save that sector before we overwrite it, and we also have to fill the BIOS Parameter Block (BPB) values from it (boot.asm, fat32.asm) before executing buildAll2.sh. This way we'll be able to use the pendrive normally with Linux or Windows.
Also set the bootable-flag of the partition-entry, if it is not already set (0x80 means bootable).
So write boot.bin to the first sector of the partition, and copy LODR.SYS and KRNL.SYS to the pendrive. The first sector(i.e. 0th) of the pendrive is called the "Master Boot Record" (MBR), and the first sector of the partition is called the "Volume Boot Record" (VBR). The MBR loads the VBR.

On Linux:
Plug in the pendrive.
First, we unmount the pendrive:
The mount command tells us where our pendrive was mounted. In my case it is /dev/sdb1.
Note that /dev/sdb1 means the first partition, and not the whole disk, so with dd we have to use /dev/sdb.
sudo umount /dev/sdb1
Next, we have to get to know where the partition begins. We can do it in several ways, for example by saving the first sector of the pendrive:
sudo dd if=/dev/sdb of=mbrOrig.bin bs=512 count=1
Then we can either get LBABegin from it with a hex-editor or we can use the script written in python3 (see below):
python3 ./printpbeg.py mbrOrig.bin
Here I got 0x00000800 (2048 decimal).
Next, save the original contents of the first sector of the partition:
sudo dd if=/dev/sdb skip=2048 of=vbrOrig.bin bs=512 count=1
In vbrOrig.bin the BIOS Parameter Block(BPB) is from the 3rd byte (zero also counted):
hexdump -C vbrOrig.bin
or use the script written in python3 (see below):
python3 ./printbpb.py vbrOrig.bin
The BPB in boot.asm and fat32.asm needs to be changed accordingly (your pendrive likely will have different parameters)
The pendrive is still shown in the window, remove it via right-mouse-click (or simply unplug it).
All the build-scripts (e.g. buildAll2.sh) need to be executable: "chmod +x ./buildAll2.sh" (do this with all the scripts).
Execute (in GFOS-folder):
Plug in the pendrive again.
Just copy LODR.SYS and KRNL.SYS to the pendrive.
First, we unmount the pendrive:
sudo umount /dev/sdb1
Next, write boot.bin (note that boot.asm already contains the BPB from orig.bin):
sudo dd if=boot.bin of=/dev/sdb seek=2048
The bootable-flag can be changed with e.g.:
sudo fdisk /dev/sdb
sudo gparted /dev/sdb
The pendrive is still shown in the window, then remove it via right-mouse-click.
Plug in the pendrive in a computer and turn the computer on.
Of course, there is a copy of the vbr (usually at the 6th sector of the partition), so that should also be updated.

There is an mbr.asm available. In case it still doesn't want to boot, just copy the values of the partition-entry from the original MBR (with bootable flag set!) to mbr.asm, build mbr.asm (there is a script) and then copy mbr.bin to sector 0 of the pendrive.

Known Bugs

- Audio with mono wav-files doesn't seem to be working (no sound).
- If a task is stopped by Ctrl-c, then prompt is not printed. We need to press ENTER to have it printed
- Floating-point: sometimes a '0' is printed before the significand. All the digits get printed regardless if they are zeros (at the end).


01.03.2017. The word RAMMAP ( -- ) added
01.03.2017. The word LOADM ( addr length -- ) added
01.03.2017. Section on MTRR added to the webpage.
02.03.2017. Minor improvements
04.03.2017. Better MBR
04.03.2017. USBFSWRITE with <= 8.3 filename
04.03.2017. PLAYWAV changed to AUWAV
22.03.2017. Release-date added to Welcome-Msg
22.03.2017. USBFSWRITE improved (existence of name is checked in current folder; better name-checking)
22.03.2017. HDREAD and HDWRITE fixed (they didn't work for sectorcnt > 65535; fixed)
22.03.2017. HDREADDMA and HDWRITEDMA fixed (e.g. timeout added; and several improvements)
30.03.2017. USBFAT32 put in order (however FSInfo structure still not used)
15.04.2017. FSInfo structure used (Section on USB changed; new words added)
14.05.2017. Cohen-Sutherland line clipping added to LINE
14.05.2017. The word POLY added (Sutherland-Hodgeman polygon clipping)
21.05.2017. Ctrl-m fixed
21.05.2017. Missing check(MaxLBA) added ( ata_rw in ata.asm)
21.05.2017. Current size of the kernel: 92KB
04.06.2017. docs/fthsrc added (see section on Graphics)
04.06.2017. Section on MTRR changed
11.06.2017. rotcube.txt added to docs/fthsrc (see section on Graphics)
11.06.2017. FORGET fixed (it didn't set user_offs; i.e. when a USER or FUSER variable was forgotten)
16.06.2017. FORGET fixed (it didn't kill the tasks that had greater dict-ptrs; also see act_dp in INTERPRET and ACTIVATE)
02.07.2017. Words OUTP and TXTVW added (see section on graphics)
02.07.2017. Symbols for arrow keys added to the font-file.
02.07.2017. Unnecessary "Press a key"-s removed
02.07.2017. "How to change system-colors" added to section on Graphics
10.07.2017. FCIRCLE and FPOLY added (see section on graphics)
10.07.2017. POLY fixed (it ruined the dict-ptr)
10.07.2017. Images of the webpage got updated (with QEMU)
12.07.2017. "dictionary-space underflow" fixed (multitasking and ctrl+c); see "saved_dp" in forth.asm for details

forthos1 at gmail.com

Click on the arrows on the right to download.

Hades Pluto,
Jun 26, 2016, 4:55 AM
Hades Pluto,
Jul 12, 2017, 12:33 AM
Hades Pluto,
Aug 3, 2013, 10:50 AM
Hades Pluto,
Jul 24, 2016, 4:23 AM
Hades Pluto,
Apr 25, 2015, 4:08 AM
Hades Pluto,
Apr 25, 2015, 7:10 AM
Hades Pluto,
Aug 3, 2013, 10:54 PM