Young folks, when you hear us talking about retro computers, you may think like this:
This middle-aged man is so done,
This old guy is living in the past glory,
It's too painful to hear,
I know, I know you were great! Please stop!
It's not that guys. We are enjoying watching you feeling awkward and cannot find how to react to our talk.
It's our party time, fellow retro programers!
I was given an opportunity to give a talk about FM (Fujitsu Micro) series computers in Demosplash 2017. While preparing the presentation, I got curious: Am I still able to code for 6809 assembly language? I found a free 6809 assembler called asm6809 and because I had an actual working FM-7, I tried to write some code. Then I just couldn't stop writing. I wrote line-interpolation by DDA, 3D coordinate transformation, and was able to render wireframe 3D graphics. Since I had something to show, I submitted to the compo competition in theDemosplash 2017, and ended up with winning the first place in the Retro Demo category. The result is posted here. Thank you my FM-7!!!!
You can download the demo code from the following link:
Demosplash 2017 First Place Winner in Retro Category "Never Ending Legend of Fujitsu Micro"
And, here is version 3. I have uploaded auto-starting disk image (D77) and tape image (T77) if you run it on an emulator (such as XM7). Or, for a real FM-7 you can feed .WAV through a data-recorder cable.
And, the source code is here:
You can assemble by typing:
asm6809 org2000.asm common.asm lineddademo.asm psgplay.asm stardemo.asm circledemo.asm squaredemo.asm wirecubedemo.asm flightdemo.asm lineddasubcpu.asm linedda.asm subcpu.asm div16.asm div32_16.asm mul16.asm transform.asm scrnclip.asm geometry.asm circle.asm util.asm moonlit.asm
Was assembly programming this easy? That's what I felt, but now I have a version-controlling system, an emulator that can actually pause the execution. I have a much more powerful text editor. I know much more programming theories and concepts. I was trying to write a flight simulator for this FM-7 when I was 14 years old, but I was too young, inexperienced, and ill-equipped.
I decided to make some of the sources open here. Many of the code below are tested on actual 6809 CPUs on FM-7. I say "CPUs" because FM-7 runs two 6809 CPUs simultaneously. But some were optimized after submitting the demo, and not fully tested on the actual CPU. Especially, the behavior of PSG looks to be slightly different between the emulator XM7 and actual FM-7.
Individual routines in the source codes do not have ORG statement since those are intended to be used with other assembly code. asm6809 sesms to fail if you don't have ORG statement or you say ORG $0. It apparently fails to calculate the offset, in which case it seems to give zero offset for every label. So, if you want to try it, make sure to start from a non-zero address like ORG $1000.
And, I guess it would be more elegant if these routines take parameters in the stack and returns values in the stack like C/C++ compiler does. But, in order to test from a plain simple F-BASIC programs, parameters need to be stored in a specific location and the return values need to be read from a specific location. This method is wasting bytes. I may fix it before writing something for the next year.
First thing I wrote this year was a division functions. I wrote signed 16bit/16bit, signed 32bit/32bit, and signed 32bit/16bit.
[16bit signed int / 16bit signed int]
[32bit signed int / 16bit signed int]
[32bit signed int / 32bit signed int]
When I tried 3D graphics in FM-7, I got stuck when I needed to divide X and Y by Z. This was the method that my programming master taught me then. It essentially does long division in binary numbers. 14-year old myself implemented it, but I couldn't fully debug then.
Although it is not used in this demo, I also implemented a square root. It takes an 32bit integer and calculates its square root. But, for performance reason, it is limited to 32767*32767.
[Square Root of 32bit unsigned int]
I was writing these assembly code and wanted to test from F-BASIC. But, I got stuck. F-BASIC 3.0 is such an old BASIC. No label, no local variables, no INCLUDE macro. I also had to hard-code the addresses. When I modify my assembly code, the addresses changed, and I had to modify my F-BASIC code as well. That doesn't work. I wrote a pre-processor for F-BASIC program. Quickly realized it can be used for other old BASIC variations.
The usage is simple.
fbasic.py <Input> <Output>
Input is a plain text file of a F-BASIC program. But the script gives line numbers, therefore no line numbers in the input. The output is a F-BASIC program that FM-7 can understand.
If you write a single line like:
You can jump to the label by writing:
You can also include another source file by:
If you want to force a line number to start from a specific number, you can say:
The next line will be line number 10000. When you combine with an assembly program. Let asm6809 spit out a SYM file, and say in the input BASIC program:
Then, in your BASIC program, you can write like:
fbasic.py will replace &&LABEL&& with the labels exported in the .SYM file.
I also thought about adding local variables, but this was enough for writing test code, so I stopped here
"The Emergency" published on I/O magazine February was a sensation. Main CPU and subCPU were running almost fully in parallel, and the author was boasting 130 lines per second. Well, he didn't tell how long a line he used to measure though. Nonetheless, it rendered real-time wireframe 3D graphics. Probably my line-drawing routine is not as fast as his, but I guess it is close. I expanded loop and modifies the program itself to accelerate drawing wider lines that are longer in X direction, but I didn't do too much optimization for taller lines longer in Y direction. FM-7's resolution is 640x200. It is short in Y direction, so it would be more effective to optimize drawing wider lines. But, if I do some more for taller lines, overall performance can get better a little more.
I don't have time to write documentation. If you are interested in using it, please read the source. Good luck!
[linedda.asm] [lineddasubcpu.asm] [subcpu.asm]
I used FM-7 emulator called XM7 for developing this program. Also to transfer the program to actual FM-7, I saved to a tape image, and then used T772WAV utility to convert T77 to .WAV file, which was then loaded to FM-7 via my 2008 MacBook Pro pretending to be a data recorder. I used FTOOLS developed by Apollo a lot. (He also gave me answers to my questions regarding his tools and FM-7 hardware. I thank him very much!) However, the conversion from .SREC file to .2B0 file that can be written to a disk image failed when I give a .SREC file created by asm6809. Apollo kindly looked into the problem and found that it was a bug of asm6809 that the check sum was not COMed. Check sum is supposed to be the complement of the lower 8bit of the sum. It was not a problem of his program, but is a problem of asm6809. So, I wrote a program that ignores check sum and converts .SREC to .2B0 myself. I wrote it in C++. It is much easier to write in C++. I do use Python everywhere, but I don't like it. If Standard Template Library can give me directory listing, I probably ditch Python.
Another problem was that a F-BASIC program converted to .0A0 file was not correctly written to a disk image unless the file size was 16+256*N. I wrote a program that adds 0s to force the file size to be 16+256*N.
If you are thinking to program for FM-7, you must be able to use C++. I don't think I need to post a compiled .EXE. But, does anyone need .EXEs?
After writing the version 1 of my demo, I was not happy with relying on F-BASIC for playing BGM. I remember there was a code for capturing PSG registers from F-BASIC PLAY command and playing back the captured data on I/O magazine. But, I couldn't find it. I knew how it was done. The capture code was hooking the IRQ handler and recorded any changes to the PSG registers. If I cannot find one, then I write. So I did write my own.
To use, in FM-7 or in an emulator, type:
This sets up the IRQ hook. Then you can load a program to play a PSG music, and then type:
This program will prompt you to type in a file name. Also it shows the addresses that the data take. To test-play your data, you can type:
and type in the file name. I wish I can write more documentation for this one, but I don't have time to do so. Please read the source code yourself.
[psgdisk.D77] [BEGINCAP.bas] [ENDCAP.bas] [psgcapture.asm] [PSGPLAY.bas] [psgplaym.asm] [uraram.asm]
The data format is very simple like [register][value][register][value].... If you see $FF as register number, it means the end of the data. $FE means just a separator. $FD is followed by a byte that specifies the wait count, the PSG registers must be kept unchanged for wait_count times 2ms. Probably easy to port to other AY-3-8910 based systems.
By the way, while writing this, I struggled to capture envelope-based tones. I hear four tones if I play like PLAY "S0M5000CCCC", but my program didn't detect changes of the registers. I had to disassemble into F-BASIC ROM to figure that the PLAY command was writing to register 8, 13, 11, and then 12, to play a tone with envelope. First I attempted to capture all writings to these registers by clearing them after each IRQ. By clearing the four registers, my program was able to detect change of the values when F-BASIC wrote something to those four registers.
Then my question was is this sequence of writing to four registers a trigger, or just some of them? I stopped clearing the volume, register 8, and my program worked fine. Then I stopped clearing registers 11 and 12, and my program worked. So, I only had to capture register 13 to trigger enveloped tones. Writing to register 13, envelope pattern, seemed to be a trigger.
To confirm the theory, I wrote a simple test program. When you run the following program in FM-7, you hear a tone. And then you subsequently hear a tone every time you press a key.
10 CLEAR ,&H1FFF
20 DEFINT A-Z
30 LOADM "ENVTESTM"
40 EXEC &H2000
60 EXEC &H2027
70 GOTO 50
ORG $2000 EXPORT SETUP EXPORT TONE SETUP PSHS A,B LDD #$07F8 BSR WRITE_TO_PSG LDD #$0025 BSR WRITE_TO_PSG LDD #$0131 BSR WRITE_TO_PSG LDD #$0810 BSR WRITE_TO_PSG LDD #$0B88 BSR WRITE_TO_PSG LDD #$0C13 BSR WRITE_TO_PSG LDD #$0D00 BSR WRITE_TO_PSG PULS A,B,PC TONE PSHS A,B LDD #$0D00 BSR WRITE_TO_PSG PULS A,B,PC WRITE_TO_PSG PSHS A,B STA $FD0E ; PSG Register LDA #3 ; PSG Register Selection STA $FD0D CLR $FD0D ; PSG Register Selection end STB $FD0E LDA #2 ; PSG Write STA $FD0D CLR $FD0D PULS A,B,PC
|Comments are welcome. Send E-Mail to:|