The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
Re: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
Very impressed with this, great for my new project where I needed to clear the sprites at at the bottom of the screen as I pushed the sprite drawing to the limit. I normally either redraw the entire screen from a back buffer or clear after a halt before plot if fast enough. That wasn't working for this so I started with an arbitrary wait loop which was tricky to get right if the number of sprites fluctuated. This seems to have solved that.
Any chance you could share your code to check if 48k/128k or +2A/+3 and how you modify the code for each?
At the moment I'm using the method you put on WoS
ld a,(2899) ;+2A/+3 ROMs return 126
cp 126
jr z,its_a_plus
and I just flip between the two versions of the fl_bus code.
Thanks in advance.
TomD
Any chance you could share your code to check if 48k/128k or +2A/+3 and how you modify the code for each?
At the moment I'm using the method you put on WoS
ld a,(2899) ;+2A/+3 ROMs return 126
cp 126
jr z,its_a_plus
and I just flip between the two versions of the fl_bus code.
Thanks in advance.
TomD
Retro enthusiast and author of Flynn's Adventure in Bombland, The Order of Mazes & Maze Death Rally-X. Check them out at http://tomdalby.com
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
The above is exactly what I use in my real-world code for machine detection. The vanilla code is written for the +2A/+3, so the its_a_plus label just jumps forward without modifying anything. If the condition is not met, then I modify the floating bus sync code:TomD wrote: ↑Mon Jun 01, 2020 10:15 pm Any chance you could share your code to check if 48k/128k or +2A/+3 and how you modify the code for each?
At the moment I'm using the method you put on WoS
ld a,(2899) ;+2A/+3 ROMs return 126
cp 126
jr z,its_a_plus
and I just flip between the two versions of the fl_bus code.
Code: Select all
ld hl,v_sync+2
ld (hl),$2b ;opcode for the DEC HL instruction [6]
ld (v_sync_sw+1),hl ;redirect the JP NZ,** to DEC HL
ld a,$40 ;change top half of port addr (must be in the $40–$7f range)
ld (port1+1),a
ld a,$ff ;change bottom half of port addr
ld (port2+1),a
Code: Select all
port1 ld de,$xx0f ;ATTR color (xx) into D, top half of port to read into E
v_sync ld a,($5800) ;[13]point to contended memory and fetch a "blanking" attr
;or DEC HL [6] for the 48K/128K/+2
ld a,e ;[4]top half of port into A
port2 in a,($fd) ;[11]read port formed by A (MSB) and FDh (LSB) into A
cp d ;[4]test for ATTR color
v_sync_sw jp nz,v_sync ;[10]
Code: Select all
port1 ld de,$xx40 ;ATTR color (xx) into D, top half of port to read into E
v_sync ld a,($2b00) ;this makes no sense, but we’re only interested in the third byte,
;which is the opcode for the DEC HL instruction
ld a,e ;[4]top half of port into A
port2 in a,($ff) ;[11]read port formed by A (MSB) and FFh (LSB) into A
cp d ;[4]test for ATTR color
v_sync_sw jp nz,v_sync+2 ;[10]note the changed jump address
Code: Select all
SMC_v_sync dec hl ;[6]the padding instruction necessary for syncing
ld a,e ;[4]top half of port into A
port2 in a,($ff) ;[11]read port formed by A (MSB) and FFh (LSB) into A
cp d ;[4]test for ATTR color
v_sync_sw jp nz,SMC_v_sync ;[10]jumping to the last byte of the “nonsensical” LD A,($2B00) instruction
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: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
Many thanks, I went with the following so it does the check on the fly rather than SMC, guess not great if you change the ROM in the middle of the program but I'm not planning on doing that
One thing I did notice is the +2/+3 routine doesn't work on the Next (using Next/+3 mode). Works fine if you select 128k or Usr 0 mode though so not a major issue.
TomD
Code: Select all
; ==========================================+==================================
; floating bus wait routines (35b)
; ------------------------------------------+----------------------------------
; _fl_bus is for Sinclair 48/128k & Amstrad +2 (taken from sidewize)
; _fl2_bus is for Amstrad +2A/B & +3 (by Ast A. Moore)
; ==========================================+==================================
_fl_bus:
ld a,($0b53) ; 13t - +2A/+3 ROMs return 126
cp $7e ; 7t
jr z,_fl2_bus ; 12/7t
ld bc,$40ff ; 10t - port
ld e,$18 ; 7t - attr to compare to
_fl_bus100:
ld a,r ; 4t
in a,(c) ; 12t
cp e ; 4t - is it >=check attr
jp nc,_fl_bus100 ; 10t - loop till <
ret ; 10t
_fl2_bus:
ld de,$180f ; 10t - attr into d, MSB of port addr into e
_fl2_bus100:
ld a,($5800) ; 13t - point to contended memory and fetch a "blanking" attr
ld a,e ; 4t - MSB of port addr into a
in a,($fd) ; 11t - read port $0ffd into a
cp d ; 4t - is it >=check attr
jp nc,_fl2_bus100 ; 10t - loop till <
ret ; 10t
Retro enthusiast and author of Flynn's Adventure in Bombland, The Order of Mazes & Maze Death Rally-X. Check them out at http://tomdalby.com
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
I’m not familiar with the Next well enough to comment, but keep in mind that on a real +2A/+3, the trick only works if paging hasn’t been explicitly disabled (i.e. it won’t work in 48K BASIC mode).
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: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
Next/+3 mode runs with +3 timings and the NextZXOS ROMs, which are significantly different from the +3 ROMs, given that they’re entirely rewritten with new NextBASIC functionality for new machine features. This tape loading mode is meant for loading new Next programs rather than for compatibility. So reading an arbitrary ROM byte in this mode isn’t a particularly good way to detect +3 timings.
Some of the other modes are intended for compatibility: 48K mode runs with 48K timings and the original 48K ROMs, with Next And 128K features disabled; 128K mode runs with 128K timings Bd the original 128K ROMs, with Next features disabled. Pentagon mode runs with Pentagon timings, and Pentagon/Profi paging. USR0 mode is not really a compatibility mode, it runs in +3 timings with Next features after invoking USR0.
It happens that there isn’t a dedicated +3 compatibility mode yet, because there is insufficient space to hold all 64K of alternate +3ROMs in the memory map. Alternate ROMs are a relatively new feature that avoided the need to endlessly patch the NextZXOS ROMs for compatibility with a succession of individual games. There was only 32K available to give to the scheme though, so it hasn’t yet been implemented for +2A/+3. This could change later after some other things have been reorganised.
As I said earlier in the thread, don’t get too hung up on expecting every program to work in every mode. The modes are pragmatic tools to let every program run in at least one common configuration, with some extra advanced options and manually applied disables to further tweak the environment where needed.
Some of the other modes are intended for compatibility: 48K mode runs with 48K timings and the original 48K ROMs, with Next And 128K features disabled; 128K mode runs with 128K timings Bd the original 128K ROMs, with Next features disabled. Pentagon mode runs with Pentagon timings, and Pentagon/Profi paging. USR0 mode is not really a compatibility mode, it runs in +3 timings with Next features after invoking USR0.
It happens that there isn’t a dedicated +3 compatibility mode yet, because there is insufficient space to hold all 64K of alternate +3ROMs in the memory map. Alternate ROMs are a relatively new feature that avoided the need to endlessly patch the NextZXOS ROMs for compatibility with a succession of individual games. There was only 32K available to give to the scheme though, so it hasn’t yet been implemented for +2A/+3. This could change later after some other things have been reorganised.
As I said earlier in the thread, don’t get too hung up on expecting every program to work in every mode. The modes are pragmatic tools to let every program run in at least one common configuration, with some extra advanced options and manually applied disables to further tweak the environment where needed.
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: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
* Oops, I said it in another Next thread somewhere else on this forum, not earlier in this thread. Soz.
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: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
the emulation it is not completely right (i think), but ZXEmuT now can run Yankee in +2A/+3 mode! ;-)
thank you for your hard work, and for detailed explanations!
thank you for your hard work, and for detailed explanations!
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
Glad you found my little writeup useful! When I was helping Mark Woodmass to perfect the timings in SpecEmu, I made a special version of my test for him. Feel free to use it, tweak your emulator, and compare the results with this 50 fps video of my +2A running it. You can advance the video frame by frame and make sure the vertical shifts in the black gaps of the yellow border alight with the correct vertical white bars. Mark was able to nail it with the help of my test.
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: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
thank you even more! ;-)
for now it looks like my contention pattern for +2A is totally broken (no wonder, ZXEmuT couldn't properly run +2A/+3 at all until yesterday ;-), and Yankee works due to very specific timings. your test will definitely help to fix it all.
for now it looks like my contention pattern for +2A is totally broken (no wonder, ZXEmuT couldn't properly run +2A/+3 at all until yesterday ;-), and Yankee works due to very specific timings. your test will definitely help to fix it all.
Re: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
OK, so I had this working fine until I started messing around with interrupts - with IM2 enabled, the game locks up and the debugger shows it's stuck in the "floating_bus_loop" (see below).
At first I thought it might be because I hadn't DI / EI 'd either side of the code, but even after adding them it still locks up.
Any idea why this is happening?
(My interrupt code just cycles the border colour through 0-7 at the moment - a simple test routine, so that I can see it's being called successfully. Removing the bit of code which changes the border doesn't fix things either!)
At first I thought it might be because I hadn't DI / EI 'd either side of the code, but even after adding them it still locks up.
Any idea why this is happening?
(My interrupt code just cycles the border colour through 0-7 at the moment - a simple test routine, so that I can see it's being called successfully. Removing the bit of code which changes the border doesn't fix things either!)
Code: Select all
DI
LD D, 8 ; attr: PAPER 1, INK 0
LD E, $40 ; MSB of port address ($40FF)
floating_bus_loop:
DEC HL ;[6]padding instruction
LD A,E ;[4]MSB of port addr into A
IN A,($FF) ;[11]read port 0x40FF into A
CP D ;[4]is it D (i.e. INK 1, PAPER 1, BRIGHT 0; FLASH 0)?
JP NZ, floating_bus_loop ;[10]no? keep trying
; Found it!
EI
Re: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
Still mega stumped by this!
I took a backup before I started messing with the interrupts, so I rolled back to that working version.
Ended up in the same situation - interrupt routine runs fine, but gets stuck in the floating bus loop and never "catches" the target value...
Added DI/EI either side - no effect.
Removed the border colour changing part of the interrupt routine again (in case my OUT (254), colour was messing with things) - no effect.
Same behaviour in Spectaculator & ZX Spin (emulating a +2 throughout development) so not convinced it's an emulator "feature" (also as it's the old "tried & tested" rather than the new +2A/+3 method)
Are there any caveats regarding interrupts, interrupt modes, etc I've overlooked?
I took a backup before I started messing with the interrupts, so I rolled back to that working version.
Ended up in the same situation - interrupt routine runs fine, but gets stuck in the floating bus loop and never "catches" the target value...
Added DI/EI either side - no effect.
Removed the border colour changing part of the interrupt routine again (in case my OUT (254), colour was messing with things) - no effect.
Same behaviour in Spectaculator & ZX Spin (emulating a +2 throughout development) so not convinced it's an emulator "feature" (also as it's the old "tried & tested" rather than the new +2A/+3 method)
Are there any caveats regarding interrupts, interrupt modes, etc I've overlooked?
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
Hmm. Could you post the entire code (well, the relevant portions) so I could test it? The only reason for it not to be working I can think of off the top of my head is that it’s sitting somewhere in contended memory (including the respective RAM banks).
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: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
Sure, my interrupt is set up at the very beginning like so:
The interrupt itself is:
Interrupt table is 257 bytes of $66. Interrupt runs fine and produces the desired headache-inducing border effect.
The floating bus loop is at $B187 and was working right up until I added the above bits of code in.
Code: Select all
; Set up interrupts
DI
LD A, $65 ; Interrupt table at page $6500
LD I, A ; Set the interrupt register to that page
IM 2 ; Set the interrupt mode
EI ; Enable interrupts
Code: Select all
ORG $6666 ; 26214
INTERRUPT:
DI
PUSH AF
PUSH BC
PUSH DE
PUSH HL
EXX
PUSH AF
PUSH BC
PUSH DE
PUSH HL
EXX
PUSH IX
PUSH IY
; --- Main interrupt routine --- ;
; Update border colour
LD HL, intrpt_test
INC (HL)
LD A, (HL)
AND 7
OUT (254), A
; --- End of main interrupt routine --- ;
POP IY
POP IX
EXX
POP HL
POP DE
POP BC
POP AF
EXX
POP HL
POP DE
POP BC
POP AF
EI
RET
intrpt_test:
DB 0
The floating bus loop is at $B187 and was working right up until I added the above bits of code in.
-
- Microbot
- Posts: 132
- Joined: Tue Jun 09, 2020 6:14 am
- Contact:
Re: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
If it's not a typo, chances are you're testing for a different attr value rather than the one you put onscreen.presh wrote: ↑Sun Sep 06, 2020 9:43 pmCode: Select all
LD D, 8 ; attr: PAPER 1, INK 0 <...> CP D ;[4]is it D (i.e. INK 1, PAPER 1, BRIGHT 0; FLASH 0)?
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
Either that, or the tested area is not wide enough for the loop to catch it. Make sure you have enough consecutive cells with the desired attributes. Depending on which machine you run this on (48K/128K), the loop will take a different amount of time to sync up. To be on the safe side, I recommend setting the same attribute value for an entire row.Nienn Heskil wrote: ↑Wed Sep 09, 2020 8:12 pmIf it's not a typo, chances are you're testing for a different attr value rather than the one you put onscreen.presh wrote: ↑Sun Sep 06, 2020 9:43 pmCode: Select all
LD D, 8 ; attr: PAPER 1, INK 0 <...> CP D ;[4]is it D (i.e. INK 1, PAPER 1, BRIGHT 0; FLASH 0)?
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.
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
Yes, your interrupt vector is pointing to the contended RAM area ($40–$7f). This will trigger the ULA snow effect. You should always make sure it’s outside that range. The ISR itself can sit anywhere in RAM, but the interrupt vector table must reside in non-contended RAM.
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: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
Haha, yes. Those are [mention]Ast A. Moore[/mention]'s original comments which I hadn't updated! Well spottedNienn Heskil wrote: ↑Wed Sep 09, 2020 8:12 pmIf it's not a typo, chances are you're testing for a different attr value rather than the one you put onscreen.presh wrote: ↑Sun Sep 06, 2020 9:43 pmCode: Select all
LD D, 8 ; attr: PAPER 1, INK 0 <...> CP D ;[4]is it D (i.e. INK 1, PAPER 1, BRIGHT 0; FLASH 0)?
Re: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
Ah! Another one of those "quirks" I've heard about but never encountered and thus forgotten. Thanks for the explanation. I shall attempt to find room up there, but it's pretty... RAMmedAst A. Moore wrote: ↑Wed Sep 09, 2020 10:08 pmYes, your interrupt vector is pointing to the contended RAM area ($40–$7f). This will trigger the ULA snow effect. You should always make sure it’s outside that range. The ISR itself can sit anywhere in RAM, but the interrupt vector table must reside in non-contended RAM.
Re: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
Having read through this thread and your webpage am I right in thinking that your code loop will catch one of the attribute bytes on the relevant row, but you can't be sure which one? And is it also the case that you're not 100% sure why this 35 t-state loop only catches attributes?Ast A. Moore wrote: ↑Wed Sep 09, 2020 9:59 pmEither that, or the tested area is not wide enough for the loop to catch it. Make sure you have enough consecutive cells with the desired attributes. Depending on which machine you run this on (48K/128K), the loop will take a different amount of time to sync up. To be on the safe side, I recommend setting the same attribute value for an entire row.
- Ast A. Moore
- Rick Dangerous
- Posts: 2641
- Joined: Mon Nov 13, 2017 3:16 pm
Re: The Definitive Programmer’s Guide to Using the Floating Bus Trick on the ZX Spectrum
True, you can’t be absolutely sure which attribute cell the loop will catch, but if I remember correctly, an entire row is certainly overkill. However, it would be difficult to set up a test that would reveal the exact pattern definitively. Moreover, I suspect that the exact timing of the triggering will depend on the length of the instructions preceding the sync loop and will thus be pretty much unpredictable.DoctorRad wrote: ↑Wed Mar 27, 2024 2:55 pm Having read through this thread and your webpage am I right in thinking that your code loop will catch one of the attribute bytes on the relevant row, but you can't be sure which one? And is it also the case that you're not 100% sure why this 35 t-state loop only catches attributes?
As for why the loop takes the number of T states it does (note that it’ll differ on different Spectrum models), you’re right, I can’t fully explain it. I ran a few dozen tests with different padding instructions and the example outlined in my writeup is just the quickest one that works. It’s reasonable to assume that using another padding instruction (or, indeed, instructions) will let you be more precise in picking and choosing the exact attribute location at the expense of causing a significant delay (for example, you may be limited to just a single attribute per two or more rows). I’d argue it is possible to create a very sophisticated timing pattern for several consecutive loops (each with its own timing) and get very precise indeed. However practical that would be, I am not certain.
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.