Electronics, coding and hacking. And ADD.

Arcade1UP USB, buttons working


Today I added the USB connector, as described on this Imgur gallery. I'm going to find a more elegant solution to some issues, but it does the job for now.

I used a female USB plug and soldered it to the PCB points using a four wires. They are currently unshielded, but that's not a problem for a low-speed device like a keyboard. Maybe I will find a more elegant solution in the future. The USB plug was then hotglued to the back of the case and will hopefully stay there for a while.

Once connected I could access the MAME menu by pressing the [TAB] key. The arcade buttons was accessible from there, and configurations automatically saved.

Below is the finished solution. That'll do for now. I removed the UART wires as they will be replaced by a BTLE wireless UART module later. The USB keyboard was left inside the arcade in case I need to reconfigure some keys on a later occasion.

Super Mario Bros works perfectly, and I'm looking forward to spending hours of fun with this arcade!

Exploring the Arcade1UP


About two weeks ago our local Toys'R'Us had a final closing sale with 90% off on all items. Knowing they had a few arcades in the store, I showed up early to get Street Fighter, but since they were all sold out I bought the Asteroids edition instead.

Assembling the game

Beer can for scale

This is the one I bought. Unassembled, flat-packed, IKEA style. Unfortunately I did not take any pictures of the build process, but the manuals were easy to follow, and I spent about half an hour setting it up. Got a little help from my 8 year old daughter, too.

After powering up the device, a menu popped up with a list of four games: Asteroids, Tempest, Major Havoc, and Lunar Lander. All games from the vector era, i.e. graphics composed of just lines.

Not quite my cup of tea to be honest, but it was a calculated risk. If it was too boring, I could do a switcheroo with a Raspberry Pi, or maybe one of those 60-in-1 boards. Either way, I wanted to explore the insides, so last night I decided to pop the lid and see how hackable it is. Spoiler alert: Oh, it is. Very much so.

Finding a serial console

I removed the game PCB, which is located behind the LCD screen. The first thing that caught my eye were the ICs: their surfaces has been etched away to hide the model numbering. This made me question my naïve approach, but I kept going and blindly probed around with the oscilloscope. After foolishly looking for some interesting test points, I stumbled across something interesting: right next to the flat flex cable, where it says "CON4", there's a 4-pin port. The signals were easily identified as: 3V3, TX, RX and GND. Yes, we have a UART.

I soldered a pin header and started looking around for USB-UART modules. Of course, all were gone and the ones I've ordered had not arrived yet. I settled using an Arduino as a temporary substitute. I simply set up a SoftwareSerial and monitored the activity using putty. The UART runs at 115200,8,N,1 and keeping an eye on it at power up shows a long boot log, and reveals that this arcade is running BuildRoot Linux!

Logging in, looking around

After the boot I was dumped at a login prompt. A user named "default" has no password, and spawns a BusyBox shell. The baudrate of 115200 caused a lot of errors, but slowing it down to a baudrate of 19200 (by issuing a stty -F /dev/ttyS0 19200) fixed that. This would not be a problem with a proper UART-USB adapter.

After exploring the file system, the essentials boils down to:

  • The arcade runs MAME. Basically all the files required by the emulator are located in /root.
  • A directory called 565 contains all the menu graphics, which is dumped directly to the framebuffer on demand.
  • Despite the menu only listing four available games, there are a total of seven games installed. The extra game ROMs are Gravitar, Asteroid Deluxe and Street Fighter!
  • The /root directory contains a couple of scripts for mounting and unmounting external storage. I suspect there's a USB port on the board somewhere.
  • A script called "" executes /root/mame with parameters from a file in /tmp.
  • Without root privileges, the adventure appears to end here.
  • Getting root privileges

    I started looking for BuildRoot exploits but couldn't find any easily accessible. The password file /etc/shadow was not readable by me at this point, so I couldn't crack the root password either.

    But wait, hang on - look at that script again, and check out the file mode bits:

    -rwxrwxrwx 2 root root 72 Jan 1  00:01

    This file belongs to root and all users have write privileges to it! The menu process is also run by root, could this be a loophole to gain root access? Another spoiler alert: Yes it is.

    I added a few commands to the script which took a copy of /etc/shadow in /tmp. Starting a game confirmed that this worked, I had a readable copy in /tmp! Instead of cracking the password, which would probably be trivial, I removed it entirely. I then modified the script once again, this time to take a copy of /tmp/shadow back to /etc.

    And now root no longer needs a password and we have full access!

    Street Fighter!

    "What, this ol' thing? Just my Asteroids arcade running Street Fighter, nothing special."

    Importing a new game

    Importing a game from the "outside" was a bit of a challenge through a serial connection. After some impatient finger drumming, I noticed that uudecode was a part of the BusyBox. This means I can transfer a file as 7-bit text over the serial terminal, and turn it back to 8-bit binary on the arcade side.

    And that worked too! Welcome to your new home, Mario.

    Plans ahead

    I have to admit there's one thing left, and that's configuring the buttons to the new games. I need to read up a little on MAME cfg files, but I think this should be a pretty painless.

    Also, while writing this blog entry, I found that someone has already found the USB port I was talking about earlier. I will attempt to solder a connector to it later today and see how it works out. This will make file transfer much easier.

    Patching the live Amiga ROM


    As I'm adressing the previous issue with the APECAT board, I'm trying my best to simultaneously plan ahead and clear the road for future obstacles.

    One of the issues I want out of the way is patching the Amiga system ROM, commonly known as the Kickstart.

    As implied, the Kickstart is stored in Read-Only Memory. Physically reprogramming it in situ is pretty much impossible, but thankfully the Amiga developers thought ahead and made a shadow copy of the address vector table in RAM. This table can easily be updated using the exec.library's SetFunction(), which is what I'll be attempting today.

    In the example below I'll be overloading the dos.library's Open() function. To prove it's doing its job, I'll be flashing the screen every time it's called, followed by jumping to the native, original Open() code afterwards.

    For those of you not fluent in 68k assembly, I've included some comments to outline the basics.

    ; exec.library:
    ; dos.library:
    	* Open dos.library
    	move.l 4.w,a6
    	lea dosname(pc),a1
    	moveq #0,d0
    	jsr _LVOOpenLibrary(a6)
    	lea dosbase(pc),a0
    	move.l d0,(a0)
    	* Store original function address
    	move.l d0,a6
    	lea _LVOOpen(a6),a0
    	lea jump(pc),a1
    	move.l 2(a0),2(a1)
    	* Prohibit multitasking and allocate memory
    	move.l 4.w,a6
    	jsr _LVOForbid(a6)
    	moveq #new_open_function_length,d0
    	moveq #MEMF_PUBLIC,d1
    	jsr _LVOAllocMem(a6)
    	bne.b .memOK
    	moveq #2,d1
    	bra.b .closeDos
    	* Copy code to allocated memory
    	move.l d0,a1
    	lea new_open_function(pc),a0
    	moveq #[new_open_function_length/2]-1,d1
    .copy:	move.w (a0)+,(a1)+
    	dbra d1,.copy
    	* SetFunction and permit multitasking
    	lea (_LVOOpen).w,a0
    	move.l 4.w,a6
    	move.l dosbase(pc),a1
    	jsr _LVOSetFunction(a6)
    	jsr _LVOPermit(a6)
    	* Close lib and exit
    	move.l dosbase(pc),a1
    	jsr _LVOCloseLibrary(a6)
    	moveq #0,d0
    	* My fake custom function
    	move.l #5000,d0
    .s:	move.w d0,$dff180
    	dbra d0,.s
    jump:	jmp $0
    dosbase:dc.l 0
    dosname:dc.b 'dos.library',0

    ...and that's it. We've successfully patched the ROM, and here it is in action to prove that it works. I'm running the program, and then loading a file, which consequentally triggers the Open() function in dos.library. As you can see, the screen flashes in many colors before loading the file.

    This is also an accidental step-by-step tutorial in case you want to write a virus for the Amiga. Just make it survive a reset and let Hell break loose. Or not. Please don't.

    But why do I want to patch the Kickstart in the first place? And why would I patch it before anything has been loaded or is running? Make a guess and wait for the next post. Bonus points if you get it right.

    Work in progress: APECAT


    Since I foolishly announced a minimum of one post per month, I'll do my best to keep my promise. This is why I'm lifting the curtains on my latest project: the APECAT.

    APECAT is short for Amiga Processor Expansion Card for Application Transfer, and yes, I totally made that acronym up. Apekatt in Norwegian, translated word-by-word, means ape and cat. But for some reason it means monkey, and monkeys are fun. That's basically as deep as it goes.

    This is work in progress as I'm still battling with a few minor bugs, but feel confident it will work eventually. I'll dig into the problems I'm experiencing further down this article.

    The APECAT is a small, minimalist board you sandwich between the Amiga's 68000 CPU and motherboard. Its purpose is to allow the user to send data from an external host, for example a PC or a Raspberry Pi, and have it uploaded directly into the Amiga's memory. It is in many ways similar to the C64FC, only for the Amiga 500.

    The goal is to be able to run software on an original Amiga, without using a floppy drive or hard drive at all. In fact, the Amiga I'm testing this on is just the motherboard. It doesn't even have a keyboard or a mouse attached.

    How will it run anything without any software in the first place?

    I have designed a hack for booting custom code from RAM, without the use of a floppy or hard drive. In short, it involves using the APECAT to stackbomb and interrupt the system ROM, followed by setting a reset-resident routine. This process takes less than a second. My custom code is then executed, which monitors the memory looking for flags set externally by the APECAT board. The basic principle has been tested and is confirmed working in the WinUAE Amiga emulator, but technical challenges has prevented me from running this on read hardware yet.

    So what's not working?

    The challenge is writing the data to RAM. I know this sounds like a deal breaker, but I strongly believe it's a minor issue and a consequence of not getting something right. I can freeze the CPU, point to a certain address in memory and write a value to it, but the value written is.. wrong. It seems almost random. I suspect this is due to one (or more) of these reasons:

    • The timing is wrong. My code is either too fast or too slow.
    • The order of write events are wrong. I'm doing things right, but not in the right order.
    • I've missed something, like toggling a line or gate. What have I overlooked?
    • The microcontroller I'm using is doing stuff I'm not aware of. Is the ICSP or something else disturbing things?
    • I'm lost in my own code. The code is quite complex and confusing at the moment.
    • I'm on a wild goose chase and this is whole project is impossible

    Have you ever done something similar? Have you experienced similar write bugs on the 68000, or another system? Any ideas what I might have left out, based on what you've read so far? Leave a comment, I'd love to hear from you if you have. Let's discuss this in detail and figure out what's wrong.

    I'm pretty close, though. As you can see from the image below, I'm bombarding the custom chipset at address $dff102, which is the horizontal scroll register. The addressing works, but the values written does not line up with what's expected. This obviously also works for other addresses, such as the background color, foreground color, bitplane pointers, etc. but this is the most convenient register to play with for visual confirmation.

    This is the state of the current board, as it almost works. Bodge wires to /BGACK and /AS was added, as they were left out in the design process. The damage on the board you see is the VCC trace from the CPU that has been cut, as it was redundant and caused problems.

    Wait, don't too carried away!

    This is no miracle device, it is nothing revolutionary. It cannot be used to real-time debug the Amiga. It cannot read anything from the CPU. It can upload shit to RAM, and at the time being, that's all it'll ever do.

    That doesn't make it any less exciting though, so stay tuned for updates. This will work soon, I know it.

    Happy New Year, my resolution, and then some.


    Okay, so 2018 wasn't quite the year for this blog. If I'm not mistaken, I managed to squeeze out one - yes one - post last year. My new year's resolution is a minimum of one post per month in 2019. Feel free to call me out if I fail to deliver.

    The reason I'm posting this is not just to point out how lazy I've been, but I want to emphasize someone who's not on the lazy side. But before I begin, let me stress that I'm not doing this for money or referrals, this is just me sharing my experience and excitement over a PCB manufacturer called AllPCB.

    Long story short: This Saturday I decided to get some new PCB's produced, so that I have something to work on for my January entry (no, this one doesn't count). I quickly looked around for some cheap manufacturers, and AllPCB popped up with an offer: $5 for 10 boards, $19 shipping with DHL. I couldn't resist the temptation, and placed an order. Keep in mind, we're still on Saturday. Today is Tuesday - three days later - and guess what? The package has arrived!

    Sure, DHL was fast (and they usually are) but looking over the order history at AllPCB, I can see that they manufactured and shipped the boards the same day as I placed the order. This is excellent service and you bet your ass I will place my next order with them as well.

    I'll bring a couple of boards + parts with me to work tomorrow, so I can populate them under better conditions than in my freezing cold shed. And, if everything goes right, I'll start testing it tomorrow night.

    Let's hope this project works and makes a cool post within the next few days.

    Add to Google