Video summary
The video documents an in-depth reverse engineering project centered on a very cheap NES/Famicom clone handheld purchased from AliExpress, which appears to be based on the VT369 chip and marketed as a phone case. After acquiring the device for five Swiss Franks, the creator opened it up to reveal an internal microcontroller with built-in ROM that initializes hardware and manages emulation via SPI flash storage containing titles like *Super Mario Bros.* and *Contra*. Initial attempts to dump the firmware using clip-on readers failed due to signal interference at high speeds of 90 MHz; consequently, successful extraction required desoldering the chip and soldering it into a socket. Despite physical challenges such as broken screens and poor contact points that necessitated hot glue fixes, the analysis confirmed the device runs an emulator rather than pure software on external ROMs, though full reverse engineering was hindered by inaccessible internal memory and proprietary extensions for graphics and audio handling.
To overcome signal interference issues during data capture, the creator employed a unique method involving an old smartphone to record screen brightness changes while processing raw analog data with `ffmpeg` to extract individual frame values as binary signals resembling Morse code pulses. This approach initially yielded noisy results due to automatic brightness control and low resolution but was resolved by re-recording at 60 frames per second with auto-brightness disabled, resulting in a clean signal that decoded into valid machine code after manual corrections for missed transitions. Further analysis of the dumped ROM revealed startup vectors, SPI flash initialization routines, and evidence of multiple memory-mapped peripherals, including an internal boot ROM, an external EPROM likely used for configuration or copy protection, and a serial peripheral accessed via custom commands rather than standard I²C protocols.
Although identifying Mapper 427 as the likely hardware mapping, the creator encountered significant hurdles when attempting to run the extracted images in emulators like Nintendoo or MAME due to incorrect register states, infinite loops from missing interrupt handlers, and mismatched hardware behavior that prevented full emulation without deeper research into Windows support. Despite failing to achieve a perfect software simulation of the device, the project successfully resulted in the extraction of all four ROM images: main flash, internal boot code, serial protection chip data, and EPROM contents. The creator concluded that while complete emulation was unlikely without further hardware investigation, they planned to upload these dumped files to community archives for others' use and intended to retrofit a working unit into a custom console in future projects not shown on camera.
Read the full video transcript
I have a new phone case which is also a
NEZ.
So, let's pull it apart and see what
makes it tick.
What this is is a cheap and nasty
NEZ/Famcom clone. It's probably based
around a similar NEZ on a chip device as
this thing here, which I've played with
here before. After Nintendo's patents in
the original NEZ ran out, everyone and
their pet dogs started producing NEZ
implementations on a single chip that
sold for very little money and were more
or less compatible with the original
NEZ. These things were available for
almost nothing. I think this cost me
five Swiss Franks from AliExpress
and they are ubiquitous. If I turn it
on, anyone who's played with one of
these before will probably get
flashbacks from the music.
>> [music]
>> Yeah, enough of that. If I then select
English, you can see that what's on it
is a million different
we go. A million different ROMs. They're
either straight copies, ROM hacks,
ripped off public domain stuff, you
know, most of them run. Some of them
don't run very well. The compatibility
of these things is not great. It's okay
for what it is, which is a very cheap
handheld games console with miserable
controls.
But if you want to play
Mario 14, for example,
this is where you go to get one of
these. Now, I'm expecting this to be
extremely similar. However,
I learned of these from James channel,
and he took the lid off one, and there's
a feature inside that I am very
interested in. So, let's just have a
quick look at it. You can see in here
that this is clearly a very different
firmware package than on the sub. If I
select English, here is the main menu,
which again is quite different. These
are all the usual collection of totally
legal licensed ROMs. What I don't see
are the ROM hacks, which are
interesting. There are fewer of them. I
think there's only 30 odd. Yeah, there's
only three pages.
and
they are displayed in this interesting
colorful title screen that I am not sure
that the stock NEZ is capable of
displaying which is rather interesting.
The games are of course if I start one
there we go the usual NEZ games
and they run okay.
I'm not experienced enough with the NEZ
to know if this is running at the right
speed or sounds right.
All I know is there's a mushroom there.
Sometimes I can reach the end of the
first level. It's either clearly
emulating the NES or it's got a Noak on
board. And I suspect it's got a NOAK
because that's the cheapest way to do
it. If it was emulating, it would need a
much more powerful microcontroller
and you know that costs money.
So, let's spudge this thing open. If I
can figure out how to open it and see
how it works inside.
Maybe I should turn this off first.
There we go.
Huh. So, that was in fact glued
together, but luckily it was really bad
glue. So, what's inside our cheap Fami
clone? Well, we've got the loudspeaker.
We've got the USB connector providing
power and only power. There's only a red
and black wire coming from there. We've
got a battery with a battery protection
circuit, which is nice. We have a PCB
and we have the screen. We also have 324
Ultra written on the board here, which
could be a model name. Let's take the
PCB off and see what there is to see.
It's screwed together with a whole three
screws. There's a hole here, but there
doesn't seem to be a post underneath it
for a screw.
And I need to take the screen out as
well. Oh, that's fun. The screen has
been plastic welded into place. I wonder
if I can get that off without breaking
it. Someone's been pretty rough with
this thing.
Okay. Well, I don't want to risk
breaking the screen at this point. So,
let's lift up the rest of the works.
Start by removing the USB thing,
revealing absolutely nothing of any
interest. So now we should be able to
lift the speaker out of the way, which I
think has actually fallen into two
pieces. Is this bit glued down?
Yes. I don't think that's really very
good. Here's a piece of 3M tape that's
just sort of Oh, it's double-sided
sticky tape, but they haven't peeled the
backing off.
Wow,
that's a choice.
Okay, can we get the battery off? This
is probably glued down, but I probably
also don't want to puncture it. Yeah,
that's easy.
Okay, so now I can flip the board and
see what there is.
Oh, good. This is exactly what I was
expecting. It's a simple PCB based
around this epoxy blob. This will
contain all the intelligence of the
device. It'll either be a NOAC, a NEZ on
a chip if this is using a NOAC, or
something else. if this is using
something else. These two 8pin chips,
this one is bigger and there is a label
on it, but I can't quite make it out
from where I am. So, this is probably an
SPI flash chip containing all the
software. And this is
something else. Power controller maybe.
Here we've got all the various buttons.
These things will push down on them,
short out the two pads, and that's how
the thing knows the button is pressed.
And if you look over here, there's an
unpopulated USB socket. If this PCB is
close enough to the edge of the case,
then they can just stick a USB socket
here and not need the little
daughterboard.
So, if I put this down here and press
The power LED comes on, the screen
backlight comes on, and the speaker
makes some very nasty scratchy sound.
Yeah, I think that metal thing was
actually part of it.
Anyone who's seen my Tony games console
video is probably going to guess what
comes next.
This is a flash chip. Let's dump it and
see what's on it. Now, the first thing
I'm going to try is this clip. I've
never had good luck with these. What
these are for is you clip them to the
chip when they're on the board, like
that, and then they let you read or
write the chip without desoldering it.
I've never been able to make these work.
The problem is that when the chip reader
powers the chip to read or write it, it
also ends up powering the
microcontroller and the microcontroller
of course immediately starts talking to
the chip and that interferes with all
the signals.
But let's give it a try and see what
happens. I might be lucky and it would
be really convenient if I were. Now I
know that this thing is a windbond 25Q16
which Mini Pro knows about. So, I should
be able to do this. And
okay, well, it's reading, which is a
good thing,
but that's not a good thing. I think
that we're getting a bad read here. It
is interesting. It seemed to get the
device and serial.
Okay. What's in the ROM?
Nothing. Yep, that hasn't worked.
Fantastic. I'm going to have to remove
the thing from the board.
Here it is on the carrier board. So, we
now uh drop it into the chip reader the
right way round.
And hopefully this will now work.
Okay, what do we get?
Right, it has correctly read the chip
ID. See here it got zero. Here it got
the right value. So I think we are now
actually getting real data.
And what do we get when we look in it?
Stuff.
What kind of stuff?
Well, I see lots of zeros. And I see
what look like jump tables or something
like. So I don't think this is
encrypted.
Let's just run strings on it and see
what comes out.
Garbage. Garbage. Lots of garbage.
There we go.
Alpha, beta, gamma, delta, epsilon,
theta, ea, theta, iota. These are this
is the Greek alphabet.
It is an unencrypted ROM. Excellent. The
next thing to do is to run it through
CPU wreck to try and recognize any
machine code that happened to be in the
thing. Now, since it's a NEZ, I expect
it to find lots of 602 code, but it
might find something else.
Right.
That's not impressive. It's found six
bytes of 6502 code. Right. This
This is garbage.
So, the NEZ boots weirdly. If this is a
real NEZ
emulation,
I would expect it to start with reset
vectors, which would be somewhere up
here, but there is nothing. If it's a
different architecture, then CPU rag
doesn't know about it. We did see plain
text strings, so it doesn't seem to be
encrypted.
I wonder if this is hooked up by an SPI
bridge. The bridge knows whether the
actual CPU is reading code or data.
Could it be encrypting the code reads
but not the data reads? That would
explain what we're seeing. That gives us
like here this is a structured table
014D 014 014F etc. So that's clearly not
encrypted. But the actual code part
assuming this is code is all wrong.
Well, I could try and figure it out by
static analysis, but it'd be so much
easier to just hook it up to the signal
analyzer
and see what it's actually doing.
As you can hear, not quite right.
If I reset it,
it runs fine for a bit and then
glitches out.
So, what I think is happening here is
that my wires are too long and I'm
hitting various capacitance issues.
That's fine. I can always shorten stuff.
And it runs for a little bit. So, it's
is at least getting to the bootup
sequence, which is good. Let me just
reassemble this so I can see the screen.
Now, it's not working at all.
I suspect something's shorting out here
where all the wires are bunched
together.
Or then again, possibly not.
The thing is, I shortened these wires in
the hope that it would work a bit
better. It doesn't. it works worse.
If I try to reset it, there is a faint
click from the speaker and nothing
happened. So, I immediately went to my
oscilloscope to see what I could see.
And not only could I see things, I saw
them happening at 90 MHz. That's really
fast for an SPI chip. Not only is it
really fast, it's really out of my
comfort zone when it comes to
electronics. And I don't think this
horrible bundle of wires is going to cut
it here. I think this is going to need
short traces.
So, I'm going to have to change my plan
slightly. I'm going to solder this thing
on, which is a ze socket attached to a
soic 8 adapter.
I've used these before. They've never
really worked very well. Turns out the
cheap PCBs don't really like have
anything this size hanging off them. So,
I'm going to also have to apply lots of
hot glue to hold it on. I'm not going to
be able to put this thing back together
and I probably won't be able to make it
so that I can see the screen, but I do
want to actually get the thing running
because this is going to need rather
more serious signal analysis than I
thought I was going to need. I don't
even know if my signal analyzer goes up
to 90 MHz. I was expecting, you know, 8
16
Well, here it is after some very fiddly
soldering that I couldn't do on camera.
So, we insert this thing like this. I
haven't done any of the hot glue yet.
I want to see if it works first.
Yeah, I don't like doing that.
Okay. And
power. Nothing has happened yet. Now,
let's try the on button,
which is here.
I said it's here.
Okay. Have I got the power wrong
somehow?
Wire has fallen out on the power supply.
There we go.
Oh, that's interesting.
That wanted to draw more than 150
milliamps.
That suggests it's trying to turn the
light on, which is good. Why didn't it
hit that limit before?
I do know that this carrier works
because I managed to read the chip. So,
at this point, the possibilities are
I've broken it or I've broken the chip
or the signaling between the chip and
the board is simply not working right. I
fired up the oscilloscope and that is
showing something rather interesting,
which is
if I check the power line on the flash
chip,
that little bump is all that's happening
on the flash chip. It's not powering up
the flash chip. One thing I found which
is exceptionally weird is if I do a
continuity test of these two pins.
This is power to the flash chip.
I think I've shorted something together
on the board. Either that or I fried the
power controller chip.
And look here. Here are two components
that appear to have dripped solder on.
Let's clean those up a bit. and then see
if anything's changed.
So, I just spread the solder around a
bit and what do we get?
Nothing.
Okay, I think that could well have been
the problem. So,
I shall carefully stick the flash chip
back in.
This thing needs rather more force than
I'm comfortable with.
It's a ze socket. It's not supposed to
use force. Okay, it's the right way up.
3.8 volt to the battery terminal
and hit the onoff button.
Oh, red light. Ah,
I mean the speaker is not making any
horrible sounds. Let's try reset.
Nothing.
Ah, maybe I should reconnect this wire.
Nasty scratchy sound. And it's not
glitching out. Okay, the board is
running, which is nice. I haven't broken
it. I really ought to start ordering two
of these things.
So, now I have it working. All I need to
do now is figure out how to capture the
SBI signals to the flash chip.
So, this might be harder than it looks.
Let's take a look under the scope. In
QSBI mode, this pin is the clock signal,
which indicates the highest resolution
we need to capture.
That is registering
8.5 MHz. That's not the 90 I was getting
before.
I wonder if this is working quite right.
If I zoom in on one of these fast bits,
does the signal change?
Okay. Yeah. Now it's registering 90 MHz.
So I think that previously
like this
it's seeing those big dips as
the frequency it's supposed to count.
So I think that each one of those dips
represents a single SPI command as it's
reading bytes from the chip. And you can
see that it's all structured very nearly
the same.
So I think it's just reading a single
bite at a time, which is very
characteristic of an SPI bridge.
So now I need something that can capture
90 MHz signals.
Given that my trusty clone signal
analyzer has got 24 megahertz written on
the front, I don't think this is going
to cut it.
This setup deeply offends me. I'm going
to have to build a jig. To do that, I
need to take the screen out. Now, this
side has already popped due to my
general mishandling, so it may come out
reasonably cleanly. That was a nasty
noise.
It's a very bad screen.
Okay, that bit's come out.
I think.
All right.
So, now at least I can place it where
the screen is visible.
Let's try some power and go through the
rather complicated startup process. I
don't think it likes having the battery
repeatedly disconnected.
So, it does this for a while.
Doing various combinations of reset does
help.
There we go. And oh, good. The screen is
working. So now I should be able to
attach it to some kind of test jig where
everything is just a little bit more,
you know,
more than stray component on my
workbench.
And here is the finished test jig. It is
largely made out of wishful thinking and
hot glue, but it does actually work. I
discovered a bunch of stuff about things
such as the fact that there's a huge
inrush current when it starts up and the
lithium battery could provide that, but
my power supply can't. On startup, the
voltage would drop just for a moment,
but that would be enough to cause the
battery controller chip to cut the
power, thus causing it to boot loop. So,
a big capacitor solved that.
This thing is 3D printed and made out of
some Cherry clone key switches and key
caps I had lying around from another
project. It's actually pretty nice to
use, although Nintendo games don't tend
to react well if you press both left and
right or up and down at the same time,
which normally can't happen because of
the D-pad. But, it does all work with
one minor proviso. Let's see if you can
spot it.
Yes, I got careless and broke the
screen. More fragile than I thought.
This doesn't really matter. I'm not
going to use the screen for anything.
All I need to know is that it works,
which it does. So I can select Super
Mario Brothers, start it playing and you
can actually see and hear on the
remaining bits of screen that it is all
present and working.
I'm not very good at Super Mario
Brothers. I can replace the screen
possibly with the one from the other
Nintendo clone that I've got, which I'm
also never going to actually play games
on and is much less hackable than this
one. The other one uses a parallel ROM
rather than the serial flash chip here.
Or maybe I can just order one off
AliExpress. Well, I'm going to deal with
that later. For now, it's working well
enough for my purposes. So, all I need
to do now is to turn that thing off.
is to hook up a signal analyzer and
capture all the traffic to the flash
chip when it starts up. And as this
thing runs at 90 MHz, I need to capture
at least 180 million samples per second,
which is a pretty tall order.
So, I'm going to have to seek outside
help.
So, here I am in a maker space with a
seriously expensive Sala A Logic Pro 16
capable of doing 500 million samples per
second. One end is plugged into my
device and the other end is plugged into
my laptop. So, all I need to do is go
over here and hit the start button like
so and hit the power button like so.
The light comes on
and the data comes in. You'll notice the
screen hasn't come on and it's not
making nasty noises. That is
unfortunately because the logic analyzer
itself is corrupting the signal. This is
like 90 megahertz. It's a pain to deal
with. But I don't need that much data.
So I'm just going to do multiple reads
and hope that the bits I need will be
uncorrupted. So, I'm just going to keep
doing multiple captures, and when I get
about 10 or so,
go home, I suppose.
Here I am at a desk with a mouse and a
real microphone. And let's see what we
can see. Here I have the capture, or
rather a segment of it. I've top and
tailed it so it's not dealing with like
3 GB of data. And you can clearly see
that we power on then there's a blip as
it does something then there's a pause
and then it goes completely ham on the
flash chip. So I suspect that this is
initialization and this is when it
starts executing code directly from the
flash. So I have already hooked up the
various analyzers.
So, let's zoom in on here.
And
down the bottom here is the SPI clock.
By default, every time the clock line
goes up, the device will sample the
master out slave in line, which is this
one.
And eight clocks gives us eight bits and
a bite. And it has in fact transferred
06 which is the write enable command.
And yes these all look like actual
commands. So you got write enable. FF is
not understood by this tool but it is in
the data sheet which I've got here.
Exit QPI mode. This was just part of
resetting the flash chip. We read a
status register.
So here you can see eight clocks some
traffic from the device to the chip
that's sending the command and then here
the chip replies with some data. So
status register contains two. So that
seems to be a fairly normal startup
procedure.
Then it does some stuff I don't really
understand. It looks like it's sending
commands to the flash chip. But
the way the computer tells the flash
chip a command's coming is by dropping
this line, which is the chip select or
enable line. So you can see that each of
these commands here, it drops chip
select, does the command, raises it
again. So these are just going to be
ignored by the flash chip. So I don't
understand what's going on there at all.
But then there's a long gap and then
some more stuff happens.
And here here is where it gets
interesting. Yes, I have had a look at
this before so I know what it's doing.
We send the E7 command. 1 2 3 4 5 6 7 8
clocks. E7 is again not understood by
this tool but it in the data sheet. And
it is interesting because it is
E7 write word read quad IO. This is the
QSPI read command that's doing all the
heavy lifting. If you look at this
diagram,
it sends the 8 bits of the command using
normal SPI stuff. Then it uses QSBI mode
to send 32 bits of addressing
information
and then it starts streaming data back
from the device. Because there are four
lines once it's in QSPI mode every clock
transfers four bits that is a nibble and
things are arranged so that we can just
read off the address.
This line here is the QSPI value being
transferred. So what's happening is it
sends the command.
It then does
16 clocks, eight clocks, eight clocks
transferring the address. Then there's a
pause where the computer that's
controlling all this sends two clocks
and nothing happens and then it starts
reading data. every two clocks transfers
a bite. So the address that it's sending
is
0 0 0
A5.
If you look at the data sheet, there are
in fact only 24 bits of address. The
bottom eight bits are flags, therefore
not part of the address. So, the actual
address being read is 000000.
Reasonable enough. Okay. Send the flags
A5, which I'll get to later. Then there
are two dummy clocks.
And then the flash chip replies with 3 6
5
9.
So, it is reading from address zero. Is
it? Well, let's go over here to the hex
dump. And if we go to address zero, you
can see 3 65 9. We have successfully
figured out that this is reading from
the flash, which is is good.
Okay, those flag bits A5.
Now, according to the data sheet, the
bottom four bits are ignored. In the top
four bits, if they are set to
ignored, ignored 1 Z, then we enter fast
read quad IO mode. What this is for is
to allow data to be read much more
quickly from the device. After the
current command is finished, chip select
goes high,
then it remembers that it's in this
mode. When chip select goes low again,
you don't have to transfer the command,
which is of course 8:00. You can just
get started directly transferring the
address in in QSBI, which only takes,
you know, 8:00.
So, you eliminate 8 clocks worth of
overhead entirely.
So, here we should be seeing another
read. I actually think it's lost clock
there because that should be another
zero anyway. Uh, I think the address is
000 1 A12.
Then we've got A5 as as flag byes 55 as
dummy and then we get
C F09
and then chip select goes high meaning
the end of a read. So the address is
1 A12.
So if we go to A12
here we can see
CFO9
CFO
9 chip select goes high chip select goes
low and then we do another read. So I
think I am successfully decoding the
reads. And if we zoom out a little, you
can see lots of reads one after the
other as fast as possible. And it just
keeps doing this forever.
In fact, something is going wrong
somewhere
because the device is crashing,
which is why when the signal analyzer
was hooked up, we weren't getting any
music. That'll be because 90 megahertz
signaling is kind of touchy and having
the signal analyzer attached is
interfering with something, you know,
like this clock not showing up.
But I think I now have enough
information to write a little program
that scans the dump and figures out the
addresses in the flash that it is
reading from.
Well, here is my program which decodes
the reads from the logic analyzer
capture. And because the capture is
complete garbage, it's full of dropped
clocks like there.
I can't trust any of the data that the
capture has produced. So I just pulled
the bytes out of the ROM dump. And here
are the results. And I am very confused
cuz this is not machine code. It's
reading pairs of bytes
which all follow the same format. A
slowly increasing low number and a more
or less constant large number into lead
with occasional reads from somewhere
else.
And this just keeps going.
I think this is the audio streaming or
at least it's trying to do audio
streaming. these other things. Well,
15A, if I
go to 15A,
there's this big block of high entropy
stuff at the beginning of the ROM. And
this is where I would expect to find,
you know, startup code. And it's reading
some stuff from there, but the patterns
don't really match machine code either.
What I was hoping to see was clear
patterns of this thing running programs
from machine code and then I would be
able to see things like function calls
and determine where it's returning from
a function and I know that has to be an
RTS instruction. So that would give me a
handle as to decoding whatever they've
done to the 2 machine code from this. So
I don't really know what's going on
here.
I wonder if there's a onboard ROM inside
the blob that's doing a lot of the work.
Maybe this is in fact an emulator and
this is running a high-speed
microcontroller and when the
microcontroller runs the NEZ programs,
it, you know, emulates it in software.
But yeah, I'm going to have to tackle
this in a different way.
So, this is interesting. You're looking
at my power supply which is currently
turned on and showing the current draw.
Currently zero. If I turn it on,
current draw goes up to about 90
milliamps. Now, if I select a game,
it goes up to 120 milliamps. This is
suggesting to me that this thing is
running an emulator and that when it's
displaying the title screen, it's mostly
idling and so is using less current. But
when it starts the game, then whatever
microcontroller is in this thing is
running flat out emulating a NEZ, hence
why it's using more current, which is
kind of surprising to me because if this
was an emulator, I would expect there to
be a external ROM with the software on
it.
this relatively slow initialization of
the SPI flash where it does one bite and
then there's a long pause and it does
the next bite does look rather as if the
internal microcontroller is running its
own code and then this huge long delay
before it actually starts doing anything
much with the flash. So, that does point
at a microcontroller with its own ROM,
except
I spent some time poking through the
flash figuring out what various bits
were, or at least labeling them so I
could identify them. I did find the ROMs
for Super Mario and Super Contra
which are at half a megabyte and 1
megabyte respectively.
And above half a megabyte there's a
whole bunch of relatively structured
information and some stuff I haven't
been able to decode.
So that this for instance
definitely does not look like machine
code. It doesn't look like it's
compressed or anything like that. This
looks like an image, but it's not in any
format I can decode, but there is also
some chunks of actual 6502 machine code,
which is what this is. Turns out CPU
wreck was lying to me. It had completely
failed to detect any of this or the
actual NEZ ROMs that were in the flash,
which is irritating.
So, what are these? Well, one
possibility is it just happens to be
another NES ROM of the set, which I have
yet to identify, but I don't think
that's the case because it's surrounded
by lots of emptiness, like quite a lot
of emptiness. Also, the way NES ROMs
work is they're divided into 16k pages.
Some of the pages are program data and
some of them are character data. The
program data is accessed by the CPU, the
character data by the ppu. And this
block here is not aligned to a 16k
boundary and is remarkably small.
So I don't think this is a NEZ ROM. The
other thing is that NES ROMs do have to
have the standard 6502 reset vectors up
at the top of memory.
So I would expect to find them here.
They're not here. So I don't really know
what this is. If I disassemble it,
I can go here to Imhex's disassembler.
This, by the way, is Imhex, a binary
analysis tool that I've been playing
with. It is pretty good. It's its big
feature is that you can it's got this
scripting language which lets you define
the structure of your binary.
And when you run that, it will then
apply the structure to the binary and
pass it for you.
So, here is the disassembly of that
piece of code. And it looks like it
loads at
6,000 hex. You see there's a JSR 6030
here.
And 6030 here is in fact the start of a
sub routine.
And 6,000 hex is actually a valid
location in the NEZ and it points at
something in a cartridge. This says
cartridge RAM, but this is entirely up
to what the cartridge does. So, this
makes sense.
But looking at it, it seems to be a lot
of little sub routines.
So, not actually standalone code,
but further down there is another block
of 6502 code, which is this one.
And this is aligned to a 16k boundary.
And up at the top there are indeed some
bytes. These bytes do not make any sense
as reset vectors. So this is the address
0103. They're actually pointing into the
602 stack. So that would give 0103 as
the interrupt vector, OCB as the reset
vector, and 010
as the NMI vector. Uh where are they?
Yeah, I mean these make sense as
addresses,
but they don't point at the ROM, they
point at RAM. So something in here would
have to initialize that.
Now the interesting thing is that while
this does look like a piece of NEZ ROM,
I would expect it to be followed by the
character ROM, which it's not. It's
immediately followed by the Supercontra
ROM, which is all of this. So this is
peculiar. Now, I do not know how this
thing actually finds the various ROMs.
Somewhere there must be a table telling
it which ROMs are at what location in
the flash and what NEZ mapper is using.
The mapper being the the memory manager
chip that NES cartridges have. Emulators
have to support all the various
different types of memory managers.
These are called mappers and they're
identified by codes. If you download a
NEZ ROM image like these ones I have
here perfectly legally up at the top
there's a header which is not part of
the NES ROM at all. It's part of the NES
file which tells it how many program
ROMs there are, how many character ROMs
there are and these two bytes contain
various flags including which mapper is
in use.
Of course, this thing doesn't use the
NEZ format, so there must be something
somewhere.
But my suspicion is that this stuff in
the blocks I've labeled MC1 and MC2
could be part of the menuing system.
That's only really a possibility. It's
possible that the menuing system is done
entirely by the onboard microcontroller.
I would think this would be unlikely as
it means that it has to be baked into
the the mask ROM inside the blob and
therefore is very difficult to modify.
It's possible. If that were the case,
then all of this stuff at the top would
be the various menu images and so on in
a fixed layout that the microcontroller
ROM is decoding.
But the more flexible way to do it is
the menu is just yet another NES ROM.
And if that were the case, then these
two machine code blocks would be it.
So I could try to reverse engineer
these. If I disassemble the big one
to to
8,000,
what we got here is
like perfectly normal 602 code. So this
would be the entry point to the ROM.
Probably
if we jump to C378, which is
here, which is a completely valid
address because this is just after an
RTS. This is where I'd expect a sub
routine to start. 6383
is here. This is storing stuff into
addresses in the 4,000hex range, which
is exactly what we'd expect because this
is where the various NEZ registers live.
And it goes away and does stuff.
Sad thing is that I haven't found much
in the way of
where are we? In the wrong place. This
one. Haven't found much in the way of
useful strings. I have found
this
cube technology company right by
Anthony.
Cube technology do have prior form in
the bootleg nez world but I don't think
this device that I'm dealing with
matches anything listed here that I need
to check this in a bit more detail. So,
this does suggest that we're looking at
something that's not just a ripped off
nezrom
and that this is something that's
specially been written for this device.
So, what I'm wondering is this capture
that I got, it could be complete
garbage. If the capture hardware was
interfering with the signal enough that
it wasn't booting, then it could never
have actually been getting anywhere
other than the very minimum of the
startup sequence. So, it's entirely
possible that this thing is supposed to
be executing that startup NESROM, but is
never actually getting there. I have no
idea. So, I think I'm just going to have
to disregard the capture entirely as
being of any use whatsoever.
That means that the next steps for
reverse engineering this are going to
have to be analytical, decompiling the
ROM somehow or via experimentation.
And the simplest experiment is to simply
modify this startup ROM. We got at 7 CO
is JSR 738.
So if I change that to
4 C
O C N
and disassemble it again,
we have a jump to C O. This should be an
infinite loop. So if I write this to the
flash, boot it, and the menu appears,
then clearly this has nothing to do with
the menu. If it hangs, it's hit this
instruction.
So let's try it and see what happens.
Programmed, plugged in, power on.
It's hung. Great. This is good news.
That means that that piece of NEZ code
was in fact part of the menu. This means
I can now run arbitrary code on it.
Although that arbitrary code does think
it's a NEZ.
Okay,
let's do some more playing.
Progress has been made. I loaded the
menu ROM into GDRA, which you can see
here. Here is the fingerprint left by
our mysterious Anthony. It now occurs to
me, is this Anthony the same Tony who
wrote the code for the other thing I
reverse engineered? Anyway, this is very
clearly a NEZ. It's doing stuff with NEZ
registers. It looks all NEZish,
but it's more than that because it's
also writing to a bunch of non- NEZ
registers. And this is extremely
indicative of
one of these a VT369 or or really it
could be any of these VR technology nox
but I think it is the VT369.
This is the most advanced NES on a chip
clone. It's got lots of fun stuff like,
you know, hardware multiplication and
division, super fast CPU, 8 bit per
pixel graphics, high resolution. This
explains nicely why the menu that I was
seeing before I broke the screen doesn't
look like a NEZ. Once I figured this
out, I then did something I should have
done a long time before, which was I
took the SHA1 fingerprint of the ROM
I've got and I looked for it in MAME.
And here it is. So, what I'm looking at
is a 36P case. That is the double quote
official double quote name for my
device. And yes, there is some NEZ
support. It doesn't actually work, but
someone has seen one of these things
before. Now, the reason why it doesn't
work is that if I go up here and look
into the memory map here
for the VT369,
there is a 4K ROM built into the CPU
which handles stuff like initialization.
And this very nicely explains
this slow initialization that I was
seeing in the SPI dump. The machine has
started up. It started executing code
out of ROM. It then goes and initializes
the SPI flash does some stuff and only
here does it actually set up all the
things so that it starts reading from
the SPI flash. And in fact the weird
memory patterns that I was seeing can be
very simply explained by this is a NEZ.
It's got a pu graphics processor and an
APU audio processor and they're going to
be reading stuff from the ROM
continuously. Like the PPU is going to
be reading stuff from ROM just to draw
stuff on the screen. So yeah, the actual
CPU traffic is going to be buried inside
here somewhere or not at all if the
system crashes before it gets to that
point. So somewhat sadly, it seems that
this thing is actually pretty well
understood, which makes my life
considerably easier, but also means that
there's not much to do with it. However,
I said earlier that the main support for
this thing isn't very good. In fact, it
doesn't work at all. It just produces a
gray screen. In fact, let me show you.
we get a big warning that it doesn't
work and we get a gray screen.
The reason why it doesn't work is
because nobody knows what the internal
ROM is for this device. That's the
internal ROM is the thing that's
actually like initializing everything
and handing off to this. Which does make
me wonder, can I find a way to dump the
internal ROM?
The internal ROM is of course baked into
this lump of epoxy here and completely
inaccessible. So I would need to find a
clever way to do it. I've already
established that I can execute code on
this chip. So I could write some code,
stick it on this that reads the ROM and
makes it available somehow.
This thing is pretty short of IO ports.
I do know where the IO ports are in
memory and the buttons will be connected
to them,
but I don't know if they're birectional.
They will of course be set up for doing
reads by default.
So, I might need something else. One of
my tricks for doing this is to do reads
from the flash in a particular pattern
that my signal analyzer can pick up. But
given how much traffic there is, that
doesn't seem like it's a good idea.
But there is one IO port that should be
easily accessible, which is
the one that turns the backlight on.
There's also the audio, but that seems
like it would be too much work.
If I can identify
how the code on this chip here is
turning the backlight on, I can turn it
on and off in patterns, read that with a
signal analyzer, and bit bang serial
bites slowly out of the thing and
capture them. This will require analysis
of the menu ROM on this thing to try and
figure out what it's doing. This ROM is
quite interesting. It's clearly divided
into three parts. The reset vector at
the end of the ROM points at CBO, which
is a little unusual because normally you
jump to the beginning of the ROM just
because that's where the first bit of
code is. Then below it, there's a big
expanse of nothing, followed by
some what look like library routines.
And above it,
starting at the beginning of the ROM at
CO, there is another big chunk of code.
This is the thing that ends in our
write by Anthony string.
Now the interesting thing about this is
that if you go look at the decompile
code, it's doing something and then it's
looking at the values in CDO and CD1 and
depending on what numbers it gets, it
then sets different values to the
pointer in address 8 that gerra is
failing to decompile properly. And once
it's done all that, it then goes away
and does something with it all. And I've
seen this before in the Tony.
I think that what we're looking at here
is code that's detecting what LCD panel
is installed. That's done by this
function here. And then it's using
different initialization tables. So if I
go look at C9 AF, well, okay, that's not
doing a lot. But down here, we get
triplets of
register two values. register two values
and so on until at the end we get two
FFS and that's what tells it to stop. So
I bet that if I could find a table of
SC7789
IDs I should be able to find all of
these things. But this means that what
we're looking at here is the LCD
initialization code. So I think what
we've got is a basically a cut and shot
ROM where it's assembled in a fairly
slap dash fashion from binary chain. Got
the library stuff which is not not
there. It's here starting at F50O.
We've got the the initialization stuff
that is agnostic to the various
different VT369 devices. And we have the
chunk of code at the top that is
initializing the extra hardware. So this
suggests that the actual menu we're
seeing is probably not in either of
those two. It might actually be up here.
There's not very much code here.
But anyway,
what I was looking for is the LCD
initialization. So I bet that somewhere
inside this function is whatever it's
doing to turn the LCD backlight on. And
that's the only bit I'm really
interested in. So if I find where this
is called from, which is here, and I put
my infinite loop here just after the
call to CO, and I flash it and I run it,
I might be lucky and see the LCD come
on, and then hit hang. I've reflashed
and installed the chip. Power on. Press
the on button. And let's see what we
see.
No backlight. Okay, I was wrong.
Something else must be turning the
screen on.
But that does give me a useful lower
bound. We know that the screen backlight
on thing must be after the piece of code
I patched. So we are actually making
progress. Incidentally, I know I haven't
broken it. I'm not sure how well this
shows up on camera, but if I turn it on,
stuff is actually appearing on the
screen. It's just the backlight hasn't
turned on. Right, I've got the other
bound. I can do this.
It's this. If I put my infinite loop
just before it, the backlight doesn't
turn on. If I put the infinite loop just
after it, the backlight does turn on.
And if I look at it, it's poking a
couple of registers. And these are some
of the many undocumented VT369
registers. But it is clearly setting a
bit in 4144 and clearing a bit in 4146.
And purely coincidentally, if we look
down here, here it is setting a bit in
40144 and then setting the same bit in
4146. I bet this is turning the LCD on.
And this is turning the LCD off. Okay, I
should be able to control the LCD now.
So here is my absurdly simple test
program.
We simply call the LCD on function and
then we infinite loop and then this gets
patched into the binary and we flash it
and we power it on to see what happens.
LCD comes on. Great. So, all I need to
do now is to figure out where the
backlight transistor is on the board.
There's a number of transistors, so
that's going to be irritating. Hook up
the signal analyzer, write some code,
and start clocking data out. Here is my
test program. It is very simple. It just
clocks through all the bytes in the ROM
and sends them out in standard UART
format at bit banging at about 30
boardish.
Assuming I did this right, it should
give us a nice clear signal that I can
then read off using my logic analyzer.
Unfortunately, there are two minor
problems. The first one is
the board's broken. It appears that me
putting this chip in and out all the
time has wrenched something and
something in here is no longer making
good contact. If I push down here and
reset the board
there, my program is running. You can
see it blinking the backlight. But if I
let go,
it stops.
So, I'm now very torn between taking
this thing off and resoldering it and
potentially breaking the board even more
or bodgeging something.
As you can see, there is rather a lot of
hot glue in there and dealing with that
is not going to be fun.
The second problem is that my logic
analyzer here which I do have hooked up
there it is connected to ground and data
is refusing to actually pick up the
signals from the program. I don't know
why the voltages look reasonable. It's
about 3 volts oscillating up and down
from zero. I can see the signals
perfectly clearly on the oscilloscope.
But this thing just returns a logic one
for everything, which is
deeply annoying.
So,
I'm going to have to go away and do some
thinking.
So, let's solve one problem by changing
my program. So, now instead of clocking
stuff out in new art format, it now
clocks it out in Morse code and also
quite slowly. I'm using Morse code
because it's relatively robust over poor
signal carriers.
The second problem is solved using this
rubber band here which puts tension on
the socket and makes it make connection.
So now it does actually work. If I reset
the board,
there is my program running. The third
step is this phone. I'm going to use
this to video this.
Three hours later, I get my video, which
looks like this. It is all done at a
super low resolution because I knew this
video would be huge. And the only thing
I'm interested in is the brightness of
the screen.
You'll notice that the brightness does
vary rather more than it should due to
automatic brightness control, but I'm
hoping that it will work out. out.
Anyway, so what I do next is
use this ffmpeg command. It scales the
video down to one by one. It converts to
grayscale and it outputs it as raw video
like so. And you see that this video is
311744 frames long. If we look at the
output file, it is 311744 bytes long.
This means that each frame becomes a
single bite of brightness in the file.
Here's pulse view. I haven't tried this
yet. Okay. Import raw analog data
without header.
All files. And here is our video file.
And the data format is unsigned 8 bit
one analog sample rate
don't care.
We get stuff when I zoom in. What do I
see?
It's not great, but that's a short long
long long
gap.
Short short short long gap
short short
gap. Oh dear. I don't like this. Uh I
think that gap here is actually
okay. The format that this thing has
been sent out as is basically hexadimal.
So it's two nibbles encoded as Morse.
But I think this is way too noisy to
decode.
So here is short long gap short.
So short long is
a and a single short is an e.
Okay, let me try and clean this up a
bit.
Here is my very shoddy Python decoder
program. We run that, we get a text file
containing this. It's actually a CSV
file. The decode is not perfect. There
are some few bad entries such as this
one which is at 570.
So if we go look at that, it's in here.
5700.
Here we go. I'm using Pulse View to
actually turn the analog signal into
binary. And there's a little dip there
that actually should be between two
DARs,
but it hasn't registered. So, there is a
missing space there. So that should
really be
five, which happens to be a zero. So I'm
just going to manually fix this up like
so. Okay, the next one is 64310.
What's this?
642 6430.
Same issue, but between two dits. So
this should actually be dit da da da.
So that's going to be da da da which
happens to be a two. I've got one there.
And the third one is here where very
clearly it's not registered the gap
between the two digits correctly. Let's
just check that. 92354
354 should be in here.
three. Yep, it's this one. Here we go.
Five DS, five dits. But this gap is just
too short.
My decoder expects this to be four or
more. But if I change the threshold to
three or more, then it actually makes
things much worse because there's some
of these gaps here, which are three
samples. So that's actually going to be
a zero
followed by a
five.
Okay. And that brings me to my second
shoddy little program, which is this,
which actually turns the CSV file into a
binary
like so. And this has produced a
4094
byte binary. Uh, that should be 4096.
There's two bytes missing at the end.
All right. So, stupid bug on my part.
There's a oneb here that should be down
there. So
yeah, I need to do another one of these
at the bottom of the program. Do not
write Python like this. This code is
terrible. Oh no, wait. That needs to be
there.
So
it's now 4095 bytes, which is still not
right.
Here's my emitter. We start out at hex
10,000.
We read a bite.
We emit it. I nibble first. We increment
the address. And then we check to see if
we've rolled over to hex 2000. [gasps]
[sighs] I don't see anything
particularly wrong with that.
So, I'm wondering if
there's an issue somewhere in here where
two bites have run into each other.
Let's actually take some of these out
and try that again.
Aha. Aha.
T9. Well, that shouldn't be there.
which is here.
Yeah, that's bad. But this won't affect
the number of bytes. It's just a bad
bite. I have no way to detect edge cases
like that. There's no check summing or
par or anything.
So, I think I'm actually not going to
fix that by hand.
What I'm going to do is to rerun the
whole 3-hour capture again in better
conditions and hope I get a cleaner
signal. I think
I redid the recording. I used a much
better phone that was capable of doing
60 frames per second. I also turned off
the automatic brightness control. And as
a result, we now have this beautiful
crisp clean signal which is so much
better than the old one. And after
running my decoder, we end up with this
file here. Now there is one odd thing
which is there is a single bad decode
454708
here. You notice that there's this kind
of
long pulse here with a tiny little dip
in the middle. That should be two DS.
This should be a whole this whole thing
should be a zero. So I was curious. So I
went and checked out the video and in
fact
there is
there you know spots that the brightness
decreases slightly. That's all you get.
So this is not a decode for an FFmpeg or
a camera problem. It seems that the
actual device has done something weird
and I don't really understand why. But
anyway, we know what it should be. It's
another zero. So, let's just manually
fix that up to about Yeah. Oh, 454
708 like so. And save that.
And now I can decode it to bytes.
Ah,
that's not good. [clears throat]
That should not be an O. 574317.
Something is deeply wrong there. Each
bite is two nibbles which are
transmitted as two characters with a
medium gap between them. So this is five
DS gap. Five DS meaning 0 0. This is
just three DARs.
Wait, there's a small gap here. Oh, I
know what's happening. This should be
another DAR.
Why isn't there a DAR there? Okay.
574300
1020
574320.
That's That's off.
That's the end of this dark.
Off. Something happened.
Off. On.
I have no idea why that happened. It's
probably the same issue as the other
one, but that's really strange. Luckily,
this is a long run of zeros, so we know
what this should be.
Like so.
And now we have 4096.
Is this correct?
Doubtful. So, let's stick this thing
into GIDra and see what happens. What
have we got? We got stuff disassemble.
Yeah, that's 642 machine code. That's
That's not I wonder if that's a decoding
bug. There are more bad bites here than
I was expecting. I wonder if something
else is going on.
Also, some of this machine code looks
weird. Why is it doing that? For
example, possible this is not actually
machine code.
What's at the end?
These look like 6502
startup vectors. Now these Yeah, that's
code.
That's Yeah.
So this is it's it's one of the
it's the IRQ.
So yeah, this is going to be the startup
ROM that the thing uses to actually
initialize.
Uh this is the reset vector, the main
entry point which is here. Does this
disassemble?
That's so much better.
Okay, I think that stuff at the top was
not machine code. This means that my
read actually looks plausible.
Okay, that looks a lot better.
So, it's doing stuff quite a lot of
stuff. So, not actually that much stuff.
So, this is the code that I expect to
actually be doing the SPI flash
initialization.
So these are all registers that are
unknown. I haven't found any
documentation for them. This is very
clearly waiting for something to be
ready which is called from a whole bunch
of places. So here we are sending bytes
to a thing then we wait. Then we send
more bytes to the thing then we wait.
This is talking to an external
peripheral. In fact, these numbers look
faintly familiar.
Let me pull up the logic analyzer view
of the SBI flash. Okay, what have we got
here? 06
FF
05.
And that's coming back. 06 FF05.
There's an 06.
There's an FF.
There's an 05.
They're all being written to F to 4301.
What's the next right to 4301? 35.
So, what's the next bite that goes in is
a 35. Okay, we found the SPI flash
command and control registers.
This actually suggests
that the block at
430
is where the whole SPI ROM interface
control registers are mapped. So I think
that this is the SPI write data register
and this
is the SPI read data register.
I'm actually going to rename some of
these. This is TX and this is RX. One of
the oddities of the SPI protocol
is that the host, the controller
controls the clock signal, which is the
one down here. So if the device wants to
send something back to the controller as
is happening here then the host has to
clock out the 8 bits so the device can
send stuff back. So in fact sending and
receiving on SPI is the same. The the
SPI controller on the well controller
has got two shift registers one for
outgoing and one for ingoing. So this is
filling the outgoing shift register with
35 and it clocks it out with this. It
hasn't filled the register with anything
which is why it's a zero but the device
is sending stuff. So the receive
register fills up with two. So the way
we expect it to work,
uh, here's our write to 35
is that we send the command.
We then do another dummy transaction
which populates RX. We then pull the
value out of RX.
I don't know why it's writing to RX
here. That's completely speurious. If
you go and look over here at the machine
code, it hasn't actually initialized a
with anything.
So, the only reason it's done that is
presumably to reset something inside the
SPI controller.
Okay, back at the dump, we then have
this big long pause while the the ROM
does stuff. And then we output an E7,
which shifts the whole thing into quad
SPI mode. Is there an E7 here?
Doesn't look like it, but then I
wouldn't expect it to be. That long
pause suggests that it's finished doing
this and it's gone away and done
something else. Anyway, let's take a
look at some of these functions. What's
this doing? This is a delay loop, right?
This is going to be our big long pause.
And then we initialize a whole bunch of
other stuff, including waiting for some
SPI transactions.
This actually looks like a very
different system than the one that did
these rights. These are sent a bite at
time. Eight clocks each. These
actually involve
multiple bytes been sent consecutively.
So I think that by this point
we are no longer using that simple SPI
flash command set.
So what does this do?
Oh, this is big.
So this is doing a whole pile of
initialization of other registers. These
are now in the 41 block rather than the
43 block,
fiddling with the power control.
And then here
we reset the system. By this point, the
SPI flash must have been set up and this
will be read out of the SPI flash.
Here's an interesting thing. Looking at
that very first startup routine, I can
see that it looks at something in 41F
and then depending on the result, it
does one of three things. If this bit is
set, it goes away and initializes the
SPI flash which we've looked at which at
the bottom of it calls 1 A2F.
If however the top bit is clear, it just
calls 182F. Then there's a third
initialization thing which is 1904 here
which is it's a different SPI flash
initialization.
So whatever that's doing clearly what
this is doing is looking to see what
kind of ROM the device has and going
down the appropriate initialization
route. And this one
is I think if there's a memory map ROM.
So I don't think this is anything to do
with the SPI flash. In fact looking at
this second initialization routine and
the the results of the logic analyzer I
think this is the one we're using. This
is the smaller simpler one. And in fact,
this is the point where the chip select
line goes high and it just starts doing
gibberish. The last two commands before
that were 35 O read status register 2.
35 is the command and this is the result
which is two. I think this one is this.
So in fact it has read status register.
It then does a command 26
and there's a long pause. Then it starts
doing more stuff. So I think this
is switching it to quad SPI mode. But
there's more. Someone on the bootleg ROM
forums who dealt with similar devices
pointed me at this piece of code.
Once the main ROM has started up, not
the internal one, the one on the SBI
flash,
it reads bytes out of an external
peripheral and stashes them into hex EO.
And then this is a code library that's
used by the rest of the system. And I
think this is a copy protection system.
This I squared CROM is inside the
silicon blob where you can't get at it.
The fact that it's read by the SBI flash
means it's all completely useless. It's
just annoying. So, I don't know what's
going on there. But I'm going to have to
dump that as well. And this is a bit
more complex and a bit weird.
This is Gidra doing a very bad job of
decoding something that is reading in
data one bit at a time. So this thing
is telling the ROM to clock out the next
bit.
This is then read as part of some status
register here.
What it's actually doing is it reads the
this will be a status presumably
might not even be I squ C but it's
shifting the value up until it rolls off
the top of the bite into carry and then
it shifts the carry into the bite being
read. So eight times round and it will
read a bite and then just repeat that
until it reaches the end of the block.
This bit is a little bit more
complicated again. Gidra has failed to
decompile this O2 code correctly. I
don't think this is reading anything. I
think this is initializing the ROM
device that I'm now thinking is not
actually I squared C and it may just be
some serial bitwise shift register.
But I am going to have to figure out how
to dump this. So I'm going back to my
Morse code program.
Well, here is my new updated dumper,
which is rather smaller and simpler than
the other one. Here is the blinky light.
Here is the thing loaded into pulse view
producing a decently clean signal. This
one is using groups of eight. short for
a zero bit, long for a one bit. It's
simpler and easier and faster than the
Morse code thing. Now, you may be
wondering why I dumped the big ROM using
Morse code.
Anyway, here is my decoder, which as you
can see is also much simpler, and it
produces 256 bytes of ROM. So this looks
like
stuff.
So let's find something looks like an
instruction. These EAS are not that 20
is a JSR.
So that's disassembled. Yeah. Yeah. This
is machine code
except for that 1B at the end.
Now, one of the things I found was that
the main ROM was actually calling stuff
here. And why is that not working? Alex
EO.
It's showing me the wrong EO. I want the
one up here. So these are places where
the main ROM is calling into this thing.
So I knew that there was a thing at EO6.
So what this is doing is a whole lot of
manipulation of the serial ROM. If it is
a serial ROM, it's all the same code
that I saw before in the main ROM, but
it's split up into multiple functions.
Makes it a bit easier to understand. And
an interesting thing is that here it's
calling it easy to see over here. It's
calling this routine EC6 several times.
And what EC6 does is something a bit
weird using EO as a temporary variable
where it goes through it one bit at a
time fiddling with various control
registers. This function here
uh I haven't updated but this reads a
bit from the device and it does this
eight times. I think that what this is
doing is clocking out a command to the
device while at the same time reading in
a reply from the device. So this routine
here is called with a value in a and it
does one of these and then it does one
of these which I think is sending out
the command. Then it sends the value
that was first passed in. There's a
pause. And this reads 8 bits back in.
So, is this another SPI flash device?
No, I don't think it is. I've identified
two commands. The one that's used to
actually read as a ROM is ASKI0, which
is hex 30. And the one which is used by
the main routine for doing all sorts of
stuff is hex 10. This one is followed by
a single bite of payload which then
seems to set the thing up to read a
single bite.
And looking at the SPI command table,
which unfortunately is not in numerical
order, I do not see either 10 hex or 30
hex in here. So, while I don't know what
it is, I think that there is more to it
than the 256 bytes I've just read. The
main routine here, it does a hex10
command with 4A as the parameter, reads
the bite that's just been read, and then
does stuff with it. And what this is
actually doing is loading one of the
reset vectors from a table which is
here. So here you can see the various
table entries. There are two different
types of NMI handlers. So these are
programmed into the memory at the top of
the stack and then at the very top of
the ROM
are the hardwired vectors that call
them. So it's clearly using this thing
to identify something about the device
which is then used for setup. So if I
want to emulate this, I'm going to have
to know what values these return. I
could dump them easily enough. It's just
matter of knowing how it works. I can
just change my program. But I would kind
of like to know what the device is. I
think 4a gets a device ID. It is
actually called from a bunch of places.
There's clearly a whole bunch of stuff.
It looks like that this is setting the
address to read from, but there's
clearly more to the address than just
these eight bits because by sending a
zero, it's read the whole 256 bytes of
the ROM out. So, I'm going to have to go
and do some more research.
I found this in the NZDEV wiki, which
describes a particular setup, mapper
427. And these describe the various
different types of cartridge you can get
which is a VT369 device which has an I
squared C bus attached to either port
4148
or 4150 which we're seeing here and that
has a I squared Cbased double quote
protection chip. Also it may have 24 CO4
EPROM connected to the same port. So
this does actually describe what I'm
seeing here where we have two I squared
C devices attached to the same port. And
when we are accessing the EPROM, it's
using address hex 10. And when it's
accessing the protection chip, whatever
that is, it's using device hex 30.
Except I'm still very confused because
none of this looks like I squared C.
I've got the data sheet for the device
which the wiki describes which is a
atmemell 24
which is a 512 by EROM
and it's got the diagrams for the the
various control sequences and these do
not match what the code is doing. For
example, random read, which I expect is
what the the EPROM access code is doing.
What you do is you send eight bytes for
the device address. And the device
address for EPROMs always starts with
the binary 1000
and the bottom four bits describe which
device and whether you're reading or
writing. Then you send the address you
wish to start reading from. Then you
send the device address again and then
you start receiving the data. But with
this the read code is very
straightforward. It sends hex 10. It
sends the address and then it receives
the value. If it was following this
logic here, we would have to send the
device twice. But it isn't. What's more,
I squared C uses 9 bit bytes because
every eight bits of data 1 2 3 4 5 6 7 8
is then followed by a acknowledge bit
and we're not seeing that. So I don't
know what is going on here. It's
possible the wiki is wrong. It has
happened. But the one thing I do know is
approximately what the API looks like.
So I can write a simple program. This is
just based on the last one which loops
through and reads all 256 available EROM
values.
This is completely leaving aside the
fact that the data sheet here says that
the device has 512 bytes. But the only
reason I know that it's 512 bytes is
because this wiki says it is and the
wiki might be wrong. So I don't know.
Anyway, let's dump the EPROM and see
what it says. Well, here's the EPROM,
and it seems to be mostly blank. I think
these repeated OFFs are what you get in
one of these EPROMs if you don't program
anything into it. There are a few bytes
that have been changed. And if I go look
at the source code here, it's reading
the bite at 4 A. And if we look at 4 A 9
A, it's that one, which is a zero. If we
scroll down, there's another reader for
a. Okay, here it's reading the bite at
two, which is that one. You can see that
is non zero. That has been modified.
Here it's reading A2, which is here, and
so on. So, I think I do actually have a
correct EPROM image, but I have really
no idea what any of this means. The
actual values over here just seem to be
written to various registers. Like the
one at A2 goes into ppu control on the
NEZ. If I go look at the documentation,
ppu control here,
the value being written is a8.
So a is 10.
That's one. NMI on zero.
Read backdrop from X pins. Sprite size 8
by 16. Zero
sets the background address. 8 is
sprite pattern table one uh ignored in
8x6 mode. So that doesn't do anything.
And the rest are zeros. So
I don't know why this is in the EPROM.
This is all stuff that has to be set
correctly for the menu to work at all.
So why would it be reading it from the
EPROM which is designed for modifiable
storage where you store like save games
and settings and things like that rather
than just having them hardwired into the
flash chip. Maybe it's deliberately like
that so that you can't run this flash
image on a different device that doesn't
have this EPROM. It's a very odd way to
do it.
So, I think that I now have everything I
need for this device. I've got the main
flash ROM, I've got the internal ROM,
I've got the magic serial ROM, and I've
got the EPROM. I don't really want to
have to write my own emulator cuz that
sounds like work. But the good news is
I found an emulator that claims to
support Mapper 427, which is what I
think this is. So if I can put these
things together in a way that the
emulator understands, there's a faint
possibility it might work depending on
all sorts of stuff. Okay, so the first
thing I need is an INZ header. So, I'm
going to steal one from
Super Mario Brothers.
It is
16 bytes long. Then
I need the the full flash ROM.
Then I need the internal ROM.
Then I need the magic serial ROM
according to the emulator's author. So
now I need to edit the header to make it
correctish.
Now we load our ROM into this
edit current header. Interesting. Okay.
Right. Now we have to feed in
information here. So, we want NEZ 2. We
want
uh that didn't work right. 4 2 7 mapper
427. This one. Submapper.
Submapper 0 has the I squed C port of
4148. Submapper one has it at 4150.
So, we're going with one. Pro ROM
kilobytes. Well, this thing is unified
architecture, so it doesn't really have
a distinction between programmur.
So, I'm just going to put the whole two
2048 there and see what happens.
MISROMs, we've got two. We've got the
Yeah. Uh, typing text into this is hard
because it won't let me delete the last
character. So, if I delete the zero and
type a two, I get 20. That's nice. Okay,
we got two misgs. We've got the internal
ROM and we've got the protection ROM.
This stuff I don't know what it means.
Console type is a VT369.
This thing says that if there's a pro
NVRAM field of five bytes, it knows
about EPROM. So,
uh, that's not right.
I think this column here is trying to
set the batterybacked NV RAM. If I set
this, that's non batterybacked and that
thing hasn't become enabled. So, I don't
know what's going on there. Uh, we are
both neither NTSC or PAL, I think. Input
or expansion device.
Don't think any of these apply to me.
Okay.
So, now if I go over to CPU and I do
run, what happens?
We get a blank gray screen.
Okay, let's try the debugger.
It seems to have completely failed to
map our internal ROM into the right
place. So maybe it is not mapper 427.
The other plausible looking one was
mapper 426. So let's try that instead.
Gray screen. And yeah, it looks like the
same thing has happened. Oh no, no,
wait. There is something here.
This looks like our code. Uh, does it?
Yes, this is indeed our code. Okay, but
it's not booting. It looks like with
this configuration, as soon as you start
the machine up, it has mapped our menu
at the right place. So, it is now
immediately executing the menu code here
and is not executing the internal ROM. I
don't honestly know if that's bad. So,
here it's turning the LCD off. part of
it initialization. It's initializes a
bunch of registers.
The bit I'm particularly interested in
is the where it reads the I squared C
protection ROM. So that's happening at
DO3.
It's not getting that far. That's why if
I put a break point CB1F here, it works
fine. So something is not right. This is
going through and executing all this
code and then it's getting stuck in an
infinite loop somewhere. This is a
little loop. It's waiting for this F4
value to change.
So I bet that this thing is written from
an interrupt of some description which
is never being called. That mysterious
value is actually being set. I can see a
break point stop when it's trying to
write it. But it is the wrong value. It
is 1 F and it is coming from
this code which is reading a value from
some hardware register.
So there is some piece of hardware on
the emulator device that doesn't match
what's on the real hardware. I don't
think this is the right mapper. In fact,
I suspect this might be a new mapper
which will be a ton of work to make
work.
My replacement device arrived. It is
subtly different from this one. Apart
from, you know, having a functioning
screen, this is intended for a different
kind of phone. I didn't order the same
one again. This has bumped the USB
socket from here on this one up around
here, but it is very clearly the same
device. One cool thing I noticed is that
if I turn it over, you can actually see
through the translucent plastic the
screen and the four LEDs that light it
up and the ribbon cable, which is not
particularly well put together. And if I
turn on this flashlight,
get things a little well oriented, you
can actually see the components. That's
the speaker. That is the battery. There
is a bundle of wires and some sticky
tape holding it all together. Here is
the big PCB
and there aren't any other components.
Here's another interesting feature and I
don't recall whether the other device
had this or not and because I've
dismantled it, I can't tell anymore, but
this black bezel here is actually
smaller than the screen. So, it overlaps
part of the screen. If you look down
here,
you can actually see under the bezel
revealing more screen.
And yes, I have checked and this
overlaps some of the play area of some
games,
which is a choice.
Sadly, this is probably where this
adventure is going to come to an end, at
least for now. I was going to try to
pack crude support in for this ROM image
into a NEZ emulator, but there are two
emulators that support the VT369 chip
that this thing is based around. One of
which is a fork of Nintend that only
builds on Windows and I don't do Windows
and the other is MAMEim and
unfortunately the MAME support is poor
and I would have to add quite a lot of
functionality which is easy enough but
first of I' have to learn how MAME works
inside so I'm not going to I will upload
the ROM images and stuff to various
sites there are forums that collect them
so none of this will go to waste I may
look at main later but if I do that that
will be a whole different project. So,
I'm going to finish up here.
At some point, I do want to retrofit
this working one into a little games
console thing with my quote controller
unquote because these rubber keys are
kind of terrible. And this is actually a
decent enough little device.
If you want bootleg NEZ games, shut up.
If you want bootleg NES games, you could
do worse.
They're nicely presented. They don't
have the, you know, the 400 in one
cartridges where all the games are
duplicates and ROM hacks of each other.
These actually seem to be pretty
legitimate ripped off pirate games. And
I haven't found a game yet that doesn't
just work perfectly. So, that's nice.
But I will do all that if I do it off
camera.
So, I'm going to finish it here.
I know nothing about nezes. It has been
really interesting to learn. I hope some
of my viewers, assuming I have any,
found it interesting, too. So, as
always, I hope you enjoyed this video.
Please let me know what you think in the
comments. And I will see you all next
time.