BB816 Computer YouTube Series

For discussing the 65xx hardware itself or electronics projects.
User avatar
akohlbecker
Posts: 282
Joined: 24 Jul 2021
Contact:

Re: BB816 Computer YouTube Series

Post by akohlbecker »

I've been working on getting the COP signature byte, no use case in mind just a fun challenge. Here is the code I came up with in emulation mode and in native mode.
I don't have the hardware to test it with me yet, which makes me think I need to work on an emulator for the project! I'll report back if any changes are needed.

One thing I'm not 100% sure of is bank crossing behavior. If we end up executing a COP at $FFFF, the next instruction from the CPU's point of view would be $0001, in the same program bank, right? That would make the signature byte $0000 in the same bank, and not in the next bank. I'm wondering because it prevents using stack relative indirect addressing to fetch the signature, since this addressing mode crosses over banks and so you can't just load Y with $FFFF to decrement the program counter.

Anyway, here is the code so far, only the COP sections:

Native mode

Code: Select all

; where each register is relative to the stack pointer after interrupt entry
int_native_stack_offset_pb = 13
int_native_stack_offset_pc = 11
int_native_stack_offset_p  = 10
int_native_stack_offset_db = 9
int_native_stack_offset_d  = 7
int_native_stack_offset_a  = 5
int_native_stack_offset_x  = 3
int_native_stack_offset_y  = 1

  +mx_16_bits
  lda int_native_stack_offset_pc,s ; get program counter
  dec                              ; decrement it by one to get to signature byte
                                   ; note: if COP is at $FFFF, then the signature byte
                                   ; is at $0000 in the same bank (TODO: verify with hardware)
  tax                              ; save this address to a 16 bits X
  +m_8_bits

  lda int_native_stack_offset_pb,s ; get program bank register
  phb                              ; save current data bank register
  pha                              ; and save the new one as data bank register
  plb                              ; so we load signature byte from the right bank

  lda+2 0,x                        ; load the 8 bit signature, from the right bank and with
                                   ; a 16 bit offset address
  +x_8_bits

  plb                              ; restore original data bank
  and # $ff                        ; ensure flags are set by the value of A
Emulation mode

Code: Select all

; where each register is relative to the stack pointer after interrupt entry
int_emu_stack_offset_pc = 5
int_emu_stack_offset_p  = 4
int_emu_stack_offset_a  = 3
int_emu_stack_offset_x  = 2
int_emu_stack_offset_y  = 1

  lda int_emu_stack_offset_pc+1,s  ; high byte program counter
  tax
  lda int_emu_stack_offset_pc,s    ; low byte program counter
  bne +                            ; decrement it by one to get to signature byte address
  dex
+ dec
  phx                              ; push new address to the stack
  pha
  ldy # 0
  lda (1,s),y                      ; load signature byte
  ply                              ; reset stack pointer
  ply
  and # $ff                        ; ensure flags are set by the value of A
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: BB816 Computer YouTube Series

Post by BigEd »

Quote:
If we end up executing a COP at $FFFF, the next instruction from the CPU's point of view would be $0001, in the same program bank, right? That would make the signature byte $0000 in the same bank, and not in the next bank
Indeed - the PC is 16 bits and only increments within that. The bank byte is independent.
User avatar
Proxy
Posts: 746
Joined: 03 Aug 2018
Location: Germany

Re: BB816 Computer YouTube Series

Post by Proxy »

having a multi-byte Instruction like COP split at the edge of a bank seems like a pretty rare scenario. unless the program is specifically written to make use of the PC wrapping... but even then it seems easier to just avoid split instructions like that.

anyways, my SBC's BIOS also uses COP for system calls because it's very convient and much easier to expand/move around in the ROM compared to jump tables accessed with JSL or Indirect Jumps.
but the way i get the signature byte is a bit different, as it loads the whole 24-bit address into a temporary DP location, subtracts 1 from it, and then uses the 24-bit Indirect Addressing mode to get the byte.
that way the code doesn't need to touch the data bank register.
The signature byte is then multiplied by 2 and put into X to be used as an index to a jump table. giving me 256 possible functions.

Code: Select all

COP_HANDLER:
    ai16                    ; 16-bit A/X/Y
    
    PHA
    PHX
    PHY
    TDC
    PHA                     ; Save all Registers (A, X, Y, DP)
    
    LDA #SYS_DP
    TCD                     ; Set the Driect Page
    
    accu8
    ; Get the Return Address, subtract 1 from it, and store it into a Temp Pointer
    LDA 10,S                ; Low Byte
    CLC
    SBC #0
    STA T_PTR
    LDA 11,S                ; Middle Byte
    SBC #0
    STA T_PTR+1
    LDA 12,S                ; High Byte
    SBC #0
    STA T_PTR+2
    
    LDA #0
    XBA                     ; Clear the High Byte of A
    LDA [T_PTR]             ; Get the Signature Byte
    ASL A                   ; Multiply it by 2
    TAX                     ; And put it into X
    
    PEA .LOWORD(COP_RET - 1)
    JMP (COP_TABLE,X)       ; Then use it as an index for the Jump Table

COP_RET:
    ai16                    ; 16-bit A/X/Y
    PLA
    TCD
    PLY
    PLX
    PLA                     ; Restore all Registers
RTI
the PEA infront of the Indirect JMP pushes the address of (COP_RET - 1) to the stack, basically just emulating an Indirect JSR instruction.
so all the COP functions can jump to that code by using RTS instead of a regular JMP.
User avatar
akohlbecker
Posts: 282
Joined: 24 Jul 2021
Contact:

Re: BB816 Computer YouTube Series

Post by akohlbecker »

BigEd wrote:
Indeed - the PC is 16 bits and only increments within that. The bank byte is independent.
Thanks for confirming!
Proxy wrote:
having a multi-byte Instruction like COP split at the edge of a bank seems like a pretty rare scenario. unless the program is specifically written to make use of the PC wrapping... but even then it seems easier to just avoid split instructions like that.
Agreed, don't plan on intentionally writing a split instruction, just want to make sure the behavior is well defined in edge cases.
Proxy wrote:
anyways, my SBC's BIOS also uses COP for system calls because it's very convient and much easier to expand/move around in the ROM compared to jump tables accessed with JSL or Indirect Jumps.
but the way i get the signature byte is a bit different, as it loads the whole 24-bit address into a temporary DP location, subtracts 1 from it, and then uses the 24-bit Indirect Addressing mode to get the byte.
that way the code doesn't need to touch the data bank register.
Thanks for sharing your code, it was nice to see another approach.

Any reason for using TDC+PHA/PLA+TCD instead of PHD/PLD?
User avatar
Proxy
Posts: 746
Joined: 03 Aug 2018
Location: Germany

Re: BB816 Computer YouTube Series

Post by Proxy »

akohlbecker wrote:
Any reason for using TDC+PHA/PLA+TCD instead of PHD/PLD?
because i didn't know or forgot those instructions existed :oops:
User avatar
BigEd
Posts: 11464
Joined: 11 Dec 2008
Location: England
Contact:

Re: BB816 Computer YouTube Series

Post by BigEd »

For info on 816 fine details and corner cases, see Bruce's major document
Post Reply