Easiest way to change AY I/O ports in a game?

The place for codemasters or beginners to talk about programming any language for the Spectrum.
Post Reply
User avatar
zxbruno
Manic Miner
Posts: 214
Joined: Sun Mar 04, 2018 6:13 am

Easiest way to change AY I/O ports in a game?

Post by zxbruno »

Was looking at this list:

http://zxspectrum48.i-demo.pl/48K_AY_games.html

And then it occurred to me how wonderful it would be if these games could be played on a Timex TS2068 or TC2068 with a Spectrum emulator cartridge. These computers have an internal AY chip but it's mapped to different I/O ports. Back in the day some people modified a few games so they could enjoy AY sound on Timex computers, and uploaded those games on the TS2068 Yahoo group which is not longer hosting content. There are over 100 games on that list. What should I be looking for if I wanted to modify the I/O ports?
User avatar
Seven.FFF
Manic Miner
Posts: 744
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Easiest way to change AY I/O ports in a game?

Post by Seven.FFF »

The SpecEmu emulator debugger allows you to set breakpoints on writes to specific I/O ports. Spin and Zeus-ish also allow you to write breakpoint expressions which can involve I/O ports.

You’re probably looking for the two OUTs here. Possibly the IN too although that’s a lot less likely. The general pattern is for programs to select a register first then immediately write a value to the selected register.

Sound Chip
The AY-3-8912 sound chip is a widely used one, to be found in the MSX, Vectrex, Amstrad CPC range, etc. It is controlled by two I/O ports:
OUT (0xfffd) - Select a register 0-14
IN (0xfffd) - Read the value of the selected register
OUT (0xbffd) - Write to the selected register
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
User avatar
djnzx48
Manic Miner
Posts: 730
Joined: Wed Dec 06, 2017 2:13 am
Location: New Zealand

Re: Easiest way to change AY I/O ports in a game?

Post by djnzx48 »

Not solely those ports, but they're likely used more often than others. Different ports allow the use of instructions such as out ($fd), a which can be useful for saving T-states.
Alcoholics Anonymous
Microbot
Posts: 194
Joined: Mon Oct 08, 2018 3:36 am

Re: Easiest way to change AY I/O ports in a game?

Post by Alcoholics Anonymous »

I made a number of conversions to the ts2068 many years ago that were originally uploaded to nvg. The nvg archive is still available:

ftp://ftp.nvg.ntnu.no/pub/sinclair/snaps/games/ts2068/

Some of them I put notes in as to how the programs were modified. Unfortunately many at the link above are multiloaders converted to work on a specific disk system and the source code is generally in the files on disk.

But the process is fairly easy. I'd always look for "LD BC,0xBFFD", "LD BC,0xFFFD" or "OUT (C),A" and the few ay routines would be easy to spot. You can do this search of three consecutive bytes using most emulators. Then you'd just change the port numbers to 0xF5 and 0xF6. I also went to the trouble of throwing away every sixth interrupt in some of the games. The music usually plays on the interrupt which was 60Hz on the ts2068 versus 50Hz on the 128k spectrum. So on the ts2068, the tune will play a bit faster. I'm not sure it was really necessary to do that though.
User avatar
zxbruno
Manic Miner
Posts: 214
Joined: Sun Mar 04, 2018 6:13 am

Re: Easiest way to change AY I/O ports in a game?

Post by zxbruno »

Thank you. It's great to know those modified games are still hosted somewhere.

If I wanted to search for those LD and OUT commands just by PEEKing the RAM, what decimal values would I be looking for? And once I had the decimal address, how would I modify the ports if I just wanted to use POKEs?

As someone who doesn't know machine code and only "thinks" in decimal, the above is easier for me. :/
User avatar
Ast A. Moore
Rick Dangerous
Posts: 2641
Joined: Mon Nov 13, 2017 3:16 pm

Re: Easiest way to change AY I/O ports in a game?

Post by Ast A. Moore »

zxbruno wrote: Sun Nov 17, 2019 3:36 pm If I wanted to search for those LD and OUT commands just by PEEKing the RAM, what decimal values would I be looking for? And once I had the decimal address, how would I modify the ports if I just wanted to use POKEs?
Because of duality between code and data, you can’t simply use PEEK to find a particular value; you’ll get a ton of false positives. Ideally, you’ll want to look at a disassembly and see what code surrounds a particular instruction.

However, it doesn’t hurt to try it your way. The opcode for the LD BC,** instruction is 01. Sixteen-bit operands are read low byte first. So, LD BC,0xBFFD would be written as three bytes as follows: 01 FD BF. FD is 253 in decimal; BF is 191. So, look for the sequence of three values: 1, 191, 253. Similarly, LD BC,0xFFFD translates to 1, 255, 253.

You’ll need to replace LD BC, 0xBFFD (01 FD BF or 1, 191, 253) with LD BC,0xFFF6 (01 F6 FF or 1, 246, 255), and LD BC, 0xFFFD (01 FD FF or 1, 255, 253) with LD BC,0xFFF5 (01 F5 FF or 1, 245, 255).

But there are more than one way to skin a cat, and programmers can employ different techniques to achieve the same goal.

For example, there are several OUT instructions (depending on which register is used as the source, and each has a different opcode: OUT (C),D is ED 51 (they’re all two-byte instructions), OUT (C),E is ED 59, OUT (C),H is ED 59, and so on.
Every man should plant a tree, build a house, and write a ZX Spectrum game.

Author of A Yankee in Iraq, a 50 fps shoot-’em-up—the first game to utilize the floating bus on the +2A/+3,
and zasm Z80 Assembler syntax highlighter.
User avatar
Seven.FFF
Manic Miner
Posts: 744
Joined: Sat Nov 25, 2017 10:50 pm
Location: USA

Re: Easiest way to change AY I/O ports in a game?

Post by Seven.FFF »

This is why using a suitable emulator to break on outs to particular ports is a good beginner’s way to start. It takes care of most of the pitfalls, and if you change them with pokes one at a time, you can keep doing this till a) everything works and b) it doesn’t break any mode.

But inevitably you always do need to be a tiny bit of a programmer to interpret the opcodes in the correct context so you can make your pokes. But this is something you can teach yourself as you go. Being able to see a partial disassembly in the debugger surrounding the breakpoints really helps.
Robin Verhagen-Guest
SevenFFF / Threetwosevensixseven / colonel32
NXtel NXTP ESP Update ESP Reset CSpect Plugins
Alcoholics Anonymous
Microbot
Posts: 194
Joined: Mon Oct 08, 2018 3:36 am

Re: Easiest way to change AY I/O ports in a game?

Post by Alcoholics Anonymous »

As mentioned, it is true you can never be certain that you've found what you're looking for by finding a specific three byte sequence. In practice, though, there aren't a lot of matches to sift through. You do have to look at the surrounding code to see if the code makes sense to be sure you've actually found what you're looking for. There are a few different ways to send data to the ay too so there's also no such thing as one patch fits all.

Trapping OUTs is a better way if the emulator can do it but I did this a long time ago before such niceties existed.
Post Reply