--------------- Creating a Soul --------------- This article deals with operating systems, and trying to write your own. This is very, very difficult. They are few good books on the subject, and building one takes several years. Qbasic is hardly the language to even try it in. The operating system is a lot more then a "c:\" or a arrow and windows; that is about 10% of it. Then you have the stuff that turns on the disk motors, moves the read/write heads of the hard drive, reads and writes to RAM, loads and runs the drivers, reads in the keyboard, communicates with BIOS, etc, etc. It takes FOREVER to do it. And, if you mess up in your code, you can PERMENENTLY damage/destroy/disable any/all of your computer. Wow, you're still here. Its scary, OS programming. First of all it is very rewarding (But then again those people that have 2 years of their life to blow don't really have anything else in their lives that is rewarding either, so OS programming wins by default). Also Qbasic wasn't designed for systems programming. I mean, you have to go back-assward and other weird stuff just to read/write areas of RAM and communicates with Ports. ASM in Qbasic is all but impossible. OS programming is almost always done in C or C++. The C Language was created for the sake of writing the operating system UNIX. So, OS programming is very hard, takes along time, and you don't have the tools to do it. You have two options. One: cry like baby, curse technology, and become the Unabomber, or the 2nd one: cheat. But this isn't just any cheating, this is MICROSOFT cheating. We'll make a pseudo-OS, like Windows. YES YES YES, no matter what anybody says Windows 3.1 and 95 are NOT operating systems. THEY AREN'T. I scream this because it pisses me of to read and hear people say they are. They are SHELL OS's. IF you own a Windows computer, what loads first? MS-DOS! And Windows 95 computer is just a MS-DOS ver 7.0 computer with "win" in its MSDOS.SYS file or whatever its autoexec.bat file is called. Windows 98 I believe is the same way. WINDOWS IS NOT an OPERATING SYSTEM! This wouldn't turn into my I HATE MICROSOFT rant, but if Microsoft calls Windows an OS, we can call our program an OS too, because ours will run after DOS loads up as well. This helps out a lot. DOS takes care of all the hardware low level stuff, and we make a new user interface like windows. There are two ways to create a pseudo OS. The Big program method, and the "Ant Method". (Please note I'm making these names up, so don't go down to your local bookstore and try to impress the red-head in your Physics class who works there by asking for a book on "Ant method programming." She likes Andy damn it! Not you. NO ONE LOVES YOU) Well folks, back in spring 97, I got an old IBM XT. I made it my goal to create one program that I could do everything with. It was really my first Qbasic program. It was called AcidOS 2.5. Why 2.5? Well, I had made 2 "OS's" for the TI-85 in TI-BASIC before. All these primitive OS's were of the Big massive program school. Just think of a personal organizer. Then throw in a simple word processor, a phone dialer, 2 games, and some other small programs and you had AcidOS 2.5. (it slices and dices and doubles as lip wax, and is only $19.95!) Sounds like Windows right. But Windows doesn't have all those programs in one huge .EXE. But AcidOS was a big .BAS file with everything in it. There was no way to customize, add to, or modify in anyway the program without "hard coding" it in. By "Hard coding" I mean opening the file and changing the code, and the saving it. All changes had to be written in. When you add a new program to Windows, you don't have to re-install a version of Windows that has the program in it do you. That would suck. And it did suck, because I was just beginning Qbasic programming, so I was re-writing AcidOS 2.5 everyday. It was more like AcidOS 2.578439. So, I developed what I now call the "Ant method." Making any Taoist proud, I looked to nature for my answers. If a big bad ass program couldn't cut it, what would? Simple, a lot of little machines working together. This is also called a Collective. I know you nerdy bastards watch Star Trek, so think the Borg. What you have is a lot of little things working together to do a bigger job than one could do. Bee and ant colonies work like this. This is a new school of thought in robotics as well. Ideally, you have small little beings, that you program to do a simple task. Several of these simple tasks do a be problem. Each of these little things can be programmed to do anything, though most are specialized. If you still don't understand, think about the cells in your body. Please understand that this isn't a lame idea of mine, but a real scientific theory that evolution seems to show works. Now with operating systems, you can have 3 different types of structure, and 2 different user interfaces. By, structure, I mean the way the operating system runs and manages all the other programs. The 3 types of structure are Linear, Multi-tasking, and Task swapping. Linear is the simplest type of OS structure. MS-DOS is an example of this. It contains a few INTERNAL commands to manage your files: COPY, DEL, RENAME, CD, DIR, and things like that. All other Disk functions, like defrag, format, scandisk, are EXTRANAL programs. when you run an external program, the processor runs only that program, until you quit or you hit the power switch. When the program is done, control goes back to the OS. You can't run several programs at once. I know so bustard is going to Email me, chewing me out about TSR's and other crap like that, well Screw You! If you don't know what I'm ranting about, don't worry about it. Just as with the ants and bees, you need a "queen program." This queen program isn't very big, but has an important job. It manages all the other little programs. If you have a spreadsheet and a game running, the queen must know what areas of memory are used by what programs, which program you can see, and what part of what program is running. This is where Multi-tasking comes in. Multi-tasking. Dude. Just sit back and marvel at it. It lets you play a game of Star Craft, then quickly flip to the word processor you were writing your report on if your mom comes in. Not just that, but everything is multi-tasking now. If you want to stay hot, you need to learn this. Ok, so, what is multi-tasking? How does it work? Why does Offspring decide to release a crappy song such as "Pretty fly" as the first single off their CD, when the rest of the CD is so much better? Well, I hope to answer the first two. Multi-tasking literally means to have many tasks running at once. The only way to do this would be to have multiple processors in your computer, one for each task. This isn't cool for home use. It cost to damn much. So, what you need to do is have one processor do a lot of things. But modern day processors can only like to do one thing at a time. Just like those jerkoffs at the DMV. They do one thing and do it until its done (and as slowly as possible.) When you multi-task, you sit down at a table with your processor and say "Listen you, I have 3 programs I'm running, you better do them all." The poor processor only has one hand, and thus can only do one thing at a time. However, he has a lot of time. Half a second is an eternity to a chip. So what they to is say, OK, I have to do three tasks Hmmm. Well, then, I will work on program1 for 20 nanoseconds, and then program2 for 20 , then program3 for 20 as well. Opps, I have no new tasks. Ok, then I will go back and work on program1 again for 20 nanoseconds. (Yes, you processor can talk, and it tells you to burn things, just like your Rice Krisby's do) Well, ok, how do this work? Well, this is the hardware side of multi-tasking. You see, the Intel 80386 had some cool modes. The chip could kind of divide itself up, into little computers (ant theory.) Each of these mini-computers used its own area of memory, and didn't know the other parts existed. Every time a new task was started, the processor created a little part for that program. All chips before the 80386 couldn't do this. The 80286 has some modes as well, but these modes (the mini-computers) couldn't be opened and closed without restarting the machine. This is why you can't multi-task on a 286. You use something called Task swapping, which I will discuss later. Anyway, the 386 had these separate little computers running each task. But since you have one processor. The "queen" program told the computer which task to run, and where in memory it was. Only one task is worked on at once. The processor moves to the next task when the queen program gets an interrupt. WHAT THE HELL IS HE TALKING ABOUT? HE WENT FROM QUEEN BEES AND ANTS TO TIMER INTERRUPTS! WHAT THE HELL IS A TIMER INTERRUPT? Your computer keeps track of time with a little piece of crystal. This thing wiggles like it is being tickled when electricity goes through it. The computer counts the vibrations of the crystal, and is able to figure out seconds, and minutes. Older crystals don't vibrate as fast as new ones. These crystals are what restricts the speed of the motherboard. The wiggling of this crystal generates an interrupt. If you don't understand, don't worry, here it is in simple terms: You have some rock in your computer. Its magic. When you shock it, it moves. After it moves so many times, it send a signal to the computer that says "Heah, so much time has gone by!" Now, what the queen program does, is when it gets this interrupt, it says "ok, the processor has been working on program1 for so long, I better get it to stop on program1 and go to program2 and work on that until I get another interrupt. The processor then stops working on program1, and goes and works on program2. Now remember, the little parts of the processor don't know the others exist. It seems to that part that it is the only program running, and when the processor goes and works on another part, the previous part just thinks the processor is taking a coffee break. This is very important. Since all the parts are independent of each other, you can close a bad part. In windows, you can use [ctrl]+[alt]+[Del] and close a program that is messing up. But it doesn't mess up the rest of your computer. The queen program just shuts down that part of the chip. That part of the chip can be used again at any time. GENERAL PROTECTION FAULT AT 43FB:001C. We've all seen something like this when using Windows, though they aren't as common in Windows 95/98. These are caused by lack of space in memory. Remember I said that each little mini-computer, or part of the processor doesn't know the others exist, and has its own area on memory. Well, GPF's are caused when two mini-computers use the same area of memory. Program2 writes some data to some part of memory. Later when the processor gets to Program5, Program5 writes here as well. Since each part doesn't know the others exist, they see "ghosts". You see, program2 KNOWS that it wrote to this area of memory. But when it is its turn, and program2 tries to read what it put there, it sees that something is wrong: the data is different. Since program2 thinks it is all alone, it doesn't understand why the data is different. At this point one of two things can happen. One, the program chokes, and locks-up. The other is it takes the different data is used anyway. This is bad, because the computer could think you have -3.1459 hard drives or something. The program will soon (like 1 nanosecond later) choke, and you get the choice between "IGNORE" and "CLOSE." Ignore almost never works, because if two programs are using the same memory to store crap, it is very likely other "ghosts" will appear, and cause more errors. Well guess what folks, Intel is a bastard, and hasn't responded to lots of Email (each one containing more foul language then the previous) about the proper ASM code to switch modes. I stumbled across a way to multi-task using C in old book from the mid 80's, but it was a way to multi-task SUB programs. Still, I am studying the text, and very carefully testing things in C. If I get it to work, I'll see if I can convert it to Qbasic, so I will get back to you about it. Ok, to create our OS, since we are following the Ant Method, we will make a "queen" program. What it will do is keep track of all the programs that are running. There is no way to switch processor modes in Qbasic (and set up the little mini-computer's or parts of the chip), so there is no way to multi-task. So, we will have to relay on an older method, used by Windows 2.0 (Yes there was a Windows 2.0, and a Dos 2.1 for that matter, and 20lb "laptops" that were so slow CS majors had nightmares about them. They bolt awake in the middle of the night screaming "FOR THE LOVE OF GOD, MAKE THE CGA MONITER STOP FLICKERING!" Its very sad) Windows 2.0 was for the XT's and 286's. It ran programs by something called "Task Swapping." What this is just a low-tech version of multi-tasking. Instead of making lots of little computers to run each task, and switching between them, Task Swapping takes an easy route. What it does, is save everything about a program, and then load another program for the processor to work on. The hard part is saving all the data, and then being able to go back and resume your work on it. First the program file itself must be found. Then Loaded. Then load up all the old data, variables, etc. Then restore the screen to the way it looked before you changed tasks. Then dig through the program until you find where it left off, and then run the program. Tasking swapping is an easy process to understand, but implementing it is a whole different manner. First of all is compatibility. You must have it. MS-DOS programs from 1982 still run in Windows 98. Unfortunately, I have no idea how to Task Swap DOS programs. So, into our OS, we must build in support to run DOS programs. You might think you do this with a simple SHELL statement. Yes you can, but if you are using Windows 98, then Run your OS, then shell out run programs, you are going to run out of memory REALLY DAMN FAST. I'll show you how to get around this later. You must also have support for normal .BAS files. You must create support for our *NEW* .BAS files. New .BAS files? Yes. Just like windows programs make use of Windows options, our new .BAS files must do the same. Alright. everyone, GO OUT. Right now, call up a friend, go hang out. You have already taken in a crap load of knowledge. I got headaches designing this next part. The idea is simple, it is just very long and hard to explain and do. THE OS KERNAL The OS kernel is the queen program I've been talking about. It must handle input from you, as well as load and manager running tasks. This is the bulk of your program. However you want to do this is your own deal, but there are something's that it MUST have. The reason I say MUST, is that if every OS written in Qbasic handles task swapping differently, No one will benefit. Code for one machine won't work on another. And remember, your OS must handle at least 3 different types of code: DOS, old Qbasic, and the New Qbasic that we will write. Allow me to be specific. When I say New Qbasic, I mean Qbasic programs that include some extra code that will allow it to be minimized and restored. Not to be on a Power trip, but I call Qbasic programs that have this "AcidOS compatible." I do this because as near as I can tell, I made the first tasking swapping OS in Qbasic, AcidOS 3.1 in the Spring of 1998. I ask that people who use my method of minimizing and restoring to put somewhere in the Program that it is "AcidOS Compatible." One thing to point out, Unlike Windows programs, AcidOS compatible programs run just fine in Qbasic. They are written in Qbasic. In fact, when I tell you the method I use, you beginners will say "Is that all" and you advanced guys will be slamming your head against the wall for not thinking of it. First off, lets ID some possible problems. We can't use Shell to run really any BIG programs (over 250,000.) because of memory restrictions. This all goes back to a little something called the 640K memory barrier, and is complicated. All you need to know is for the most part, when you enter DOS or run a DOS program in Windows, you have a max of 640k to deal with. Many people will yell at me about this, but since this isn't my article on memory, I'm not going to get into all this. For simple OS programming like this, all you need is 640k. So, we must find a way to quit your OS, run the .EXE/.COM/.BAT you selected, and then return to the OS, all without the user having to enter in any commands. Second, we must allow .BAS Files to run in Qbasic which is loaded into memory, so that changes can be made. The computer must then reload the OS and restore all the old settings once Qbasic is closed. This means we can't use the RUN statement, because it would not reload the OS when done. Third, we must set up a way for AcidOS compatible files to take advantage of their abilities when run in an AcidOS compatible operating system, yet if you use them in Qbasic, then they act like a normal .BAS file. This must be exact so everything is compatible. So If I run an AcidOS compatible program through AcidOS compatible operating, I can minimize it, and have several "running" at once, yet if I run it just through Qbasic, they act like normal Qbasic Programs. HANDLING THE FILES TYPES. For .EXE we get sneaky. Since we can't use the SHELL commands to run our .EXE files, we ACUALLY have to exit our OS, run the program, and get back to the OS without the user knowing. How? that is a questioned that bugged me all of Winter break in late 1997. Finally, I came across some old files from GW-BASIC that did something called keyboard-stuffing. What Key-stuffing is, is you make the computer think the user type in some keys. You know how the computer can be doing something, and you can type on the keyboard. Then when the computer is done, it can read all those keys you hit. Well, there is a special part of your memory that is called the Keyboard Buffer. When you type a key, it is put in the Buffer. The computer reads from the buffer not the keyboard. So, you can put stuff into this Buffer, and then the computer thinks that the user typed it in. So we, make a BATCH file that has 2 lines. The 1st is the .EXE file we want to run, the 2nd is another Keyboard stuffer program. If we have in our Batch file our OS.exe file, the Batch file stays loaded in memory. This is only a small amount of memory used, but you will get errors after you run a few .EXEs. To overcome this, we will have a program called Stuffbuf.exe which will stuff the buffer for us. That way, when the .BAT file ends, DOS will re-load our OS. Here is the concept map of all this in plain English -The User selects .EXE to run -The OS creates a .BAT file with the .EXE to run, and the StuffBuf.exe program -The OS then stuffs the Keyboard buffer with the name of our .BAT file, and exits. -DOS takes over, and sees that their are characters in the Keyboard buffer, and it reads in the characters, and then runs that .BAT file -The .BAT file runs, and it runs the .EXE program. -The user uses the .EXE program, and when he quits, the .BAT file runs the stuffbuf program. -The stuffbuf program will put the name of your OS.exe file into the Keyboard buffer. The line will look something like: StuffBuf AcidOS -The .BAT file ends, frees up memory, and then DOS says, well Hell, There is something in the keyboard buffer (THE NAME OF OUR OS), and runs the .EXE file of our OS. (I my case AcidOS.EXE) Here is the Code from AcidOS 4.1. The SUB RunEXEFile is called, where Filename$ is the path and name of the File you want to run. StuffBuffer is the Sub that puts the name of our Batch file into the Keyboard buffer. The name I used is "_.bat". Finally, StuffBuf is the .EXE file that also stuffs the keyboard buffer. SUB RunEXEfile (filename$) a% = FREEFILE OPEN "_.bat" FOR OUTPUT AS #a% PRINT #a%, "@echo off" PRINT #a%, filename$ PRINT #a%, path$ + "stuffbuf acid" CLOSE #a% StuffBuf "_.bat" SYSTEM END SUB SUB StuffBuffer (batch$) Stuf$ = LEFT$(batch$, 14) + CHR$(13) Length = LEN(Stuf$) DEF SEG = 0 POKE 1050, 30 POKE 1052, 30 + Length * 2 FOR a% = 1 TO Length POKE 1052 + a% * 2, ASC(MID$(Stuf$, a%)) NEXT SYSTEM END SUB Here is an example of it working: I want to run QBASIC.EXE -The OS writes a Batch file named _.BAT It looks like this: @ECHO OFF C:\DOS\QBASIC.EXE C:\ACIDOS\STUFFBUF ACID -My OS stuffs the Buffer with "_.BAT" and exits -DOS takes over and sees that ".BAT" is in the keyboard buffer -DOS runs _.BAT -_.BAT runs C:\DOS\QBASIC.EXE -The user fiddles with it, does what ever, and Quits -The next line in "_.BAT", which is "STUFFBUF ACID", is run -The Keyboard buffer now has "ACID"+ an enter key in it. -_.BAT has no more lines, and returns control to DOS, freeing the memory it was using -DOS sees that "ACID"+ an enter key is in the Keyboard Buffer, and runs ACID -ACID runs, Checks for flags (I'll talk about it later) sees that it isn't being started for the first time, and that it is being run after having run a .EXE file, and loads its old settings. All the user has seen of this is AcidOS, then Qbasic, then AcidOS again just the way it was before. DAMN THATS COOL! We ran a .EXE file, saved a lot of memory, and the User didn't even know! Ok, That was a little tricky, but I hoped you followed. Are you being to see how this isn't just ideas and concepts, but things you can really do, tangible things! Its a rush. What you just wrote is basically Windows 3.x in Standard mode. OK now we know how to run .EXE files. To run .BAS files is easy. We can't just use the RUN statement, because then we can't get the computer to automatically go back to our OS. But, what if the program is an AcidOS compatible .BAS, and has the ability to be minimized, and moved, and other cool stuff. I don't really want to get into AcidOS compatible Programs right now, but they will ALL have certain code in them that will Identify them. What your OS will do is scan through the .BAS file, and look for these special lines of code that ALL AcidOS compatible programs have. If the OS detects these, then it will run it a special way I will talk about in the next section. If the .BAS lacks these, then it is a plain old .BAS file, and has to be run a separate way, so that the OS runs when the .BAS is done. To do this, we basically use the same method as running a .EXE file. we run QBASIC.EXE as the file, and use /RUN [filename] to load an run the .BAS. I have a SUB in AcidOS 4.1 called RunBASFile. It looks like this SUB RunBASfile (filename$) a% = FREEFILE OPEN "_.bat" FOR OUTPUT AS #a% PRINT #a%, "@echo off" PRINT #a%, "c:\dos\qbasic /run "+filename$ PRINT #a%, path$ + "stuffbuf acid" CLOSE #a% StuffBuf "_.bat" SYSTEM END SUB Well, hell, That was easy. It works just like to other method. Next, we have to have a way to run our AcidOS compatible .BAS files. This is kind of hard. What we are going to do is make .BAS files that run just like normal .BAS files, but if they are run through AcidOS compatible Operating systems, they can be used in Task swapping. You can minimize these files, and return to them later. Just like Windows. Just for the record, these enhanced programs that take advantage of AcidOS compatible commands will be called AcidOS programs for the rest of the article. Originally, they would be .BAS files, but about halfway through writing this article, I found a way to used compiled .BAS files, and for that matter, AcidOS files can be written in ANY computer language, as long as it is compiled into an .EXE file. First things first. How do I get an AcidOS program to see that it is being run in AcidOS. Remember, we what it so that AcidOS programs can run both in and out of AcidOS, just like DOS programs can be run in or out of Windows. Originally, I was going to use the COMMON key word, and use this to pass on important information from the queen program to the other programs, by running them with CHAIN. However, If I did this, The OS itself and all AcidOS programs would to be written in Qbasic only, and could never be compiled, because COMMON can't share variables across .EXEs. Instead, I used RAM to set "flags". Ok, history lesson time folks. If you read "Boolean Hell" in last issue, then you know all about truth tables. You also learned all about Binary. Well, every thing on a computer is measured by 8ths. A Kilobyte isn't 1000 bytes (Kilo means 1000 people) it is 1024 bytes. Because 1024 is the closest number to 1000 that is divisible by 8. Knowing this, look at your screen. I don't want to get to detailed, because I have an article for next issue written all about screen memory, but here goes. In RAM, there is an area that holds what's on the screen. When you are dealing with the standard text screen, you have 25 lines, and 80 rows. this makes 2000 little places for a characters on your screen. You then have ANOTHER 2000 little places need to hold the color for each place. So 2000+2000=4000 places need in RAM to store screen data. BUT WAIT! everything on computers MUST be divisible by 8. So, in RAM, there is REALLY 4096 bytes of RAM for screen data. But the computer only uses 4000 of this. You have a 96 byte scratch pad! You can shove stuff in there, and run a ton of other programs, and then go back and look, and what ever you put in will still be there. (This isn't ALWAYS true, starting Windows and other stuff will purge the data, but for our purposes of OS making, we don't need to worry about this) So, what we do, is have our OS put some a little "flag" into memory, and run a program. If that program is AcidOS compatible, it checks in RAM for this flag, and if it finds it, the program knows it was run through AcidOS. Normally, all the settings information would be put into RAM, and another program started, and then when it ends, the settings are read from memory. the only problem with this is that I don't know how to "lock" areas of memory so that other programs can't use them. And since we only have 96K of memory to work with, we will just put in strings of characters, to communicate between programs. Ok, there are 2 video buffers on your computer, 1 for color, 1 for monochrome monitors. Everyone basically uses color monitors now, BUT, even Windows 95 runs on monochrome monitors, so for compatibility, we must support this. What our OS will do is determine which Video buffer the computer is using, and use the last 96K of it. To do this you use the following code: DEF SEG = 0 IF PEEK(&H463) = &HB4 THEN DEF SEG = &HB000 'Its MONO! ELSE DEF SEG = &HB800 'Its COLOR! END IF Please note, this isn't what the monitor is, but what the video card is. I am writing this on a 386 with a Super VGA card, but with a monochrome VGA monitor. What the above code does is look and see what buffer the computer is using. I will discuss more about Video buffers in the next issue. OK, so, we are now at the starting address of the Video Buffer. The Buffer is 4096k long, though the last 96k aren't used. To access them, use PEEK, and POKE. We use 4001 because 4000 is the end of the Video buffer that the computer uses. POKE(4001),65 '65 is the ASCII code for "A" PRINT CHR$(PEEK(4001)) 'This prints "A" on the screen Well, we would use POKE(4001) by the main program to put a little flag into memory, and then our AcidOS programs can simply use PEEK do detect this flag. If they don't see it, they assume that they are being run outside of AcidOS, and function like normal files. This files can be .EXE .BAS .PAS .C .CPP, or any language. Now, there is a chance that the value at 4001 is the same as our flag, but was put their on accident. I know this chance is small, but imagine running a normal .EXE, that you didn't know was AcidOS compatible, and when you quit, your computer freezes, because it tries to load up an operating system that doesn't exist! To minimize this, the OS will set 4 flags in a row. The string "OS*1" will be put into memory into 4001-4004 of the Video Buffer. The possibility of these values being put into those memory address in that order by any other program are basically NIL. But, Heah, If you throw a pen at the top of the table enough times, it will go through without leaving a hole (its true, ask your physics teacher) Another plus for this is that the OS is now upgradable. If I am working on an OS that allows split screen action, and have several different windows open at once. Operating systems that can use this will use the string "OS*2." This way old programs can run on Newer OS's. Also, a program that is capable of using these functions can tell from the Init string if the OS can support it, and adjust itself. Here is the code I used in AcidOS 4.0: SUB SetOSFlags DEF SEG = 0 IF PEEK(&H463) = &HB4 THEN DEF SEG = &HB000 ELSE DEF SEG = &HB800 END IF OSint$ = "OS*1" FOR a% = 4001 TO 4004 POKE (a%), ASC(MID$(osint$, a% - 4000, 1)) NEXT END SUB AcidOS programs should use the following code to detect if AcidOS is Running: FUNCTION DetectOS% OSint$ = " " FOR a% = 4001 TO 4004 MID$(OSint$, a% - 4000) = CHR$(PEEK(a%)) NEXT IF LEFT$(OSint$, 3) = "OS*" THEN DetectOS% = 1 END FUNCTION ELSE DetectOS% = 0 END IF END FUNCTION Well, there is alot of Data to make available to the AcidOS program. In fact, alot more than we could cram into 92 (96-4 for the init string) bytes. So, what we do is save this information in an ASCII file, and let the AcidOS program take what it needs. For example, I built in a Print Manager into AcidOS 4.0. Now, I might be running a game, or something that doesn't want to add files to or even use the printing buffer. The information will be put in the ASCII file, but the program is only programmed to take what it needs. Well, this was a brain-racking experience. I need to think of every possible thing a program could want. Since I might create something in the future, like that multi-windows thing, I needed to include things that might not be needed now. Here is the list of things I put in the OS.INI file: Path of AcidOS Path of program running Screen mode of OS Where in the program (if at all) it was minimized My OS.INI file for AcidOS 4.0 when I run "Voices of Liberty"(TM) looks like this: C:\AcidOS\ C:\Games\VOL\ 0 0 When I run it again, after I have minimized it, it looks like: C:\AcidOS\ C:\Games\VOL\ 0 72 Every time you run or switch to a program, a new OS.INI is written. In addition to these, I created 4 Signal bytes in RAM. These signal bytes tell the conditions under which a program is being called. There are 2 signal bytes for AcidOS programs, and then 2 signal bytes for AcidOS that tell AcidOS the return state of the programs being called. Here are the conditions: Signals from AcidOS to a program: AA=Normal start up. The program hasn't been running in minimized format. The program runs normally from the beginning. BB=Minimized start up, The program was running, and it is resumed. All previous settings are loaded, and the screen is loaded, and the program resumes roughly where it left off CC=Shut Down This signal tells the program that the either the whole OS or this program alone has been shut down by the user. The AcidOS program, should clear out all its files that hold saved information, and prompt the user to save if that program offers saving. (Ex: you shut down a word processor like Acidus Software's Typist, Typist receives this signal, and asks the user if they want to save the document they were working on. Signals From a program to AcidOS: AA=Normal Ending The program has been exited by the user, and all work on it is terminated (ex: you select Exit, or something like that, and the program ends) BB=First time minimized The program has been minimized, but this is the first time it has been. This is important, because the OS then has to make a minimized icon, or in someway create a NEW link to the program. CC=Minimized program The program was minimized again, it was already running on the computer. This can't be confused with 11, because the OS needs to UPDATE the link to the program, not create a new one. DD=Error in the program The program erred. The program will make a file named "ERROR.DAT" in the programs path explaining what caused the error. Here are the following subs to create signal flags: SUB OSSignalFlags (code$) 'Set flags for Program to read DEF SEG = 0 IF PEEK(&H463) = &HB4 THEN DEF SEG = &HB000 ELSE DEF SEG = &HB800 END IF POKE (4009), ASC(LEFT$(code$, 1)) POKE (4010), ASC(RIGHT$(code$, 1)) END IF SUB ProgramSignalFlags (code$) DEF SEG = 0 IF PEEK(&H463) = &HB4 THEN DEF SEG = &HB000 ELSE DEF SEG = &HB800 END IF POKE (4011), ASC(LEFT$(code$, 1)) POKE (4012), ASC(RIGHT$(code$, 1)) END IF Please note that only AcidOS compatible programs will recognize these codes. If I run Qbasic through AcidOS, I can't minimize it. BUT, if I run "Voices of Liberty" (TM) from Acidus Software, it can be minimized. Also, I will be telling you how to use the signals sent back and forth between AcidOS and AcidOS programs, so you can write AcidOS programs. AcidOS programs can be in .BAS format or a compiled .EXE. You can write AcidOS programs in any language other than Qbasic, as long as you compile it into an EXE. Lets look at that OS.INI file. First off I put the path of the OS as the First line. In my OS, I had it add a line to your autoexec.bat, declaring "OS = C:\AcidOS" which is the directory that my OS is in on my 386. You can easily get this by using the ENVIRON$("OS") command, but I included it anyway, because not everyone's OS will be like mine. Also, I included the path of the program being run. I did this because it makes things a lot easier. If I run "Voices of Liberty"(TM) though AcidOS, it will know what directory to load its files from: here is an example: BLOAD ProgramPath$ + "Nuke.gfx" ,0 This way, you wouldn't get any funky errors. I also included the screen mode of the OS, so if in the future, I can possibly have several windows on the screen at once. AcidOS 4.0 is all TEXT based, and has no graphics. So It uses Screen mode 0. Your can be in any mode you want. I decided to put nothing else in the OS.INI file for the OS*1 standard. OS*2 might have more, I'm not sure. I'm not even sure If I will make an OS*2 standard. Minimizing and closing appear magical, but are really quite simple. Basically you write your program so that when a certain key is pressed (I used F1), The program stops, saves all its variables, and its location into a file, put up a little flag for AcidOS, and fills the 2 Signal bytes with its return conditions. To make a program stop, use the "KEY" and "ON KEY" statements. Again here is code directly from an AcidOS program called "Cents"(TM) a% = DetectOS% 'Our Function that looks and sees if it was run in AcidOS ON KEY(1) GOSUB MinimizeProgram 'Map the keys ON KEY(2) GOSUB CloseProgram 'Map the keys IF a% THEN 'If OS was detected, enable Minimize/Close keys KEY(1) ON 'F1 KEY(2) ON 'F2 ELSE 'If Not, disable KEY(1) OFF KEY(2) OFF END IF The DetectOS% is the Function that looks into RAM for the "OS*" string. If it returns a true, then KEY 1 and 2 are turned on. These are F1 and F2. I use F1 to minimize, and F2 to close. This little bit of code also shows how if DetectOS% doesn't find an OS, then Minimize and Close cannot be used at all, thus avoiding errors if you ran "Cents"(TM) alone. Note: I just used F1 and F2, you can use any keys you want, just be sure to tell the user which keys do what. Also, you can have these items selectable on pull down menus if you want. Ok, So, you have your program, and you press F1 to minimize it, and the program jumps to MinimizeProgram:. Next, you must save the contents of the screen. Saving and loading screen images can be tricky, because each different video mode has a different way of storing data. I will tell you how to save screen images in screen mode 0 right now, because, that is how I did it with AcidOS. If you have graphics, you will merely have to write a sub program that redraws the screen. I will have a future article which talks about this. Remember those Video buffer things? Well, what you are going to do is go to the start of the Video buffer in memory, and simply copy the next 4000 bytes into a file. It is that easy. I don't really want to get into how BLOAD and BSAVE work, so here it is plain and simple. You set an address with DEF SEG, and with BSAVE, tell the filename you want to copy x number of bytes to. In this case, we would use something like: SUB SaveScreenImage (ProgramPath$) DEF SEG = 0 IF PEEK(&H463) = &HB4 THEN DEF SEG = &HB000 ELSE DEF SEG = &HB800 END IF BSAVE ProgramPath$ + "Screen.gfx", 0, 4000 END SUB That just figures out which video Buffer is being used, and goes to the starting address of it. BSAVE then saves 4000 bytes (80 rows * 25 lines * (1 character + 1 color value) = 4000 bytes), into a file named "Screen.gfx" in the directory the program was run in. We got ProgramPath$ by opening the "OS.INI" file. Also, you must save all the variables in you Program as a file. How you want to do this is your own thing. I used "OPEN ProgramPath$ + "Set.ini" FOR INPUT AS #" so I could save strings, easily, though you can really use any way you want. Now, we need to make a little flag for AcidOS to check for when it re-load, so AcidOS knows it isn't being run the first time, but really coming back from a program. We do this just like we did with "OS*1", we will use instead "PG*1" PG stands for ProGram and it can use up to OS*1 features. Again, this sharing of information about what the OS and what the programs are capable of doing allow for Upgrades later. Instead of using Memory address 4001-4004 away from the start of the video buffer, we will use 4005-4008. Here is the code, for a program to put the Flag into memory: SUB SetPGFlags DEF SEG = 0 IF PEEK(&H463) = &HB4 THEN DEF SEG = &HB000 ELSE DEF SEG = &HB800 END IF PGint$ = "PG*1" FOR a% = 4005 TO 4008 POKE (a%), ASC(MID$(PGint$, a% - 4004, 1)) NEXT END SUB The last thing that going in your "set.ini" is the location in the program where you were. Remember all those losers that told you NEVER to use GOTOs, well, SCREW THEM! What you do is have throughout your program have PlaceInside% = 1, or 2 or what ever. You should place these right after labels, and at the beginning of loops. When they minimize, this gets saved. When they return, you will have a little hunk of code that is basically a series of "IF THEN GOTO"'s that will take you roughly back to where you were. BECAREFUL: You can run into problems During FOR LOOPS, and GOSUBS. You could return to the program in the middle of a GOSUB, hit a return, and the program chokes. Another thing to watch out for are open files. You might want to keep track of them, so you don't get all those nasty FILE I/O errors Also if, you are in a FOR LOOP, and you return, it doesn't work anymore, even if you save the counter variable in the FOR LOOP. To bypass this you can convert all your FOR NEXTs until DO WHILEs like so: FOR a% = 1 to 100 Dump%(a%) = a% NEXT a% = 1 DO Dump%(a%) = a% a% = a% + 1 LOOP WHILE a% <= 100 I'm sure there are alot of ways to track were in the program you were, but this is the easiest way I found. Again, this is something that you can do, your own way, and don't have to follow my method, though I like it. Finally, use the SYSTEM command to kick out of the program. AcidOS loads up, sees the flags, and reloads its settings, with the program minimized: When you run a minimized program, here's what happens: AcidOS creates a new "OS.INI", and saves its settings. It then uses the RunEXEFile SUB, and kicks out to DOS. DOS runs _.bat, and the EXE file you selected. The file checks for the "OS*" flag in memory, and if it fins it, open "OS.INI" The program looks at the 2 Signal bytes, and sees what the OS told it to do. It sees that it has already been minimized, and it first loads up the screen image. To do this, it uses the following Code: SUB LoadScreenImage (ProgramPath$) DEF SEG = 0 IF PEEK(&H463) = &HB4 THEN DEF SEG = &HB000 ELSE DEF SEG = &HB800 END IF BLOAD ProgramPath$ + "Screen.gfx", 0 END SUB Next, it loads up the old data. This is how I do it, though how you decide to save your data is cool. DIM MapData%(10) OPEN ProgramPath$ + "SET.INI" FOR INPUT AS #1 INPUT #1, PlaceInside% 'THIS IS THE LOCATION OF WHERE IT LEFT OFF FOR x%=1 to 10 INPUT #1, MApData%(x%) NEXT Line INPUT #1, Name$ input #1, ... input #1, ... input #1, ... CLOSE Then you need to resume the program. I used ON GOTO. I have never had to use this statement before, and it is really quite dumb. But it works here. ON PlaceInside% GOTO Main, Test, EnemyMove, PlayerMove, cool What this command does is take the value of PlaceInside%. IF it =1 then it goes to label Main. IF it =2 then it goes to label Test. 3 takes you to EnemyMove..etc..etc. See, this is very helpful here, but it is normally worthless. The program goes to the label and resumes. ISN'T THAT DAMN COOL? THAT TOOK ME THE BETTER PART OF A YEAR TO THINK OUT AND PREFECT! WELL, DAMNIT, IT WAS HARD, SO YOU BETTER LIKE IT WHETHER YOU LIKE IT OR NOT! OK Folks, here is the cool part, YOUR ALMOST DONE. And The last part is totally up to you. I have told you how to get your OS to run an outside .EXE, .COM, and .BAT files; how to run a .BAS file, and how to run a .BAS file with special options like minimizing. I also told you what the programs tell the OS when they restart it. Notice I never really told you how your OS should LOOK. That is your choice. If you want to write a GUI like WINDOWS, go for it. Your OS can be text based, Graphics based, Have a mouse, have a joystick, have icons, have a menu bar, have modem support, anything! I will have an article in either the next issue or the one after that on cosmetic things like that. I will also send you a copy of my OS in the next issue, so you can see how I did it. This stuff is very hard, and I'm sure their are parts in this article that weren't clear to everyone, and I'm sorry for that. I have had 3 people read this, and have modified it accordingly. IF you have any questions, please E-mail me, and I will publish them in the next issue with an answer, so everyone can understand it. -------------------------------------------------------------------------------- This tutorial originally appeared in the QBasic Developers Forum, Issue #3. This was written by Lord Acidus.