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. (-: