This page is in reverse chronological order, if you are new to this site
please start reading from the bottom.
2005-04-16 19:34 |
Added a cycle cap to the HighResolutionTimer . This effectively
prevents the timer from running away. Running away is where the amount of time
needed to complete a cycle batch results in the next batch being larger, and
this process tends to run away into larger and larger batches. The cycle cap
is the maximum number of cycles that can be returned by the timer regardless
of how many cycles should have actually happened. This will keep the system
responsive to user input but will reduce the effective clock speed.
Started to design a component for picking colors. Failed for now to come up
with a control that suits me for that purpose however, so the ability to adjust
the master palette is not ready yet.
|
|
2005-04-13 11:26 |
Updated the MemoryMapper interface to include a method that can
be called by main memory to indicate that a write was performed. The mapper
can do whatever it wants with that information and then returns whether or not
the write to memory should actually take place. Since most values the mappers
care about are writes into ROM they needed that ability to prevent ROM (usually
program data) from getting all messed up.
The other side effect of that however is that memory write functions needed
to be created to allow the mapper to do its initial load of memory and ignore the
mapper's own ability to veto writes. It was a catch 22 really. The mapper is
responsible for the initial load of the ROM into memory, the mapper has the ability
to veto writes to memory, in general the only writes that are vetoed are the
ones to the section of memory that is ROM, thus the mapper was vetoing its own
attempt to load the ROM into memory.
|
|
2005-04-12 23:13 |
Corrected an off by one error in the pixel color that only occurred at the
right-most edge of the sprite (assuming the sprite was not flipped). It was
being cuased by an inaccurate bit shift. Added correct transparency to sprites
so color value 0 is not drawn. Added code that will properly flip the sprite
in either the horizontal or vertical directions (or both) correctly.
|
|
2005-04-12 14:29 |
Spent a little time today upgrading the pattern table viewer. When I wanted
to draw a sprite with a script last time, I had to scale a screenshot
of a pattern table up 400% and draw lines on it by hand and do a lot of counting
to make sure I was looking at the tile I wanted. This process seemed like a
huge waste to me so I added a red box as a cursor for the pattern tables and
convenient labels at the bottom for identifying which pattern table you are
in, and also which tile you are over. While I was in there I greatly reduced
how often the pattern table image needed to be regenerated. It was a good thing
in general and was also very helpful for displaying the red box cursor quickly
as the mouse moves around.
|
|
2005-04-11 22:07 |
After some work on the PPU today, I finally got the sprite rendering PPU
internal function working to the point where a test script designed to
display one of the helmet guys from Super Mario Brothers actually showed him.
He is built out of four 8x8 sprites positioned carefully next to each other
and the colors he's made out of are simply colors hand picked by me. The
screen shot has been posted in the screen shots page.
|
|
2005-04-11 15:02 |
In continued efforts to work on the guts of the PPU, I created a sprite
test script for the OpCode Test Shell. This script included new commands that
didn't exist at the time. Now inspired by that script the ppu
command has been written granting you more or less direct control over the
internals of the PPU.
Also in the desire to make information validation even easier, I spent some
time creating additional tool windows. Now, similar to the PrgRomHexViewerGui ,
I have created both SpriteRamHexViewerGui and VideoRamHexViewerGui .
Then realizing that a visual way of validating the palette would be a good idea
I also created the PaletteViewerGui coupled with the
PaletteView component. Screenshots have been updated with the
new tools.
|
|
2005-04-11 01:27 |
Wired the PPU to the video screen with the Observable/Observer system. This
is one place that will work perfectly. In an effort to test the PPU/Video
interaction I created a test pattern tied it into the main hardware loop and had
it cycle internally while sending update messages to the screen. The result was
quite fun to watch, and while the cycle counts were higher per update than the
CPU running on its own, they were actually keeping up.
|
|
2005-04-10 16:02 |
A very long time ago I wrote the NesController interface and
the class NesJoypad . At the time I felt I was doing it correctly
based on the specs I had, but since I had virtually nothing else in the system
coded to wire the controllers into, I had no real way of knowing. Today, while
working on the DmaManager I wired the joystick ports into the
system through DMA's, and I must say, the task was completely painless. The
interface turned out to be well designed and easy to use. I've also written the
various video memory DMA channels as well, but they have not yet been tested.
One thing I've realized I need to figure out is how to implement the
appropriate delays caused by DMA's. For example, while the DMA to write a full
page of main memory into sprite memory takes place nearly instantly in my code,
the CPU needs to be prevented from doing anything for a rather incredible 512
cycles. Related to this is the thought that my Memory Mapper interface will both
need to be updated (as I expected it would) but also that the use of the mappers
will need to be moved from the upper hardware level down to the main memory level.
More research is needed before I can prove that, but for now I have a rather
strong hunch based on things I've read.
|
|
2005-04-09 17:35 |
I stumbled across a rather vast collection of PPU related research
documentation in my very own collection. Part of the problem was that many of
the documents actually refer to the PPU as the 2C02. I actually knew that from
all my research, but it had completely skipped my mind when I went looking for
something on which to base my PPU development.
Wrote an OpCode Test Shell script to validate the write to sprite memory
DMA I had written. Testing it identified a bug in the OpCode Test Shell where
address 0 was not accurately testable for any of the memory banks. Once that
was fixed the DMA was proven to work accurately. There are several others to
write still, but so far my game plan for DMA's seems to work quite well.
|
|
2005-04-08 10:13 |
As it turns out the JMP bug wasn't terribly difficult to code
it just took a little bit of mental gymnastics to come up with a way that
reliably produces the desired effect. It now works in the correctly "bugged"
way. The various Zero Page indexed addressing modes now remain in the zero
page of memory as they are supposed to. The theory that it would be a
centralized fix turned out to be correct.
Since I'm ignoring the task of OpCode Test Scripts for now in lieu of coding
things that are more interesting, I will be working on a DmaManager .
The way I see it, memory being observable is only truely helpful for the timely
updating of various GUI tool windows, and not for the core activity of the
emulator. After thinking about it for a bit, the observer would end up doing
things in a seperate thread and would likely result in obnoxious race conditions
from time to time that would be nearly impossible to trace down.
Speaking of memory access, my NesMainMemory does not do proper
shadowing for a couple of spots, and may need to be the home for the above
mentioned DmaManager . We shall see as I learn more about the
sneaky little things the NES did that were not directly part of any of the
main chips. Information I have on the CPU totals in the thousands of pages,
while what I have on the PPU stacks up to less than one hundred pages and it
all seems to contradict itself or not provide any real information. So much
research still appears to be required.
|
|
2005-04-05 19:15 |
Remembered a "bug" in the Indirect JMP OpCode that was in
the real processor but has not yet been implemented in my CPU. This one may be
a little tricky to code, and due to the confusing nature of the result, probably
equally tricky to test.
Also realized the Zero Page, X and Zero Page, Y addressing mode instructions
must all be tested for address wrap conditions because all zero page instructions
are designed to stay in the zero page. Fortunately that should be a centralized
fix in the code.
As a distraction from OpCode Test Scripts I have started to research the PPU.
It turns out there is a 3rd bank of RAM in the NES. Clocking in at a whopping
256 bytes in size, the SPR-RAM (or Sprite RAM) is an independent memory bank
accessible through DMA Channels. I added a NesSpriteMemory class
to the system to accommodate.
|
|
2005-04-05 19:15 |
I found a good explanation of page boundry crossing by indexed addressing
modes and corrected the code used for determining when it has happened. Now
all 152 OpCodes are written, and all the addressing modes appear to work
correctly. All OpCodes previously colored blue on the
OpCode Page are no longer blue. All that's left
is to validate all OpCodes that haven't been validated yet and the CPU will
be done. I hope to finish that tonight or at least make a lot of progress.
Ok, for the record, it's extremely difficult to remain motivated while
working on OpCode Test Scripts. Especially because many of the OpCodes I'm
now building scripts for now have several conditions that must all be validated.
This includes things as simple as setting flags accurately, and as complicated
as chewing up the right number of cycles.
|
|
2005-04-05 11:56 |
All OpCodes are now coded in the CPU core. The remaining ROL and
ROR proved to be quite a pain due to just how different Accumulator
and memory based addressing modes really are. SBC wasn't so bad
as it's almost exactly the same as ADC except for the use of the
carry flag and the obvious replacement of a minus sign in a few places.
All that remains is to either locate a document that better explains what
page boundry crossing is or at the very least to read it again and again until
it clicks. That will be part of the validation process for 17 of the remaining
60 OpCodes.
|
|
2005-04-04 13:55 |
Continued efforts on developing OpCodes in the CPU have finally resulted
in a working ADC OpCode. This is extremely exciting and it took
a programmers manual from 1976 before I felt I had enough information to
accurately code it. For good measure I've already tested ADC
in immediate addressing mode through the OpCode Test Shell. Subtraction
and the missing modes of ROL and ROR are next on
my list, and are the only remaining OpCodes not yet written.
|
|
2005-04-02 14:46 |
With so many OpCodes now successfully verified I decided to spend a little
time actually coding the guts of the ones that are still missing. Coded several
ASL OpCodes and a couple ROL and ROR 's
as well.
|
|
2005-04-02 10:07 |
I've been working for many hours now (tonight and this morning) on getting
the cycle counts correct for branch instructions. So far they still aren't
correct and are proving to be extremely tricky to fix. Most of the problem
is accurate detection of a page boundry crossing for relative addressing
mode.
Relative addressing mode page boundry detection now works perfectly. The
branch instrustions are no longer blue on the OpCode Page
because of this fix. Now comes the tedious process of testing all of the
branch instructions. The scripts have to test all 5 uses of each branch
instruction and validate resulting PC value and the number of cycles the
branch took. Fortunately there are only 8 of them for which to write scripts.
|
|
2005-04-01 11:29 |
Validated OpCode count is now up to an amazing 82. That puts me well over
half done with the CPU by OpCode count. There are still several more OpCodes
I can write test scripts for, but I think I'm going to actually spend a little
time writing new OpCodes today for a change of pace. Also added JavaDocs to
the file that was missing them.
The regs OpCode Test Shell Command now supports display of
individual register values or flag values by name. The new regset
command allows for directly setting register values and works in the
same way as the memset and vidset commands.
Put the output from help for each OpCode Test Shell command
up on the Help Page.
MemoryAccessMessage now supports an access type of TYPE_CLEAR
for use by the clear() functions of both NesMainMemory
and NesVideoMemory .
|
|
2005-04-01 00:13 |
The step command was not returning any information besides how many
cycles it took to execute the next step. The output of how many cycles an operation
took does little good for accurately identifying what was done. A new data transport
class called ExecutedInstructionInfo was created for the purpose of
providing more information back to the OpCode Test Shell.
Plans for tomorrow (well, later today I guess at this point) include filling in
the JavaDocs for GameGenieTableModel which was thrown together in
haste and didn't get them as it should have. I've been tossing around the idea of
adding a command to the OpCode Test Shell that allows direct manipulation of CPU
register values. And naturally, more OpCode Test Scripts and maybe even some work
on correcting the "blue" OpCodes or writing code for unimplemented OpCodes.
|
|
2005-03-31 11:25 |
Working on OpCode Test Scripts again. I've corrected a problem that universally
affected all CMP , CPX , and CPY OpCodes.
The problem was caused by a misinterpretation of a description on how the OpCodes
work. After referencing another document and rereading the original description
again, I pinned down how it should be working and set out fixing the 14 OpCodes
that were broken because of this. Now finished validating INC ,
DEC , CPX , and CPY for all addressing
modes.
Added memclear , vidclear , step ,
and rom commands to the OpCode Test Shell. The power on
command no longer clears memory. The step command runs the next
instruction in memory as though the CPU were just granted enough cycles to do
it. The rom command loads a ROM file and inserts it into the
hardware.
Corrected the power up sequence the hardware was using. The old way resulted
in the program counter being stuck at the default of $0000 which is inaccurate in
all sorts of ways. The power on order of events was powering on the CPU before
powering on the mapper and for that reason the CPU was loading the Reset Vector
before any memory was loaded from the ROM.
|
|
2005-03-29 23:29 |
After a bit of work on the news/development note admin tools for this site,
I have resumed working on OpCode Test Scripts. I'm expanding my script creation
into addressing modes that are more complicated since they obviously need to be
tested too, and likely more than the easier ones for which it is easier to write
scripts. It makes me happy to be working on the core emulator again on some level
after a break for Game Genie related things and a spot of web development.
Added the clear() method for resetting memory to all zeros to both
main and video memory banks and also made the power on OpCode Test
Shell command do this to both banks. This will help eliminate false successes on
OpCode Test Scripts caused by values that exist in memory before the test.
Verified and corrected as needed 7 OpCodes tonight. These included advanced
addressing mode versions of STA , STX , STY ,
INC , and DEC OpCodes. Many more will likely be verified
tomorrow, and if I can work up the motivation, I will even code some OpCodes that
haven't been implemented yet.
|
|
2005-03-28 15:14 |
I've finally gotten around to actually working on the Game Genie GUI. It's
been a while since I've used a JTable so I'm a little rusty and it
took a little longer than I would have liked as I relearn how to use them. The
GUI window does very little in the way of validating the codes or values entered
by the user, but it does work. You can add or remove codes with relative ease.
There is a screenshot of the new GUI on the Screen Shots
page.
|
|
2005-03-26 19:10 |
Today I fixed how the indirect addressing mode functioned. It was not
returning the target address, it was instead returning the value at that
address. For this reason the JMP OpCode in indirect mode
was broken. Also, the JMP instruction in absolute mode was
doing more of an inaccurate indirect jump instead. Both have been corrected
and function properly now.
|
|
2005-03-19 17:23 |
Coded the GameGenie hardware and incorporated the use of a
MemoryFilter into NesMainMemory . The Game Genie
I have created is not limited to 3 active codes as the original Game Genie
was, but due to processing overhead, I can't recommend the use of excessive
numbers of codes. Every time memory is read the Game Genie code must check
to see if it needs to return a modified value for every active code. How
much overhead this adds is unknown, but considering the frequency of memory
reads, I can only assume it adds up pretty quickly.
Next on the list of things to work on is a GUI for dealing with active
codes. I will likely allow codes to be entered as either original Game Genie
formatted codes, or as raw data for the 3 fields (or 2 fields for 6-character
codes.) I figure I will resume working on OpCodes soon, but I needed this
break from them.
|
|
2005-03-18 18:26 |
Corrected a small problem where 8-character Game Genie codes were not being
properly recreated from stored data all the time. Had the wrong bit mask in
one place. If that bit happened to be a 1, the index of the resulting value
was way out of translation range. Otherwise it worked fine.
Revised the MemoryFilter interface. Didn't seem right that a
filter would need a reference to a memory bank to function, so now both the
read and write functions expect a value. To work correctly, it is expected that
you read a value from memory and pass it through the read filter to get the byte
that should be returned. For writes, you pass in the value you expect to write,
and it returns the value that should actually be written. Makes much more sense
this way as it also means that the MemoryFilter interface can be
used on any type of memory where before it was being inadvertently restricted
to work with main memory only.
|
|
2005-03-17 02:21 |
Completed the GameGenieCode class. This class acts as a data
transport and translation system. This particular file may have more bit
shifting and masking than any other file I've ever written. The designers of
the Game Genie were clearly trying to make it difficult to make your own
codes. Perhaps they were planning on selling you new codes, and if my memory
serves me, they did just that for a short time. Their efforts to obfuscate
their code system did little beyond making it more of a pain to emulate
in the end, but my tests of the code translation functions seem to prove
my efforts victorious none-the-less.
|
|
2005-03-15 23:49 |
Very little development today due to socioeconomic forces beyond my control.
(Forces that will likely continue to affect me for the next couple of months.)
I still have some things to talk about however. In web site development related
news, the display and input form portions of the feedback system were written
today, the submit and form validation parts will probably be written tomorrow.
On the Game Genie front, I put together a skeleton of the actual hardware
code today and prompty realized I would not be able to do anything effectively
the way I was planning on doing it. My thought was to have a GameGenie
object that was a main memory observer. It seemed right until I started writing
it. Then I quickly realized that an observer would be unable to jump in and
supply an altered value since the unaltered value was just read (and thus why
the GameGenie code was getting the access message about it.) The correct way
to do it is actually to create a generic MemoryFilter interface that
provides the rules for altering values read from or written to memory. Then to
revise the NesMainMemory to allow the use of one of them. And
finally to make the GameGenie hardware code implement the
MemoryFilter interface. A clean and simple solution that provides
the ability to support Game Genie codes, and any number of other interesting
filters that someone may come up with later on.
|
|
2005-03-15 02:46 |
Started working on a database backend for the Monkey Coder sites (which
obviously includes this site.) This system is small and only designed to
handle news (like development notes) and feedback (like bug reports and
other end-user comments.)
In news actually directly related to MonkeyNES I can say only that as a
small break from working on OpCode test scripts I started to think about a
GUI for Game Genie related activity. To make everyone's lives easiest it will
support a code box for original Game Genie codes and boxes for the translated
hex values. The boxes will be connected in both directions so you can fill
out one set or the other and the other set will be filled out for you. This
should give you the ability to create Game Genie codes in the simplified
broken down way (the way the system will handle them internally) and it will
produce for you the scrambled codes the original Game Genie used. So, if you
own one, you should be able to try out the codes on your real system. I will
code the Game Genie system when I have time, and hopefully soon while it is
still fresh in my mind.
|
|
2005-03-12 13:27 |
FreeBSD has historically weak Java support. I believe the last "official"
release of Java for FreeBSD was version 1.1.8. Recently there has been talks
between FreeBSD people and Sun people to try to get a more recent version of
Java onto FreeBSD. From that effort a port has become available for Java as
recent at 1.4.2. Technically 1.5 is also available, but they don't reccomend
its use. This is exciting news for FreeBSD users. It took my FreeBSD machine
(P4/1.7ghz) a little more than 4 hours to compile Java and it used almost 1.7GB
of hard drive space in the process. MonkeyNES does in fact run under FreeBSD
which was cool to see. Due to these efforts a monkeynes.sh file
is now also included in the package to start the emulator. This also means
that the minimum version of Java required to run the emulator will not be 1.5
as was previously indicated. That way I have the potential to reach the most
people on the most operating systems.
And once again... back to test scripts for OpCodes. Several OpCodes have
been corrected (more address/value mismatching) and several have been proven
to work correctly. The total for validated OpCodes is now up to an impressive
52.
|
|
2005-03-10 17:42 |
I've been working on OpCode test scripts all day. Several of the OpCodes
that I had already validated I had to revisit because I was not properly
verifying conditions that are supposed to change processor status flags.
I am being much more careful to write the scripts completely now.
Several OpCodes that had already been verified incorrectly have now been
fixed. One example is the TSX OpCode was not correctly setting
status flags S or Z . The reason for this was simply
because the code wasn't even there. The document on which I've been basing most
of my OpCode development said nothing about affected flags for any of the "Stack
Instructions." As it turns out, all the other documents I have do say something.
TSX and TXS are not quite opposites as
I had previously assumed. Transferring from IX to SP
affects no flags because the SP register simply doesn't care.
Transferring from SP to IX however can affect
either the S or Z flags because the IX
register does care.
The NesCpu now correctly treats all unknown OpCodes as
NOP 's. INX , INY , DEX and
DEY all now correctly set the S flag. STA ,
STX and STY now work correctly in absolute addressing
mode.
|
|
2005-03-09 01:15 |
I thought of a feature that would make the OpCode Test Shell even better.
The ability to verify values automatically seemed like a good thing to add.
That way when looking over the output of a complicated script you can see
right off the bat whether a value is what you expected it to be or not. Now
using the test command you get a clean and easy to read true
or false value from a comparison.
The test command gives you direct access to all CPU registers,
all CPU flags, and both main and video memory banks at any address. You can
compare them using =, !=, <, >, <=, or >= to any hex value you wish. As with
all other commands in the test shell, full help is given both at parse time
and through the help command.
Back to writing OpCode test scripts...
|
|
2005-03-05 22:18 |
After 2 extremely long feeling days of updating JavaDocs for source files
that truely should have had them all along, I am done. All current source
files now have full JavaDocs. Go check them out from the
JavaDocs page if you like.
|
|
2005-03-04 23:00 |
After what has seemed like an eternity of doing JavaDocs, and if not an
eternity certainly all day, I have caught up on fleshing out the JavaDocs
for 30 of the 44 java files. If this isn't an extremely strong case for
doing JavaDocs as you develop instead of all at once I don't know what is.
Not a whole lot to report on the development front because of all that
JavaDoc'ing. Check back tomorrow for what I hope to be the report claiming
I am done with JavaDocs and have resumed my efforts on OpCode validation.
|
|
2005-03-04 11:41 |
The opx parser now works! It successfully translates 6502
assembly statements into op commands for you. Now the real
JavaDoc effort can begin.
|
|
2005-03-04 08:27 |
Added into the OpCode Test Shell the ability to detect recursive or cyclic
nested file loads. It allows nested files to be loaded up to 10 layers deep.
I cannot imagine anything that would require a depth more than about 3 deep,
so I figured this wouldn't be limiting, but would help prevent trouble. The
count of 10 does not include the original load command typed in by the user.
Started working on the opx parser as well.
Added the CpuRegister16 class to prevent confusion between the
8-bit registers and the program counter (PC) register which is a 16-bit
register. Also added the cage() function to CpuRegister
to provide a centralized function for restricting the bits that are in use by
the rregister.
Began fleshing out the JavaDocs for this project. This may take several
days to complete, but I feel it will improve the overall quality of the project
tremendiously.
|
|
2005-03-03 07:56 |
Ok, the supposedly broken addressing mode was not actually broken, the use
of it was however. I inaccurately assumed the addressing mode was broken when
"fixing it" also fixed the OpCode I was testing at the time. The flaw there is
that all the other OpCodes that use that addressing mode need to go back into
the test bucket. I have reverted that change and created a master test bucket
script. OpCodes are no longer fully validated until they are ALL validated at
the same time by the master script.
This also presented an interesting problem where using the clear
command in files loaded by a script would effectively destroy the output for
that script instead of simply cleaning up the output buffer which is desired
when scripts are being executed one at a time. The load command
now disables the use of the clear command in nested scripts.
|
|
2005-03-02 12:46 |
The OpCode Test Shell is just about the best piece of code I've ever written.
It's like installing a bug zapper into your code and hooking it up to a 20,000v
power source. I've found broken OpCodes, broken addressing modes, even
memory writes that weren't being contained properly within their 8 bits per
address, all made visible in crisp detail with small scripts.
|
|
2005-03-02 08:51 |
Ok, lots of new features added to the OpCode Test Shell. There are now
quite a few things the it is capable of doing. You can run ops, clear the
output, turn the power on and off, set values to or get values from either
main or video memory, add comments, view the CPU registers, load scripts
from a file, and save the shell output to a file. It even reports how many
cycles the instruction took to complete so you can validate branch taken and
page boundry conditions. And how about the added pleasure of a command history
you can navigate with the up and down arrows. All that and all the help for
each command you could ever want built right in.
Now comes the fun, read horrible, part. Now I have to sit down and
write 152 test scripts that literally beat the heck out of each OpCode and
confirm how it handles both base and border conditions and make sure they
all work. And let's not forget that I'll need to fix the ones that I find
to be broken. On the bright side, most of these scripts don't need to be very
long and many will be able to borrow code from each other as they test similar
things. On the not-so-bright side however... did I mention that I have to
write 152 of them? Many of which are for OpCodes that haven't even been
developed yet.
|
|
2005-03-01 15:34 |
Everything except opx is written now for the test shell. New
things may be added as I use it to test OpCodes and determine that new
features would be nice to have.
The process of verifying all the OpCodes will be documented on the
OpCode table page with the use of colored
backgrounds behind verified OpCodes.
|
|
2005-03-01 08:34 |
Created the basic layout for the OpCode Test Shell and tied it into the Tools
menu. More information to follow as I work on it throughout the day.
The function for getting a specific bit from a register still wasn't working
correctly and should be fixed now. The OpCode Test Shell has come very far
considering it didn't exist at all this morning. It now has an extensive help
system and can execute instructions. Next on the platter of things to add to the
shell are setter and getter functions for main and video memory. The help system
already knows about them, but the code isn't actually done yet for them. After
that the opx command for executing 6502 assembly instructions instead
of the raw hex support of the op command will be written.
|
|
2005-03-01 01:04 |
Cleaned up the CPU State Viewer in the ways mentioned below. Everything is in
convenient to read hex values, the status register has been split into the individual
flags and a bug was located in the CpuRegister.getBitValue(int) function.
The function was supposed to return an int with a 1 or a 0 depending on the value of
the bit at the requested position, but the value was not being properly shifted and
the value was of the mask not the bit.
Tomorrow I begin the insane process of creating an OpCode test shell. A system
through which each OpCode can be executed with different values and the CPU/memory
state before and after can be viewed and checked for accuracy. I'll be honost here,
I'm really not looking forward to this, even if I know I need to do it.
|
|
2005-02-28 00:21 |
The CPU State dialog is done for now. It's ugly, it should problably have
the information presented in a cleaner way, and it's not real-time, but it does
appear to work. On the fact that it's not real-time I did that on purpose. The
last thing the poor overworked CPU code needs right now is the added overhead of
sending out state update messages. Breaking apart the processor status (PS)
register and converting the other values into hex prior to display would probably
be nice so I'll keep that in mind for the next version.
On the bright side this new tool has hinted at a couple of potential bugs.
That makes it worth the effort already. Now granted the CPU isn't done yet, but
the ACC and PC registers either aren't ever being updated, or they aren't being
reporting correctly to the state viewer, but something about their values seems
wrong.
|
|
2005-02-27 16:28 |
I remembered that I was working on this project once upon a time and started
looking at it again. Most of today was spent digging through the code and even
these development notes to figure out what I may have been doing when I stopped
coding last time. Cleaned up this site a little bit too. Specifically I pulled
the OpCode table out of the development news page and enhanced it to include ALL
OpCode information (accessed by mouse over of the table.)
Since at some point in the last 6 months version 1.5 of Java was released by
Sun, the project will likely be written to require it from this point on. This
may also involve revisions to existing code to use new features. Hopefully the
new version of Java will be a little faster.
In regards to my complaining about the speed of the project in previous posts,
I would like to mention that a wise friend of mine reminded me of a very important
rule of development. "Get it to work, then make it faster." So for that advice
I send my thanks to Org, as without that simple thought I may never have resumed
development on this project.
First I plan to work on is a CPU status GUI. It will undoubtedly be an
overcrowded and hard to read window full of register values and status flags and
program counters and everything else, but I think it will be very handy to have
in the near future as I attempt to debug my OpCodes.
|
|
2004-09-06 22:32 |
I've stumbled across some serious doubts about how I'm doing things within
my NesCpu class. Questioning things as simple as "Am I properly
restricting the values to 8 bits or 16 bits for addresses?" up to things as
complicated as "Am I setting register values and flags correctly for any of
my instructions?" and let's not forget the one that can spell doom for the
whole project "Why is my CPU running so slowly considering how simple the
things it does are?"
I think before I can go much further on the NesCpu class I
will need to create an op code test driver and build the hooks I need to
support it. That way at least I can see exactly what I'm doing and whether
or not it's wrong and if it's wrong, how exactly it's wrong.
After that I will need to start thinking of ways to speed everything up. The
current speed of things internal to the CPU isn't able to keep up with the clock
speed of the system, and that's without the added overhead of the PPU, the pAPU or
cycle counting in mappers. I only hope I can figure out how to make it faster.
I think in this case I may be fighting a battle against the inherent speed issues
of Java.
|
|
2004-09-04 20:01 |
Added a PRG-ROM Hex Viewer so that I can look at the bytes in the PRG-ROM to
verify things. Sounds so simple, but it's actually easier to use than a hex
viewer on the .nes file because of the fact that it only shows what's currently
in PRG-ROM (and with the correct offsets) and not other things like the INES
header and CHR-ROM and the like.
|
|
2004-09-04 13:36 |
Finished coding all the addressing modes. Now I can really start laying into
the op code development. For progress on the op code development please see the
table on this page.
|
|
2004-09-04 02:07 |
Found a decent document on how the addressing modes work, it's not quite
perfectly clear on a couple because I have to match them up to information
in other documents due to differences in names but it should be good enough
to go on. In the mean time I can code many of the implied mode instructions.
I also needed to stop development to chase down some conclusive data on
how exactly the stack works in the 6502. I knew that it lives in page one of
main memory, and I knew that the stack pointer points at the first available
empty spot on the stack... but I needed to know which way the stack worked
in terms of addresses. I'm glad I looked because I would have assumed that
the stack pointer starts on $0100 and increments toward $01FF with new pushes.
I would have been completely wrong however. As it turns out the stack pointer
starts on $01FF and decrements with new pushes. This is very important for
roms that do any sort of stack short cutting.
|
|
2004-09-03 00:36 |
Began working on the NesCpu and NesOpCodeTable
classes. This is obviously one of the largest pieces of this project and
between the two around 2500 lines of code have been added so far, and that
is without even a single op code actually working in the CPU. Tomorrow will
be spent coding individual op codes and researching addressing modes and
that sort of thing.
|
|
2004-09-02 11:23 |
My research on how to render things faster turns out to have been a very
good use of my time. I added a little bit of code to time the rendering of
the Pattern Table View so I could easily see if my research was producing any
speed advantage. Below is the results of my optimization:
|
Initial |
CPU On |
Old |
3437ms |
3547ms |
New |
62ms |
6ms |
Improvement |
55.44x |
591.17x |
I didn't change anything about my PatternTableTile as I had
originally planned to do. I started instead with the alternate rendering
method. Instead of using the Graphics class to literally draw
every pixel into the view, I now blast the raw pixels into a buffer, dump that
into a MemoryImageSource , dump that into an image, and use the
Graphics class to draw that image for me. It sounds like much
more work, but when you consider the virtually non-existant overhead of blasting
pixel values into a buffer it becomes quite obvious that time will be saved.
Today I bit the bullet and purchased some parts for a replacement machine
for TrollServer. It'll be a couple of weeks before they come in and I can set
up the server again, but the process is at least underway.
|
|
2004-09-01 17:55 |
Both memory banks (main and video) are observable now. To make this feature
a bit faster for situations that truely don't need observation there is a
second copy of each of the access functions now with NoMessage
stuck on the end, these versions as indicated by their name don't send an access
message to observers. This was added to make supporting mappers with features
such as IRQ timing counters and virtual register access possible. As a test bed
for this capability the Pattern Table Viewer now observes video memory and updates
the tiles as needed.
I will likely be modifying the internal structure of the PatternTableTile
class to (hopefully) speed it up a bit on the rendering end. While I'm at it, I
will probably explore other methods of rendering to speed things up (because if
the speed found in my Pattern Table Viewer is all that I have, I'll be seriously
hurting for a good frame rate while emulating for real.)
In the near future I'll probably add a Technical
page for more detailed descriptions of how things work within this system. Or at
the very least, how I am planning for them to work.
TrollServer is still down and out, I have no replacement hardware yet. Anyone
with a quad Itanium2 or Opteron system sitting around that wants to donate it?
|
|
2004-08-27 19:53 |
Began the rather brutal process of managing the NesController 's
interaction with the user and with the NesHardware . Ironed out
a couple of issues with my timing loop too. The system I have so far seems to
be pretty clean, there are undoubtedly a few issues that would come up if a
Joypad was not "plugged in" to the Hardware, but I'll let those slide for now
since with the simple system of a drop box to choose the type of controller
plugged into each port, they should never come up.
Still no TrollServer... Keeping my code for the project and this site on
my USB JumpDrive in the mean time.
|
|
2004-08-27 19:53 |
Built the main timing loop which locks the system to a specific clock speed
while keeping it synchronized. Created the NesController interface
and NesJoypad class for user input. Put the NesHardware
in its own thread. Fixed the disabling of the menus to have the right things
enabled or disabled at the right times. All in all it was a busy night of
development.
In other news, the TrollServer machine is on its very last legs. There was an
ongoing battle between the power supply and the motherboard and it would appear
that battle is drawing to a close. There are no survivors expected. The frantic
process of trying to find another cheap machine to turn into the reincarnated
TrollServer has begun, but with my luck on ebay, it won't end up working out for
me in the end.
|
|
2004-08-27 19:53 |
Tonight's focus is mostly non-NES related. I've fixed the StateLight class up a
bit. It now draws correctly. I also created a logging singleton called DebugLog.
It supports output to standard out, to standard error, to a file, and into the void
(not logged.)
I am also planning to build several of the options GUI windows and the Help
About window. I'm getting to the point where having some knowledge of what
options I intend to offer is a good idea. Tweaked the NesPalette
class so that the int versions of all the colors are available as well as the
Color versions.
|
|
2004-08-26 23:17 |
Tonight I came up with a design for the timing system that I think I like. It
should be able to keep the system to roughly the correct clock speed while at the
same time keeping things properly synchronized. That way when I eventually support
games that do PPU timing hacks, the rusults should be correct.
The basic plan is to time everything backwards. Effectively timing everything
based on how much could have gotten done in a certain time frame and then doing that
much stuff. 'Stuff' in this case is running a cycle at a time on each of the chips
that is affected by the clock. (CPU, PPU, pAPU, etc.) If a single cycle isn't enough
time to do something, the cycle is stored by each chip individually until enough are
available to do the next operation.
Began the process of encapsulating all the systems of the NES into a single
container class called NesHardware . It contains things such as the
CPU, PPU, pAPU, Main Memory, Video Memory, the Game Rom, the Memory Mapper and the
High Resolution Timer. With them all together under one roof the interactions between
them should be fairly straightforward to design.
The sloppy coding of hard wiring the Pattern Table Viewer to the Power menu has
been fixed. It is now accessible as it should be through the Tools menu. Also added
to the GUI are the ROM loaded (green) and power on (red) lights in the status bar at
the bottom.
|
|
2004-08-26 09:27 |
I haven't been able to work on this project for a few days due to schedule
conflicts. Busted alternator in my car that I needed to replace, various social
obligations, and countless other distractions have kept me occupied. I've glanced
at my research stuff a handful of times and I organized my NES ROM collection into
directories for each individual letter so the directories wouldn't take so long to
load. More development is coming very soon.
To appease the masses that flock to this site every day for updates and
screen shots and new versions and all that other fun stuff, I have added several
screen shots of the Pattern Table viewer to the screen shots page. Now showing
16x Mapper 0 games that you might recognize.
|
|
2004-08-20 18:36 |
Aparently I was very tired last night, because my mathematical acrobatics were
producing incorrect numbers for how big the pattern tables actually are. Today I
decided to give it a go anyway and load the CHR-ROM as though it were simply the
Pattern Tables. Then I made a Pattern Table Viewer and sloppily hard wired it to
the Power On menu. I loaded up a Mapper 0 ROM, turned on the system, and amazingly
the very recognizable graphics from Super Mario Bros. showed up in the Patter Table
Viewer box.
The next step is to correct the sloppiness mentioned above and to correctly wire
the Pattern Table Viewer to its proper place in the Tools menu. To do that I will
also need to build a class for orchestrating all of my hardware related classes.
Also fixed a problem in my GenericFileFilter where it wasn't matching odd
capitalizations of the .nes file extension.
|
|
2004-08-19 17:42 |
Due to the sheer number of mappers there are, the mappers have been moved
from the com.monkeycoder.monkeynes.hardware to the
com.monkeycoder.monkeynes.hardware.mapper
package.
Also still trying to figure out exactly how the CHR-ROM is laid out. It
doesn't seem to be simply the Pattern Tables as I had at first figured it might
be. While it does fit perfectly in the Pattern Table space in the PPU Video RAM
area, the info I have about the Pattern Tables seems to make them far smaller than
the amount of data typically found in a page of CHR-ROM. Back to square one on
that research I guess. For good measure I'll likely craft a Pattern Table Viewer
before I move on just so I can see what IS in there.
|
|
2004-08-19 13:15 |
MonkeyNES Site Launched. After a couple of days of development and a couple of
days of research before that, I figured I should make decent web site detailing
the process. Eventually I may make this page database powered, but for now I'd
like to stay focused on MonkeyNES.
|
|
2004-08-17 15:40 |
Working on many "under the covers" systems that do large amounts of work
but don't really get much credit in the end. These include the code for
loading a *.NES file into memory, the access functions for dealing with
the main and video memory banks, and things like that.
|
|
2004-08-16 23:56 |
MonkeyNES development has begun. Trying to get around several limitations of the
Java language already. Specifically, the NES is an 8-bit system so nearly everything
involving numbers is based on the numbers 0 to 255. Java doesn't have unsigned types
(either primitive or objects) which was messing me up with opcodes at first because
the numbers were ranging from -128 to 127 which is obviously not going to work. My
rather simple solution was to treat every 8 bits as 32 bits instead. This allowed
plenty of space for numbers while probably speeding up the system as a whole due to
the 32-bit machines it would likly be running on.
In most cases this change doesn't even require masking to make it work which is
nice. The "wasted" memory involved is still nothing to worry about because of the
simple fact of how little memory the NES actually had.
|