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?
Easiest way to change AY I/O ports in a game?
Re: Easiest way to change AY I/O ports in a game?
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
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
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
Re: Easiest way to change AY I/O ports in a game?
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.
-
- Microbot
- Posts: 194
- Joined: Mon Oct 08, 2018 3:36 am
Re: Easiest way to change AY I/O ports in a game?
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.
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.
Re: Easiest way to change AY I/O ports in a game?
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. :/
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. :/
- 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?
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.
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.
Re: Easiest way to change AY I/O ports in a game?
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.
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
SevenFFF / Threetwosevensixseven / colonel32
NXtel • NXTP • ESP Update • ESP Reset • CSpect Plugins
-
- Microbot
- Posts: 194
- Joined: Mon Oct 08, 2018 3:36 am
Re: Easiest way to change AY I/O ports in a game?
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.
Trapping OUTs is a better way if the emulator can do it but I did this a long time ago before such niceties existed.