I actually did, i'm testing it on emulator(s), FCEUX, Mesen, Nestopia and EmuHawk seem to accept my ROM.
THIS IS NOT A JOKE. PLEASE STAY SERIOUS.
This is what we want:
The ROM fits only in 16 KB.
It should have 32 KB of PRG RAM. (Mappable from $4020 through $BFFF)
It must use CHR RAM.
This is how memory will be mapped:
Kernel registers from $4020 through $402F.
31.9625 KB ROM from $4030 through $BFFF.
16 KB ROM from $C000 through $FFFF.
8KB CHR RAM from $0000 through $1FFF (PPU)
2KB VRAM (will we use it anyway?) for 4 screens (Nametable)
I'm being inspired by the A2 for this. It uses a 6502 CPU too, so doing something similar on the NES should be easy to do.
Also, i think i can use the expansion port for the console to add custom hardware (like disk reader, etc...)
I thought the device for the expansion port should use a M68K or a W65C816 for processing reasons, or nothing at all. But we still need something that can make hardware like disk readers to work.
40 KB of RAM is a lot, but adding up to 64 KB would be even better. It's unfortunate that the NES doesn't decode the PPU registers properly, so it's mirrored all up to $3FFF. The 2KB SRAM is also mirrored, but i guess we have to live with that.
40 KB is still 10 times more than what the A2 had, so we shouldn't complain about that.
Now, what if we want to read from an external device???
First: We need a processing chip. M68K, W65C816, or just the W65C02 would help us do that.
Second: We need a device that reads our external device. Let's say it's a floppy reader...
Last: We need a VIA (or something else) to communicate with the external processor that will load our floppy for us.
With that, here's how it should work:
1 register for sector number.
1 register for number of sectors.
2 registers for address origin to load data to. (lo/hi)
1 register for enabling the transfer from device to RAM.
1 register for device status.
I'll use my assembly code to specify the informations. Then i'll poke a byte to the register that enables the reading. At this moment, i use this code:
Code: Select all
Wait_until_read_complete:
LDA Device_status
BPL Wait_until_read_complete
xyz...
At this moment, the 2A03/2A07 shouldn't access the RAM. If it does, the data is corrupted.
When the loading routine is done, when the status register bit 7 is true, we can continue.
Then, the code should be executable.
That lets us the possibility to import software to the console, like programs you saved on disk, or... BASIC???
If anybody is guessing about importing BASIC to the NES, it's another story, you have to decompile it, change things etc... Just throw that out...
How we read the keyboard? Oh yeah... oops.
Our external hardware will let us connect a PS/2 keyboard. We'll use a register for that.
Our input is sent to the external CPU. After checking and processing, it's sent to the register. The kernel will read it, then use it like actual keyboard input.
I don't know how USB works. Don't harass me with that.
Also, the idea of a "mouse" is useless for me. Use Windows 2.xx for that instead.
Now, i guess i'm done for the hardware. Regarding the software:
RAM address $0 will be used for "NMI routine ID".
0 just increments VBlank counter (address $1) then executes an RTI instruction.
1 is used by the kernel.
2 is for "custom NMIs". When NMI occurs, it just jumps to the address specified by RAM addresses $1E and $1F in little endian.
3 is used for commands from the kernel.
RAM address $1 is just a VBlank counter.
RAM addresses $2-$16 are reserved for the kernel.
RAM address $17 is what i call a "Break mode". It is used when a "BRK" instruction is executed.
0 returns to the kernel command prompt and shows registers values.
1 returns to the kernel command prompt and... that's it.
RAM addresses $18-$1D are reserved for the kernel.
RAM addresses $1E and $1F are used to specify the "custom NMI" routine address.
Finally, RAM addresses $20 through $9F are used as a command buffer, for conversions etc.
RAM page $02 ($200-$2FF) will be transferred to OAM by the kernel every frame. That lets you poking some values into CHR RAM to display sprites.
RAM page $03 ($300-$3FF) is used as a buffer for the command prompt. This is where your command goes when you type it.
Now, let's talk about interruptions, programming, etc...
The BRK instruction has an use. It's use is to stop your program and return to the kernel command prompt.
Basically, in your game, you may have a "quit" button, if you use it, your game will execute the BRK instruction. At this moment, the command prompt loads again.
WARNING: Before doing that, please clean pages $02 and $03 (RAM addresses $200-$3FF) so there's no conflicts with the kernel. Also set the "Break mode" (Address $17) value to $01.
NOW, for programming: "SEI" and "CLD" instructions are not required.
You don't need to clean the RAM. (Why wouldn't NES OS do it for you, anyway?)
The APU is already initialized.
And, for graphics: since the OS uses CHR RAM and not CHR ROM, you can change the characters and the sprites, even the ASCII characters that are already loaded! And, as i said earlier, you can display custom sprites in the command prompt.
Now, for the most exciting and final part: the commands.
Here's the commands i've implemented:
start: Executes code at the specified address.
poke: Modify one or multiple values from an address.
peek: Display a value from an address.
vpoke: Modify one or multiple values from a PPU address.
vpeek: Display a value from a PPU address.
clear: Clears the screen.
textcolor: Changes the color of the text.
shadow: Changes the color of the text shadow (there's none when you start the OS.)
bgcolor: Changes the color of the background.
light: Changes the color of the background to sky color.
night: Changes the color of the background to black.
These are the commands that i will implement:
list: Display data from an address to another.
vlist: Same, but for PPU BUS addresses.
ramclear: Clears RAM from an address to another.
vramclear: Clears VRAM from an address to another.
That's it! Honestly making an OS for the NES will just help us for making software directly on it and saving to disks etc... But it would be better in my opinion to do one for the SNES.
I'll release the ROM when it will have all commands implemented and all bugs fixed! (it still won't be finished after all...)