Architecture of the Playstation
copetti.org
copetti.org
To us the elephant in the room limitation of PS1 is not mentioned here as far as I could tell from a quick read-through: it had no Z-buffer. This meant that you either had to do heroic pre-computation (sort polygons ahead of time) or you ended up with lots of flickering polygons (bluedino's "jiggling and sparkling" comment below seems apt).
The other thing to note is that to make a truly high-performance game for PS1 you had to completely ditch Sony's sanctioned C APIs -- something they said would cause your game to get banned, but which we did anyway. Sony's libraries spent more time copying registers to and from the stack than they did doing the actual work, so they were a big lose.
Finally, that 2KB scratchpad was immensely powerful if you used it well. It's the only reason the 3D collision detection on Crash was fast enough; it took me 9 months to get that performant enough to ship. The CPU and RAM in those machines were just incredibly slow by today's standards.
I notice another game today on here using ClojureScript. Apart from a lack of tooling / engine, is Lisp better suited for gamedev?
It was very powerful to be able to write code for critters and other animated objects in GOOL/GOAL because it was both conceptually simple and compiled into tiny amounts of code, which mattered a lot when you only had 2MB of RAM (half of which was video RAM if I recall correctly).
https://blog.jakspeedruns.com/opengoal-project-update-septem...
GOOL: https://all-things-andy-gavin.com/2011/03/12/making-crash-ba...
GOAL: https://en.m.wikipedia.org/wiki/Game_Oriented_Assembly_Lisp
If you were using the GNU assembler, it automatically fills branch delay slots with nop instructions unless you prefix assembly code as using `.set noreorder`. GAS would also handle load delay slots as well.
We used gcc on a MIPS M4K in a communication chip. We had a lot of existing C code and were short on ROM and on CPU cycles. Therefore a few co-workers wrote a tool which parsed the gcc asm output to fill the branch delay slot with an instruction with no side effects on the branch. It also fixed some gcc issue with 16 bit memory accesses in C were created as 32 bit load instruction in asm (which can be two cycles if the first 16 bit of a 32 bit word are needed). I had a HW/SW cosim setup to test code and hardware (Verilog). These were cool projects. Good memories (although quite vague now).
PS: If we would have had a license of the Green Hills compiler we could have saved some of the effort. IIRC it did branch delay slot optimization.
> Moving on, the ordering table puts the burden on the developer/program to show the geometry in the right order. In some cases, the calculations implemented rely on too many approximations to gain performance. This may result in flickering or occluded surfaces that should have been displayed.
> This meant that you either had to do heroic pre-computation (sort polygons ahead of time)
Much more detail on this is available in this amazing series of blog posts:
https://all-things-andy-gavin.com/2011/02/02/making-crash-ba...
I remember sitting in a meeting with our technical contact at Sony's headquarters in San Mateo where he basically asked without asking if we were using the C libraries. From the way he asked the question it was clear that the correct answer was "No, not using the libraries" since otherwise our game wouldn't be performant. At the same time we both knew we couldn't say that explicitly since that would violate Sony's contracts.
Well of course you were using the libraries! Just like you were using the documentation. Exactly like you were using the documentation, in fact. The fact that neither got jumped to as executable code is clearly immaterial.
How often did the polygons get out of order?
(Or am I thinking only in 2D arrays when the problem is really multiple-polygon occlusion?)
However, the way I did it was to precompute the sort order of the polygons ahead of time and store periodic key frames (the complete sorted list) along with diffs. These diffs were generally very small, meaning your intuition that not much changes from frame to frame is a valid one. The problem is without the runtime oracle telling you which polygons move from frame to frame, it seems hard to exploit this property.
Another issue with approximate polygon sorting methods like bucket sorting is that the sort isn't terribly stable from frame to frame, so you get the annoying flickering effect that you see so often in PS1 games, as a pair of polygons alternates between relative sort order as you move around.
Fascinating! Was this because Sony didn't bother checking, or they saw the performance you were getting and just let it slide?
The problem was there was just no way to make a fast C API for things like polygon rendering, because as soon as you touched RAM (the stack) you were looking at many cycles of delay per instruction.
https://youtu.be/Qo-wX5CeDRA?t=340
So it most likely wasn't Blasto.
There is a section "Visibility Approach" under the GPU section that starts: "Just like the competition, the PS1 doesn’t include any hardware feature that solves the visibility problem."
I agree that it doesn't really stress the ramifications of that.
I have a few questions, interspersed with my musings on them.
Based on an initial misreading of the above as the RAM being slow, I mistook your statement to mean that memory latency on a similar order to today's computers was something that you had to fight with. Was it memory latency per-se that made achieving sufficient performance hard?
Per the article, the system had EDO memory, which I discover can deliver a word read in 3 cycles for the first word of a page, and two cycles for subsequent words in the same page -- or 1 cycle for all if it is fast enough. I don't know the details of a MIPS memory access cycle, but by comparison, the 68k takes at least 4 clock cycles to pull a word off the bus. Thus, ISTM that EDO memory could keep a 68k fully supplied with data without resorting to wait states. I would hope that a MIPS processor, being a more modern design, could pull a word off the bus in a singe clock cycle, but on the other hand, I could see Sony possibly using cheaper chips with a tRAC slower than the CPUs clock period to save money.
Or, was the issue less so memory latency per-se, and more a bus utilization problem? In the article, I see that the DMA controller leaves the CPU idle while other devices are using the bus unless the CPU is making use of the scratchpad.
Re-reading your statement, that the CPU and RAM were just slow in general compared to today, I find myself wondering, how did the power of your development workstations compare to the PS1? Were you guys using high-end workstations like NeXT or SGIs, or common PCs of the era, since per the article, the SDK and development board targeted Windows 3.1 and 95?
It was admittedly nearly 30 years ago but my recollection is that the only way to make anything fast on that hardware was to keep everything in registers and avoid touching memory except when absolutely necessary. It was definitely many cycles to access memory.
A Pentium Pro could run Unreal, I think. That game (and engine) basically could crush down any PSX and N64 at once.
A Pentium 2 could emulate the PSX at lowest settings.
- A year ago, an old version of this article got shared in hn (https://news.ycombinator.com/item?id=22932134) and since then, google started positioning my site in their search results, and many forums started noticing the site. Yay!
- Fast forward, I graduated from uni, continued working on more articles in my free time, and with all the newly acquired knowledge, I decided to re-write the old PS1 article to make it much more informational and accurate - This is the one you are seeing right now.
- The rewrite wasn’t easy, though. Luckily, I found very kind and talented experts that lent me a hand, you can see them credited in the ‘Changelog’ at the end of the article. Curiously enough, we are still debating on Discord about some discrepancies regarding the main diagram shown in the article. LSI’s docs (the CPU manufacturer) and Sony’s docs contradict each other when they explain the layout of the CPU’s ‘main’ bus! But don’t worry about it, it doesn’t affect any statement in the article. It’s more of a need to have everything as accurate as possible.
Finally, I’m always open to comments, improvements, suggestions, anything really! I share the writings here (https://github.com/flipacholas/Architecture-of-consoles) to discuss improvements but you can also find my email in the site.
PS: The insight shared by developers in the parent thread is phenomenal.
Maybe early CD-ROM drives couldn't read the side-channel data, but all drives (readers and burners) after a certain generation can read raw 2448 byte (2352 byte raw sector data + 96 byte subchannel data) sectors. I think Plextor drives might have been the first to support it?
> 5-stage pipeline: Up to five instructions can be executed simultaneously
Although technically correct, that's a bit misleading IMO. The instruction execution is overlapping, but you can still execute at most 1 instruction per cycle (each stage of the pipeline can only execute one instruction at a time). You need a super-scalar pipeline design to do more than 1 instruction per cycle.
I Agree. My issue is that the other consoles also have a pipelined CPU and I'm trying not to copy-paste the same long explanation from other articles every time. So I included a link next to the PS1's pipeline description. I will try to reword it though. Thanks!
One of the hacks we created was a limited pre-emptive multi-tasking system on the original Playstation to run our physics engine at a constant frequency. We'd asked Sony US who escalated to Sony Japan and told us it couldn't be done and we should write our code in a cooperative multi-tasking style.
We eventually figured out how to use the vertical blank interrupt to save all the registers, modify the return address to return from the interrupt to our physics code, then our physics code would run (not in the interrupt context), then restore the registers and longjmp back to the main game code which had been originally interrupted by the vertical blank interrupt.
This wasn't general-purpose pre-emption and had only fixed divisors of the screen refresh rate available, but was enough to get our physics engine to run close to isochronously.
Side note 1: our game (NASCAR Racing) was comparatively terrible and I remember being in awe of what the Crash Bandicoot, Ridge Racer, and other early PSX teams accomplished in gameplay and graphics.
Side note 2: as unconventional as the PSX was, it was positively mainstream compared to its contemporary Sega Saturn.
So that's really like, half preemptive with the return side really being cooperative style?
The physics thread (with interleaved joystick read code on PC) did have to yield back to the main/graphics thread. That was no issue in our case; I've not thought deeply about it, but it seems like the method is likely extensible to do context switches among multiple [unaware/non-cooperating] threads.
It's interesting that you were able to adapt this technique to PS1 hardware; does that game run properly under emulators or does it give them fits?
I don't know if the game runs on emulators, but I know it runs correctly on a mid-generation PS3 and I'd expect that VBlank interrupt handling would be implemented by an emulator, so I'd expect it should work.
PS: Massive, massive respect for you and the rest of the Crash team. When that game came out, we couldn't comprehend how you were able to pull off that game on the same hardware we were using. Much respect (and thanks for the great gaming memories)!
The TMPR5900 (the MIPS chip developed by Toshiba to power the PS2) was sufficiently complex to develop that we developed a cycle-accurate simulator so Sony (and a few game developers) could start development before hardware was available.
However emulation isn't always the best approach: the PS2 (at least the first edition) implemented back compatibility by simply including a PS1 on board. That's a kind of Moore's law in that the cost of doing so had dropped so much since the original PS introduction that it was worth it.
I noticed this at a friend house, while looking for something in the garage we came across his old system and games. We could not resist taking it back into the house and setting it up.
The first thing I noticed was how long the load times were. And how noisy the machine was when reading and seeking on the discs.
The next thing was the primitive texture mapping. Polygons 'jiggling' and 'sparkling' all over the place. It reminded me of my first attempts at programming 3D graphics in VGA, before realizing what floating point (or fixed point) could do.
We tried re-living some of the classics, and after not even an hour we just shook our heads and went back to what we were originally doing.
The shimmer and dithering are not really noticeable on CRTs. Maaaybe if you had a really fancy Trinitron or another of the last-generation ultrasharp flat screen CRT TVs, it would be noticeable, but those weren't mainstream until pretty comfortably into the PS2+ era.
Granted, I was a kid then. If you were a professional artist or something in the 90s, I'm sure you noticed.
That said, as much as I love playing old games on a CRT, I'm in a PAL region, and in today's world of high-refresh rate screens 50Hz is nausea inducing.
There is no such thing as CD distortion. Does that make the whole opinion invalid?
Or is it that it isn't a problem of PS1 but a problem of games - which, again sure, this might be true but that'd be the splittiest of hair splitting :-P it is the lack of a hardware feature that drove the games do what they do, so it isn't entirely "blameless".
Yes, this is what I wanted to emphasize.
My intent wasn't to say that the 'lack of z-buffering' statement was incorrect (it's still true), but that there's a fundamental issue behind it, the visible/hidden surface determination, and now it depends on the developer's implementation. I believe this is overlooked on non-technical sites.
With this, I just wanted to make it more informative for the reader. I don't think the question is if the PS1 has a z-buffer or not. Sure, z-buffering is a solution, but there's the reasoning behind it that I wanted to transmit it to the reader.
Anyway, that's just my opinion.
However i think the combination of lack of z-buffer, affine texturing and RGB color output with dithering was kinda unique - or at least very rarely seen elsewhere. You could see several z-buffer-less and affine-only texture mapped games on software rendered PC games, but pretty much all of them were using 8bit palettized modes. Some also used dithering (e.g. Ultima Underworld) though it was very rare.
By the time there were a few games that used RGB colors and software rendering (e.g. Unreal, Heretic 2), PCs were also powerful enough to do perspective correct texturing.
The N64 has it’s own set of graphical limitations, but hold up a bit better to the test of time, IMO. At the time I know it was the school yard debate of which looked better and many felt the sharpness of the PS1 was preferred over the softer N64 image.
Most games didn't aged well, however some of them are still impressive today considering the limitations:
- Chrono Cross: almost no loading times after the initial one.
- Crash Bandicoot: the graphics are still very charming, and there is almost no graphics 'jigling'.
- Valkyrie Profile: one of my favorite RPGs of all the time, and thanks to its 2D graphics and huge sprites it is still very good looking even today.
- Tekken 3: Very detailed character models and I think it runs at 60 FPS? Even if it doesn't, it is still impressive.
It does, at least on NTSC. On the PlayStation Mini or whatever they called it, they packed a 50FPS PAL version of the game - and as near as I ever figured out, it was because the MT chip inside of it couldn't emulate Tekken 3 at 60FPS.
The first system that I feel like had enough power to be a 3D system without being completely terrible was the Dreamcast. It had enough power that you could target 60fps and even if you missed it, get close enough, and have enough power to draw recognizable environments and make things that could at least hide the fact they weren't made out of huge polygons, with a bit of artistry. It wasn't near obligatory to spend multiple refreshes' worth of time on a single frame to put up a competitive-looking frame. I played quite a few games on that and it was rare to see slideshows. All the 3D I've played prior to that still feels clunky to me, but playing the Dreamcast feels primitive, but workable.
The Dreamcast was probably the first system I played where a 3D game looked just as it did in the arcade.
Here's the first track in Ridge Racer Type 4, for example, which looks so much nicer without the track and wall textures wobbling about:
https://www.youtube.com/watch?v=BDJpmP9jfeA&t=204s
Edit: the original version, for comparison:
Developers were:
1. grappling with an entirely new dimension of gameplay
2. investing enormous amounts of engineering work into making 3D world run at all on these systems
And it seems to me that the result was that gameplay the gameplay for this generation at least for action-oriented titles, generally was a big step back from the 16-bit era.
There are certainly some early 3D action titles that still shine for me though. The PSX-based entries in the Tekken series and Metal Gear Solid come to mind.
I regularly use my PlayStation instead of my PlayStation 2 for playing PS1 games, it appears to me that the video output on the PS2 while playing PS1 games is of a lower fidelity (while using an SCART lead), the output is always off centre on the PS2. I assume it’s something to do with the hardware differences in the video output between the two?
https://www.gamasutra.com/blogs/DaveBaggett/20131031/203788/...
It looks like the author, Rodrigo, has done similar articles for a bunch of other consoles which is incredible.
I think by modern standards though it’s very evident in most games, with the draw distance being so low.
The PS was a specialized machine though. Don’t discount either the benefits of developing and optimizing for a single set of known hardware, rather than a wide wide array of PC hardware.
The Last of Us for the PS3 never fails to leave in awe, Naughty Dog did some serious black magic to get those results out of the hardware they were targeting.
It's really amazing how much can be done when talented developers target specific hardware.
Max Payne ran on a PIII @1GHZ with 128 of RAM (not a bg step over 88MB considering W98SE could use about 32MB) and the graphics were on par to Mario Galaxy if not better.
>The Last of Us for the PS3 never fails to leave in awe, Naughty Dog did some serious black magic to get those results out of the hardware they were targeting.
It's really amazing how much can be done when talented developers target specific hardware.
Textures, textures, textures. Max Payne had amazing textures, so did most console games from Konami and such. Yet, a lot of UE1 based games had so blurry-ish and shitty textures they indeed look worse than a Game Cube game.
I am not talking about the texture size, but the quality of the artwork.
There was a port to the original Xbox, which had only 64 MB of RAM!
Is something like that feasible for 5th Gen systems like the Playstation or have we crossed a threshold of complexity where if you want cycle accurate hardware, it's time to pony up the money to license the IC data from Sony and to have custom chips manufactured?
I'm not a web dev though, so I don't mind switching to a better pattern. Do you know a better one?
I think the difficulty for some readers (myself included) is that they are non-standard/different from how every other web page works.
I actually quite liked them, kind of like an extended aside.
I will find it when I get home and reply to this comment.
Would rather just have a table of contents with items and sub-items.