hoglet67 / PiTubeDirect

Bare-metal Raspberry Pi project that attaches to the Acorn TUBE interface and emulates many BBC Micro Co Processors
GNU General Public License v3.0
187 stars 23 forks source link

Frame Buffer: *HELP MOS loops forever #143

Closed hoglet67 closed 2 years ago

hoglet67 commented 2 years ago

This is because the *HELP code in the MOS reads the POS VDU variable directly.

hoglet67 commented 2 years ago

This is the code in the MOS that does the padding required to output *HELP MOS nicely into multiple columns, each 20 characters wide.

The cause of this bug is that the *HELP MOS code directly accesses the VDU variable POS (the X location of the cursor), and this is not being updated when output is redirected to the Pi VDU driver.

    JSR LE25C       X = Window Right - Window Left
    CPX #&13        Exactly 20 characters wide?
    BEQ L9EEF       Force a newline
.L9ECB
    JSR LE252       X = POS, Y = VPOS
    TXA
    BEQ L9EA0       POS of 0 means we have already wrapped, so handle next item (this works in the 80 col case)
    CPX #&14
    BEQ L9EA0       POS of 20 means we are done padding, so handle next item
    BCC L9EE4       POS of <20 means more padding to do
    CPX #&28
    BEQ L9EA0       POS of 40 means we are done padding, so handle next item
    BCS L9EE9       POS > 40
    JSR LE25C       X = Window Right - Window Left
    CPX #&27        Exactly 40 characters wide?
    BEQ L9EEF
.L9EE4
    JSR L9F0C       Print Space
    BRA L9ECB

.L9EE9
    CPX #&3C
    BCC L9EE4       POS of <60 means more padding to do
    BEQ L9EA0       POS of 60 means we are done padding, so handle next tiem
.L9EEF
    JSR L9F1E       Force a newline
    BRA L9EA0       handle next item
hoglet67 commented 2 years ago

This is the section of MOS code the loops forever, captured using ICE-65C02:

14.089772 : 9ECB : 20 52 E2 : JSR $E252
14.089778 : E252 : 20 6D E2 :    JSR $E26D
14.089784 : E26D : A9 02    :       LDA #$02
14.089786 : E26F : A0 10    :       LDY #$10                ; access &0318 (X)
14.089788 : E271 : A2 00    :       LDX #$00                ; subtract &0308 (window left)
14.089790 : E273 : 20 8A E2 :       JSR $E28A
14.089796 : E28A : 38       :          SEC
14.089798 : E28B : 2C 66 03 :          BIT $0366            ; test bit 1 of VDU 23,16 setting
14.089802 : E28E : F0 0B    :          BEQ $E29B
14.089805 : E29B : B9 08 03 :          LDA $0308,Y
14.089809 : E29E : FD 08 03 :          SBC $0308,X
14.089813 : E2A1 : 60       :          RTS
14.089819 : E276 : 48       :       PHA                     ; push POS
14.089822 : E277 : A9 04    :       LDA #$04
14.089824 : E279 : C8       :       INY                     ; access &0319 (Y)
14.089826 : E27A : A2 03    :       LDX #$03                ; subtract &030B (window top)
14.089828 : E27C : 20 8A E2 :       JSR $E28A
14.089834 : E28A : 38       :          SEC
14.089836 : E28B : 2C 66 03 :          BIT $0366            ; test bit 2 of VDU 23,16 setting
14.089840 : E28E : F0 0B    :          BEQ $E29B
14.089843 : E29B : B9 08 03 :          LDA $0308,Y
14.089847 : E29E : FD 08 03 :          SBC $0308,X
14.089851 : E2A1 : 60       :          RTS
14.089857 : E27F : AA       :       TAX                     ; X = VPOS
14.089859 : E280 : A8       :       TAY                     ; Y = VPOS
14.089861 : E281 : A9 08    :       LDA #$08
14.089863 : E283 : 2C 66 03 :       BIT $0366               ; test bit 3 of VDU 23,16 setting
14.089867 : E286 : F0 24    :       BEQ $E2AC
14.089870 : E2AC : FA       :       PLX                     ; X = POS
14.089874 : E2AD : 60       :       RTS
14.089880 : E255 : 2C 6C 03 :    BIT $036C                  ; b7 set when cursor off righthand edge of screen
14.089884 : E258 : 10 01    :    BPL $E25B
14.089887 : E25B : 60       :    RTS
14.089893 : 9ECE : 8A       : TXA                           ; A = POS
14.089895 : 9ECF : F0 CF    : BEQ $9EA0
14.089897 : 9ED1 : E0 14    : CPX #$14
14.089899 : 9ED3 : F0 CB    : BEQ $9EA0                     ; A = 20
14.089901 : 9ED5 : 90 0D    : BCC $9EE4
14.089904 : 9EE4 : 20 0C 9F : JSR $9F0C                     ; Print a space
14.089910 : 9F0C : A9 20    :    LDA #$20
14.089912 : 9F0E : DA       :    PHX
14.089915 : 9F0F : A6 B0    :    LDX $B0
14.089918 : 9F11 : DA       :    PHX
14.089921 : 9F12 : A6 B1    :    LDX $B1
14.089924 : 9F14 : 20 EE FF :    JSR $FFEE
14.089930 : FFEE : 6C 0E 02 :       JMP ($020E)
14.089936 : 0900 : 48       :       PHA
14.089939 : 0901 : A9 03    :       LDA #$03only on the Pi VDU dsriver,
14.089941 : 0903 : 8D E2 FE :       STA $FEE2
14.089945 : 0906 : 68       :       PLA
14.089949 : 0907 : 8D E4 FE :       STA $FEE4
14.089953 : 090A : 60       :       RTS
14.089959 : 9F17 : 86 B1    :    STX $B1
14.089962 : 9F19 : FA       :    PLX
14.089966 : 9F1A : 86 B0    :    STX $B0
14.089969 : 9F1C : FA       :    PLX
14.089973 : 9F1D : 60       :    RTS
14.089979 : 9EE7 : 80 E2    : BRA $9ECB
hoglet67 commented 2 years ago

I was originally thinking we could fix this by intercepting OSBYTE &86 on the host to read POS, VPOS from the Pi Frame Buffer, but:

Instead, I've solved this by extending our host side VDU driver to maintain POS at &0318:

;; Host-side OSWRCH Redirector
;;
;; This redirects OSWRCH calls on the host back over to the Pi VDU driver
;;
;; It's used for the output of MOS command (like *CAT, *HELP, etc)

.host_oswrch_start
    ;; Stack the character to be printed
    PHA
    ;; Emulate the POS VDU variable at &0318
    ;; This is used directly by *HELP MOS for padding and also by *CAT in ADFS
    CMP #12         ; Clear screen returns cursor to POS=0
    BEQ zero_pos
    CMP #13         ; So does carriage returnhome
    BEQ zero_pos
    CMP #30         ; So does home cursor
    BEQ zero_pos
    ;; There are other cases we ignore for now (VDU 8; VDU 9; VDU 31,x,y; VDU 127)
    ;; as these are very unlikely to be emitted by the POS commands that read back POS
    CMP #32         ; Set C=1 if printable char (i.e. space or greater)
    BCC write_fifo
    INC &0318       ; printable char, so increment POS by one
    LDA &0318       ; compare POS to the window width
    CLC
    ADC &0308       ; plus Window Left
    CMP &030A       ; compare to Window Right
    BCC write_fifo  ; Still within window?
.zero_pos
    ;; Zero pos (cursor in left most columb)
    LDA #&00
    STA &0318
.write_fifo
    ;; Select the VDU FIFO at &FEE4
    LDA #&03
    STA &FEE2
    ;; Restore the character to be printed
    PLA
    ;; Write character to the VDU FIFO
    STA &FEE4
    RTS
.host_oswrch_end