A clever method of using a single 8-bit register to be used for two things at a time

edited January 2011 in Development
I don't know if this is the way the SAVE routine in the Spectrum works. Anyway, this is what I've learned today.

I've been commented the disassembly of the "save_bytes" routine of the Jupiter ACE. Everything was more or less "familiar": pilot tone, sync pulses, and then...

I tried to understand the logic behind the piece of code that outputs the required pulses for a '1' bit or '0' bit within the byte that is being transferred to the MIC output. It was tought to me because, although I quickly found the RL instruction that supposely shifts each bit in a byte so it can be translated into pulses, I couldn't figure the structure of the loop that is assumed to be repeated 8 times. In short: I didn't found a register that holds 8, and in each turn, decreases its value and then, conditionaly jumps to the RL instruction.

The answer is: a single 8-bit register (L) holds both the byte that is being outputted to MIC, and the counter of bits outputted.

How does it perform this? At first, L holds the byte to transfer.
Then just before entering the "transfer bit" loop, the carry is set (SCF).
Then, a RL L instruction. This instruction loads whatever it is in the carry to the bit 0 of L, and the bit 7 of L is transferred to the CF flag. The first time RL L is executed, a '1' is loaded into bit 0 of L.
So, regardless of the initial value of L, as long as there are bits left to transfer, the L register is not 0.
So, everytime we executed RL L, and as long as only the first time we execute it, the CF is set, and the remainder times is reset, we obtain:
- If ZF is set, the byte has already been trasferred. If it is not set, then read CF to know the value of the bit that is about to be outputted to MIC.

The code is more or less like this:
;L is the byte to be outputted to MIC
SA_BYTE
    SCF
SA_BIT:
    RL L
    JR Z,END_BYTE
    JR NC,SEND_ZERO
    ;Send ONE
    ;Make sure CF is reset before the jump
    JR SA_BIT
END_BYTE:
    ;Other stuff... load next byte and so on...
SEND_ZERO:
    ;Stuff required to send ZERO
    ;Make sure CF is reset before the jump
    JR SA_BIT
Post edited by mcleod_ideafix on

Comments

  • edited January 2011
    I don't know if this is the way the SAVE routine in the Spectrum works.

    It works in exactly the same way.
  • edited January 2011
    The answer is: a single 8-bit register (L) holds both the byte that is being outputted to MIC, and the counter of bits outputted.

    How does it perform this? At first, L holds the byte to transfer.
    Then just before entering the "transfer bit" loop, the carry is set (SCF).
    Then, a RL L instruction. This instruction loads whatever it is in the carry to the bit 0 of L, and the bit 7 of L is transferred to the CF flag. The first time RL L is executed, a '1' is loaded into bit 0 of L.
    So, regardless of the initial value of L, as long as there are bits left to transfer, the L register is not 0.
    So, everytime we executed RL L, and as long as only the first time we execute it, the CF is set, and the remainder times is reset, we obtain:
    - If ZF is set, the byte has already been trasferred. If it is not set, then read CF to know the value of the bit that is about to be outputted to MIC.

    It's called a "marker bit", a common technique I talked about 7 years ago in my very first article for MagazineZX. See here (spanish):
    http://www.speccy.org/wiki/programacion/ensamblador/compresor_tapc
  • edited January 2011
    Metalbrain wrote: »
    It's called a "marker bit", a common technique I talked about 7 years ago in my very first article for MagazineZX. See here (spanish):
    http://www.speccy.org/wiki/programacion/ensamblador/compresor_tapc

    In your article, the C register is used "solely" for one role: to have a counting of how many bits to process. This routine uses L with two roles: to have a counting of how many bits to process AND to have the value whose bits are being written to the tape. One normally would use two registers to acomplish this: one to count (either with a marking bit or with a descendant counter) and another one to hold the value being written to the tape. The use of a single register to perform these two roles at the same time is the thing that I have spotted here.
  • edited January 2011
    Very clever indeed. There are some pretty devious tricks in the ROM code!
  • edited January 2011
    In your article, the C register is used "solely" for one role: to have a counting of how many bits to process. This routine uses L with two roles: to have a counting of how many bits to process AND to have the value whose bits are being written to the tape. One normally would use two registers to acomplish this: one to count (either with a marking bit or with a descendant counter) and another one to hold the value being written to the tape. The use of a single register to perform these two roles at the same time is the thing that I have spotted here.

    In the decoder routine I analyze in my article, (IX) holds both the data that is being read bit by bit, and also the marker bit to mark the end of the current byte, preventing its value to become 0 until the marker goes out (exactly the same as ROM load routine). The second marker bit, this time in register C, is preloaded at a certain position to count how many bits we want to put into that very same C register, so the C register is also playing two roles.
  • edited January 2011
    One of loading routines ("shavings slow") of an old versi?n of k7zx used an 8 bit-register for three purposes:
    -counting 8 times the incoming bit (in fact 4 times 2 bits)
    -save incoming bits
    -calculate color for the loading strips efect on screen's BORDER (red and magenta).
Sign In or Register to comment.