A Befunge-93 interpreter which runs on x86 real mode
To make the experience fit your profile, pick a username and tell us what interests you.
We found and based on your interests.
example-code.webmExample code being entered and executedOpen Web Media Project - Video - 5.52 MB - 10/08/2024 at 02:28 |
|
During this week when the RetroChallenge has started, I added more functionality to the Befunge-93 interpreter. The editor page now accepts input to enter simple code and to execute it press F5 key, I implemented the basic commands to print the string enclosed in double quotes, and the commands to change the program counter flow.
As I said, I'm developing the interpreter using 8086 assembly, I'm not using C language or another high-level language. The reasons are:
The 8086 assembly isn't that hard, considering that's a CISC processor, which means the processor has single instructions that can execute various operations.
Even that the Befunge-93 is limited to 80x25 cells and has only one stack, it's powerful enough to write interesting programs, like Hunt the Wumpus or Game of Life. Remember the mantra Fetch-Decode-Execute for parsing the individual commands.
The fun I'm having on building the interpreter is the concept of 8086 assembly and real mode on one side and an esolang on the other side. I'm learning more about the memory segmentation, the various BIOS interrupts of video and keyboard and the commands of Befunge-93.
Here is a video where I enter the example code and press F5 key to execute it:
Now it's October 1st and the RetroChallenge has started (at least for my timezone). I spent the month of September doing research about the real mode, BIOS interrupts, 8086 assembly and how to build the Befunge-93 interpreter. Now with the research done I have a basic skeleton code which I can improve and add missing features.
Initially, the interpreter will be monochrome, I'll decide later if I'll add color to the program, because I'm more concerned about building and testing the interpreter to verify if it behaves accordingly to the spec rather than adding bells and whistles.
I updated the main image of the project page with the Fungesector title screen, the logo was made using the figlet command. And the background photo looks like gibberish, but it's Hunt the Wumpus, the most complex code written in Befunge-93 that I know (it occupies almost all playfield). The interpreter will be accomplished when I manage to play it.
I forgot one thing to tell about the tools used to develop the interpreter. How can I debug the code if the code had an error? I'll use Insight, which is a DOS program that can debug real-mode DOS programs. I can convert the second stage to a COM executable format and analyse it.
Now that the "Hello sector" result was shown, it's time to design the Befunge-93 interpreter to run in real mode. The interpreter needs an editor where you can type the code and press the arrow keys to move the cursor, a location where you can load pre-stored codes and save the code you've written, an output display, an options screen to change the defaults and behaviors of interpreter and some help docs to explain how to use the interpreter.
How can I put all of these things on the program? I was looking in the docs of BIOS interrupts and there was an interrupt called INT 10,5 - Select Active Display Page. This is a interrupt where you can switch to a new display page of video adapter. Using mode 0x03 on VGA adapter there are 8 display pages available to use.
I imagined a kind of state machine to switch from a display page to another (for example, press any key to go to edit screen, press F1 to go to help page, press F5 to go to output display and run the code). Here is the draft of state machine that I imagined (made with JFLAP):
For interpreting the Befunge code, I'll use the technique usually used to implement videogame emulators (like the NES or Game Boy). This technique is called Fetch-Decode-Execute cycle:
The output display will operate like a teletype and you can use the keyboard when prompted for input. When the program ends, it should appear a message indicating that the program has finished and the user should press any key to go back to the editor.
For the case of infinite loop or to stop a running program before the end, the Ctrl-Break key should be pressed (there is a int 0x1b which handles this key). And when the program has a runtime error (like a unknown command), the program should be halted with a error message.
In this project log I'll show the initial result of developing for the real mode. The binary I have generated loads the sectors from the pendrive and prints "Hello Sector" with borders on the center of the screen from the second stage. I created a folder and organized the files with source codes for the first stage, the second stage, the subroutines and the helpers with the constants and macros.
Basically when the computer is booted, the BIOS loads 512 bytes on the physical address 0x07c00 (using the calculation of segment << 4 + offset), this 512 bytes is typically called the first stage. If you want more bytes, you have to load additional sectors using the Diskette BIOS Services (in this case, int 0x13), and after loading the sectors jump to the second stage.
I have created code which includes the files of first stage and second stage, sets the magic bytes to make the binary bootable, and has a option to generate a floppy image or binary file.
Now I'll show the result on the 86Box, with the configuration of machine type [1988 i386SX] and machine [ALi M1217] Chaintech 325AX (MR BIOS):
And running the binary on real hardware in the pendrive (I had to take a photo using a camera):
PS: This project log was supposed to be posted on the Sunday, but I had problems which prevented to post it on the Sunday. I realized the biggest challenge of the project isn't the project itself, but to keep thinking about the next project log and write the details. And also I had problems on uploading the images, I solved this by getting the direct image URL location using the Developer Tools of Mozilla Firefox.
For this project log, I'll briefly describe how to write a basic bootloader with 8086 assembly using the tools and documentations available on the internet. I'm using Linux, so the steps and tools used are from the Linux perspective.
So, what you need to develop something for x86 real mode? You'll need a set of tools:
In addition to these tools, you'll need some good documentation with the descriptions of BIOS interrupts. I recommend the HelpPC Reference Library which describes various BIOS interrupts related to disk, video and keyboard services. Also you'll need a x86 instruction reference, which contains a list of opcodes (there are opcodes which aren't available for the original 8086). When developing for the x86 real mode you can't use DOS interrupts (because DOS isn't running on the pendrive).
The biggest challenge when developing for the x86 real mode: there are various flavors of BIOS, each one with unique features and quirks, so it's important to test on various emulators and real hardwares as much as possible.
The code I'm developing will be divided in two parts: the first stage, which is responsible for loading the sectors of pendrive and showing a message if had a error; and the second stage, which will contain the Befunge-93 interpreter.
With the tools and documentations, I've written some code which loads the sectors on the first stage and prints some text on the second stage. The code is a bit disorganized and not well-commented, so for now I'll show the code and the result on a future project log.
Now the RetroChallenge has just begun... Oh wait, it begins on October 1st, not September 1st... Anyway, I guess there is more time to do my research about the real mode and Befunge.
I'll give some brief explanation of real mode. When you boot your computer (assuming x86 architecture and with BIOS), the default operating mode is real mode, which has 1 MB addressable memory. The reason for booting on real mode is because of backward compatibility. There are other modes (unreal mode, protected mode, long mode), but for this challenge I chose real mode because it's simpler compared to other modes, and because it has a 'real' name.
Now for the Befunge explanation. Befunge is a esoteric language which is two-dimensional, meaning that the program counter can go up, down, left or right. The language has a stack (similar to Forth), which can be manipulated using stack operations, and features a playfield, where the commands are located and executed (and can be self-modifying). The two main dialects are Befunge-93 and Funge-98, the Befunge-93 has a limit of 80x25 cells and has fewer commands compared to Funge-98, but it's easier to implement.
What happens when the real mode and Befunge-93 are blended? I'll discover this and post new project logs about the tools used to make this project, the satisfactions and frustrations I had on this project, more explanations about real mode and Befunge, and running this project on real hardware.
Create an account to leave a comment. Already have an account? Log In.
I'm not a fan of Malbolge, it's too esoteric even for esolang standards. I chose real mode to flex my 8086 muscles, and the 80x25 resolution is perfect for Befunge-93.
Become a member to follow this project and never miss any updates
Why not Malbolge? :D