We're using cookies to ensure you get the best experience on our website. More info
Understood
@guyperfectRegistered December 4, 2012Active 3 years, 4 months ago
375 Replies made

Whoops, got ahead of myself. I’m no longer allowed to go back and edit that post for correction, so I’ll post the correction here.

Bit 14 of the shift register is not used as the output. That was NES that did that. In Virtual Boy, the output bit is the inverse of the result of the XOR operation.

For example, if bit 7 and bit 14 are XORed together and the result is a 0, the output is 1. The 0 is then shifted in on the right.

I apologize for the misinformation. (-:

Thanks for the input, though it doesn’t appear that persistence factors into it any. The entire display is emitted by the LEDs over the span of 5 milliseconds, which is 1/200th of a second; well faster than the fastest known human vision persistence. Increasing the time that 1 column of LEDs (1/384th of that 5ms period) emits should, by all accounts, result in a brighter image no matter how long it stays on.

My take on it is that the content on the dev wiki is… not helpful. I look at pages like Instruction Summary and come away from it knowing no more than I do going in. It’s mostly a copy/paste of Tucker’s old document, and as such is quite incomplete, has several factual errors, and most of the pages are stubs.

At the end of the day, it’s easier to look through Tucker’s document and not find what you need than it is to follow links through the wiki and not find what you need. (-:

That’s why I set out to make the Sacred Tech Scroll. Like Martin Korth did with his NO$ projects, it’s a single document filled to the gills with all the necessary details. I’m sure to make edits to it as I’m writing an emulator, but there’s enough in there to make working programs using every aspect of the Virtual Boy… ’cause I have. (-:

That said, I’m working with dasi now to get some programming tutorials written up, and we’re thinking the dev wiki would be a good place for those. The way I see it, if it’s not a good place for hardware details, it could at least be a good place to learn Virtual Boy development.

Greg Stevens wrote:
I’m pretty sure that the compiler I’m using is not doing an arithmetic shift when I use >> and I just need to fix that.

Compilers usually use arithmetic right shift on signed variables and ordinary right shift on unsigned variables. If you want to use arithmetic shift, make sure your variable is signed.

While I can make a wire frame model and move it around in 3d space, I still need the routine to actually rotate the object around the 3 axis.

The best way to do this is with something called a transformation matrix. Basically, the concept is this: you take your input XYZ coordinates as a vector, multiply the transformation matrix by the vector, and the output is a new vector with your modified XYZ coordinates.

In 3D geometry, you’re going to want to use a 4×4 transformation matrix, and use 4×1 (rows, columns) vectors for your coordinate input. Why 4 when XYZ only accounts for 3 coordinates? For starters, you can’t perform a three-dimensional translation with a 3×3 transformation matrix. Further, the W coordinate is required for perspective projection, which is a non-linear transformation and therefore a transformation matrix in and of itself is insufficient.

When you want to modify a transformation, such as applying a rotation or translation, you simply populate a second transformation, then multiply them with each other to produce a new output matrix. It’s really quite handy.

The OpenGL documentation demonstrates the mathematics behind working with a model/view matrix:

* glRotate
* glScale
* glTranslate

Further, it provides calculations for a projection matrix. Projection matrices take world coordinates and convert them into normalized device coordinates. Basically what this means is: X = -1 is the left edge of the screen, Y = 1 is the top edge, Z = 1 is as far “into” the screen as a point can be, etc.

* glOrtho – In an orthographic projection, objects in the distance are the same size as objects up close.
* gluPerspective – A perspective projection simulates real-world perception of objects.

After applying the transformation matrix for projection, you then need to divide each of the X, Y and Z components by the W component to yield the final device coordinate.

Clear as mud? Great! If you need help, just let me know. (-:

The plot thickens!

There were some errors in my previous post. Where I mentioned the bit string lengths were 48, I actually meant 40; they processed 5 bytes.

Second, the algorithm for CPU processing of bit string instructions is incorrect. Turns out the CPU is smarter than that.
__________

I’ve prepared revision #7, attached to this post.

RealityBoy, astonishingly, gets it 100% correct:

And this is Mednafen, which gets two of the three columns right (even if the brightness is bonkers):

The column on the right is the initial state of memory prior to any bit string instructions.

For both columns, one bit string starts at bit 24 of word 0, and the other bit string starts at bit 0 of word 2. The length for both is 168 bits, which is 5 whole words, plus one byte.

The left column has the source string begin before the destination string.

The right column has the destination string begin before the source string.

In both cases, on the real Virtual Boy system (as well as in RealityBoy), the source is copied to the destination intact; the source string is never overwritten by the output before it can be processed. In other words, it behaves like the standard C function memmove(), but on individual bits instead of whole bytes.

This tells us something very important: the bit string instructions were absolutely designed to function on overlapping bit strings. By this point, I can only assume that MAGIC happens when an interrupt occurs, and that when the instruction resumes it will finish processing correctly. That is to say, by this point, I believe NEC covered all their bases when designing the V810.

In the mean time, let’s all take a moment to point at Mednafen and laugh.

Attachments:

Heeeey, it’s an Arwing! If that’s your first C program, then color me impressed (but with a slightly different angle for each eye)

Okay, thanks to HorvatM and bigmak for testing this program. You guys rock!

First of all, the reason it wasn’t working right is because I typoed an instruction in the hex editor. I typed 00 02 where I should have typed 02 00. After fixing it, the program works great! I’ve attached the fixed ROM to this post.

Anyhoo, both users determined that the maximum effective brightness of the LEDs is in the neighborhood of 0x80; maybe a couple more, maybe a couple less. This is very important information.

However, I couldn’t get the math to line up. My current guess is that the maximum physical brightness of the LEDs is around 0x80, not that the emission period is necessarily saturated within the display period. I’m not really sure how to go about finding out, since by this point everything is hypotheical.

Attachments:

Got it! Only took four tries, but after I knew what I was doing, it all went smoothly.

Memo to self: if it doesn’t show up, you forgot something.

ROM is attached to this post.

Attachments:

All ASCII characters fit in 7 bits. The international characters (including those with umlauts) in CP-850 as shown in the image are in the 128-255 range; the highest bit is set.

My guess is that something in the compiler is reading characters as bytes, sign extending them when that high bit is set, and is munging up your result accordingly.

It’s hard to diagnose at a glance, but you might see some success if you use unsigned char variables instead of char variables.

Also, the really awesome thing to use is Mednafen and its debugger. Mednafen is one of the emulators out there. It’s debugger will show you all the registers (even VIP) and let you root around in the loaded memory space.

Duly noted, and thanks for the tip. (-:

One of the things I want to do is make a programmer/hacking focused emulator of my own. It’s not because there isn’t one; I just want to make an emulator and Virtual Boy sounded like a good project. I originally considered NES, and that one’s been emulated out the wazoo.

Anyhoo, the point is that when it comes to spiffy Virtual Boy emulation, I hope to bring something to the table!
__________

In other news, I got my first ROM up and running! It won’t work on a real Virtual Boy, however, because the VIP column table isn’t initialized. But with that one exception, it works like a charm.

My first (and second) attempt was to produce the image I posted in the original post, but it didn’t work. Why didn’t it work? Who the crap knows; there was a fair amount of code and I had no idea which part of it was wrong. So instead I pulled back a step and consulted Occam, who recommended I do the simplest thing that could possibly work.

So rather than three squares, which is more involved than one might think, I just set out for the simplest output possible: change the color of the screen. And that, much to my delight, worked like a charm. The program does the following:

* Run a dummy loop for 0xFFFF iterations to allow the system pseudo-RAM to warm up. This is specified in the dev manual, and the exact method was taken from Wario Land.
* Clear the status register and disable interrupts. This was also taken from Wario Land.
* Configure World 31 as the control world; no worlds will be drawn to the framebuffers. Come to think of it, I think I was trying to use World 0 in my other program. Whoops!
* Set BRTC to 127 and REST to 0. This controls brightness values.
* Set BKCOL to 3, meaning to use the brightness timing specified by BRTC.
* Set all flags in DPCTRL. This includes the enable flag and display reset signal. The display isn’t active with this off.
* Set the XPEN flag in XPCTRL. This enables drawing by the VIP, which is required for the clear color to change.
* Idle forever in a loop. Just call HALT over and over.

The ROM itself is attached to this post. Its code is as follows:

; Delay to allow pseudo-RAM to warm up
07000000  20 B0 FF FF  ORI     FFFFh, r0, r1
07000004  3F 44        ADD     -1h, r1
07000006  FE 95        BNE     07000004

; Clear status and disable interrupts
07000008  05 70        LDSR    r0, PSW
0700000A  00 78        SEI

; Set World 31 as the control world
0700000C  20 A0 40 00  MOVEA   0040h, r0, r1 ; END = True
07000010  40 A0 BE 3D  MOVEA   3DBEh, r0, r2 ; r2 = 0x0003DBE0;
07000014  44 50        SHL     4, r2
07000016  22 D4 00 00  ST.H    r1, 0h[r2]

; Set BRTC to 127 and REST to 0
0700001A  20 A0 7F 00  MOVEA   007Fh, r0, r1
0700001E  40 BC 06 00  MOVHI   0006h, r0, r2
07000022  22 D4 28 F8  ST.H    r1, F828h[r2] ; BRTC
07000026  02 D4 2A F8  ST.H    r0, F82Ah[r2] ; REST

; Set BKCOL to 3
0700002A  23 40        MOV     3h, r1
0700002C  22 D4 70 F8  ST.H    r1, F870[r2]  ; BKCOL

; Set DPCTRL to 0x0703: LOCK, SYNCE, RE, DISP, DPRST
07000030  20 A0 03 07  MOVEA   0703h, r0, r1
07000034  22 D4 22 F8  ST.H    r1, F822[r2]  ; DPCTRL

; Set XPCTRL to 0x0002: XPEN
07000038  22 40        MOV     2h, r1
0700003A  22 D4 42 F8  ST.H    r1, F842h[r2] ; XPCTRL

; Idle forever
0700003E  00 68        HALT
07000040  FE 8B        BR      0700003E

The reset handler is fairly uneventful:

FFFFFFF0  20 BC 00 07  MOVHI   0700h, r0, r1 ; main() code is at 0x07000000
FFFFFFF4  01 18        JMP     r1
Attachments:

Okay, I’ve picked through the writes to the VIP control registers. Tomorrow I’ll look into trying these out in an emulator.

VIP_REGS[REST] = 0;

REST is the duration of LED emissions while all three brightness values are disabled. In this case, 0 since you can’t see anything.

VIP_REGS[XPCTRL] = VIP_REGS[XPSTTS] | 2;

Sets XPCTRL.XPEN, which enables VIP drawing. This one’s kinda important.

VIP_REGS[DPCTRL] = VIP_REGS[DPSTTS] | 0x0302;

Sets:
* DPCTRL.LOCK to 1, preventing the VIP from reading the column table every frame
* DPCTRL.SYNCE to 1, indicating that the servo controller should send left and right sync signals to the VIP
* DPCTRL.DISP to 1, enabling the display subsystem. That’s another important one.

VIP_REGS[FRMCYC] = 0;

Specifies the VIP should display 1 image per game frame.

VIP_REGS[INTCLR] = VIP_REGS[INTPND];

Clears all pending VIP interrupt condition flags.

while (!(VIP_REGS[DPSTTS] & 0x3C));  //required?

Waits until the changes to DPCTRL take effect, and neither the left nor right displays are being shown.

Dear lord, it’s full of stars. And just like that, my plans take a sharp turn to the left. (-:

We already have Nintendo’s Virtual Boy Development Manual

Do we now? All I’ve been able to hunt down is David Tucker’s doc. Do you have a link to the official manual?

I am indeed using assembly; manually and with a hex editor no less. I’m in the process of documenting the system internals, since existing information on the Virtual Boy is only some 75% of what the silly thing actually does. To that end, I’ve prepared a system and will be getting a FlashBoy in before long to fill in the rest of the holes in our development docs.

Having said all that, I’m no newcomer to reverse engineering. As part of my documentation efforts, I figure the best sure-fire way to do it right is to start at the very bottom and work up, hence why I’m hand-coding a ROM file for basic output. By the time I’m done, we’ll have a document at our disposal that looks something like this.

Thanks for the tip about the component registers. I’ll look into those and see if I can get the displays to provide more useful output. (-: