6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Wed Sep 25, 2024 5:24 am

All times are UTC




Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: Wed Aug 25, 2021 12:35 am 
Offline

Joined: Sun May 30, 2021 2:16 am
Posts: 374
So, in an earlier general thread (http://forum.6502.org/viewtopic.php?f=1&t=6745#p86419), drogon pointed out that there were errors in the version of Sweet16 on the forum (http://www.6502.org/source/interpreters/sweet16.htm), which differed from the Red Book version (http://www.easy68k.com/paulrsm/6502/SW16RB.TXT).

cjs suggested using "the SW16RB.TXT listing and just trim off the address and data columns at the left." So, I did that, and fixed some of the directives ("DFS"), but I still can't get the damn thing to work. I don't know if I mis-copied something - I proof read it a bunch of times.

There is a "PLA" after A is already pulled off the stack once, after the save routine:

Code:
SW16    JSR   SAVE16       ;PRESERVE 6502 REG CONTENTS
        PLA
        STA   R15L       ;INIT SWEET16 PC
        PLA              ;FROM RETURN
        STA   R15H       ;  ADDRESS


Might that have something to do with it? On a fresh call to Sweet16, what could it be pulling off the stack?

And what about this bit:
Code:
 ;-------------------------------
 ACC    .byte 0
 XREG   .byte 0
 YREG   .byte 0
 STATUS .byte 0
 ;-------------------------------

Shouldn't these be pointers to addresses in RAM?

I don't know. Any takers?

Jonathan

Code:
;***********************
;*                     *
;*   APPLE-II PSEUDO   *
;* MACHINE INTERPRETER *
;*                     *
;*   COPYRIGHT 1977    *
;* APPLE COMPUTER INC  *
;*                     *
;* ALL RIGHTS RESERVED *
;*     S. WOZNIAK      *
;*                     *
;***********************
; TITLE "SWEET16 INTERPRETER"
    R0L      .EQU   $0
    R0H      .EQU   $1
    R14H     .EQU   $1D
    R15L     .EQU   $1E
    R15H     .EQU   $1F
    SW16PAG  .EQU   $F7
;    SAVE     .EQU   $FF4A
;    RESTORE  .EQU   $FF3F
;
    .ORG   $F689        ;adjust
;
SW16    JSR   SAVE16       ;PRESERVE 6502 REG CONTENTS
        PLA
        STA   R15L       ;INIT SWEET16 PC
        PLA              ;FROM RETURN
        STA   R15H       ;  ADDRESS
SW16B   JSR   SW16C      ;INTERPRET AND EXECUTE
        JMP   SW16B      ;ONE SWEET16 INSTR.
SW16C   INC   R15L
        BNE   SW16D      ;INCR SWEET16 PC FOR FETCH
        INC   R15H
SW16D   LDA   #SW16PAG
        PHA              ;PUSH ON STACK FOR RTS
        LDY   #$0
        LDA   (R15L),Y   ;FETCH INSTR
        AND   #$F        ;MASK REG SPECIFICATION
        ASL              ;DOUBLE FOR TWO BYTE REGISTERS
        TAX              ;TO X REG FOR INDEXING
        LSR
        EOR   (R15L),Y   ;NOW HAVE OPCODE
        BEQ   TOBR       ;IF ZERO THEN NON-REG OP
        STX   R14H       ;INDICATE'PRIOR RESULT REG'
        LSR
        LSR              ;OPCODE*2 TO LSB'S
        LSR
        TAY              ;TO Y REG FOR INDEXING
        LDA   OPTBL-2,Y  ;LOW ORDER ADR BYTE
        PHA              ;ONTO STACK
        RTS              ;GOTO REG-OP ROUTINE
TOBR    INC   R15L
        BNE   TOBR2      ;INCR PC
        INC   R15H
TOBR2   LDA   BRTBL,X    ;LOW ORDER ADR BYTE
        PHA              ;ONTO STACK FOR NON-REG OP
        LDA   R14H       ;'PRIOR RESULT REG' INDEX
        LSR              ;PREPARE CARRY FOR BC, BNC.
        RTS              ;GOTO NON-REG OP ROUTINE
RTNZ    PLA              ;POP RETURN ADDRESS
        PLA
        JSR   RESTORE16    ;RESTORE 6502 REG CONTENTS
        JMP   (R15L)     ;RETURN TO 6502 CODE VIA PC
SETZ    LDA   (R15L),Y   ;HIGH-ORDER BYTE OF CONSTANT
        STA   R0H,X
        DEY
        LDA   (R15L),Y   ;LOW-ORDER BYTE OF CONSTANT
        STA   R0L,X
        TYA              ;Y-REG CONTAINS 1
        SEC
        ADC   R15L       ;ADD 2 TO PC
        STA   R15L
        BCC   SET2
        INC   R15H
SET2    RTS
OPTBL   .lobyte   SET-1      ;1X
BRTBL   .lobyte   RTN-1      ;0
        .lobyte   LD-1       ;2X
        .lobyte   BR-1       ;1
        .lobyte   ST-1       ;3X
        .lobyte   BNC-1      ;2
        .lobyte   LDAT-1     ;4X
        .lobyte   BC-1       ;3
        .lobyte   STAT-1     ;5X
        .lobyte   BP-1       ;4
        .lobyte   LDDAT-1    ;6X
        .lobyte   BM-1       ;5
        .lobyte   STDAT-1    ;7X
        .lobyte   BZ-1       ;6
        .lobyte   POP-1      ;8X
        .lobyte   BNZ-1      ;7
        .lobyte   STPAT-1    ;9X
        .lobyte   BM1-1      ;8
        .lobyte   ADD-1      ;AX
        .lobyte   BNM1-1     ;9
        .lobyte   SUB-1      ;BX
        .lobyte   BK-1       ;A
        .lobyte   POPD-1     ;CX
        .lobyte   RS-1       ;B
        .lobyte   CPR-1      ;DX
        .lobyte   BS-1       ;C
        .lobyte   INR-1      ;EX
        .lobyte   NUL-1      ;D
        .lobyte   DCR-1      ;FX
        .lobyte   NUL-1      ;E
        .lobyte   NUL-1      ;UNUSED
        .lobyte   NUL-1      ;F
;
;   NB: The code from `SET` must be on a single page.
;
SET     BPL   SETZ       ;ALWAYS TAKEN
LD      LDA   R0L,X
BK      .EQU   *-1
        STA   R0L
        LDA   R0H,X      ;MOVE RX TO R0
        STA   R0H
        RTS
ST      LDA   R0L
        STA   R0L,X      ;MOVE R0 TO RX
        LDA   R0H
        STA   R0H,X
        RTS
STAT    LDA   R0L
STAT2   STA   (R0L,X)    ;STORE BYTE INDIRECT
        LDY   #$0
STAT3   STY   R14H       ;INDICATE R0 IS RESULT NEG
INR     INC   R0L,X
        BNE   INR2       ;INCR RX
        INC   R0H,X
INR2    RTS
LDAT    LDA   (R0L,X)    ;LOAD INDIRECT (RX)
        STA   R0L        ;TO R0
        LDY   #$0
        STY   R0H        ;ZERO HIGH-ORDER R0 BYTE
        BEQ   STAT3      ;ALWAYS TAKEN
POP     LDY   #$0        ;HIGH ORDER BYTE = 0
        BEQ   POP2       ;ALWAYS TAKEN
POPD    JSR   DCR        ;DECR RX
        LDA   (R0L,X)    ;POP HIGH ORDER BYTE @RX
        TAY              ;SAVE IN Y-REG
POP2    JSR   DCR        ;DECR RX
        LDA   (R0L,X)    ;LOW-ORDER BYTE
        STA   R0L        ;TO R0
        STY   R0H
POP3    LDY   #$0        ;INDICATE R0 AS LAST RESULT REG
        STY   R14H
        RTS
LDDAT   JSR   LDAT       ;LOW-ORDER BYTE TO R0, INCR RX
        LDA   (R0L,X)    ;HIGH-ORDER BYTE TO R0
        STA   R0H
        JMP   INR        ;INCR RX
STDAT   JSR   STAT       ;STORE INDIRECT LOW-ORDER
        LDA   R0H        ;BYTE AND INCR RX.  THEN
        STA   (R0L,X)    ;STORE HIGH-ORDER BYTE.
        JMP   INR        ;INCR RX AND RETURN
STPAT   JSR   DCR        ;DECR RX
        LDA   R0L
        STA   (R0L,X)    ;STORE R0 LOW BYTE @RX
        JMP   POP3       ;INDICATE R0 AS LAST RSLT REG
DCR     LDA   R0L,X
        BNE   DCR2       ;DECR RX
        DEC   R0H,X
DCR2    DEC   R0L,X
        RTS
SUB     LDY   #$0        ;RESULT TO R0
CPR     SEC              ;NOTE Y-REG = 13*2 FOR CPR
        LDA   R0L
        SBC   R0L,X
        STA   R0L,Y      ;R0-RX TO RY
        LDA   R0H
        SBC   R0H,X
SUB2    STA   R0H,Y
        TYA              ;LAST RESULT REG*2
        ADC   #$0        ;CARRY TO LSB
        STA   R14H
        RTS
ADD     LDA   R0L
        ADC   R0L,X
        STA   R0L        ;R0+RX TO R0
        LDA   R0H
        ADC   R0H,X
        LDY   #$0        ;R0 FOR RESULT
        BEQ   SUB2       ;FINISH ADD
BS      LDA   R15L       ;NOTE X-REG IS 12*2!
        JSR   STAT2      ;PUSH LOW PC BYTE VIA R12
        LDA   R15H
        JSR   STAT2      ;PUSH HIGH-ORDER PC BYTE
BR      CLC
BNC     BCS   BNC2       ;NO CARRY TEST
BR1     LDA   (R15L),Y   ;DISPLACEMENT BYTE
        BPL   BR2
        DEY
BR2     ADC   R15L       ;ADD TO PC
        STA   R15L
        TYA
        ADC   R15H
        STA   R15H
BNC2    RTS
BC      BCS   BR
        RTS
BP      ASL              ;DOUBLE RESULT-REG INDEX
        TAX              ;TO X REG FOR INDEXING
        LDA   R0H,X      ;TEST FOR PLUS
        BPL   BR1        ;BRANCH IF SO
        RTS
BM      ASL              ;DOUBLE RESULT-REG INDEX
        TAX
        LDA   R0H,X      ;TEST FOR MINUS
        BMI   BR1
        RTS
BZ      ASL              ;DOUBLE RESULT-REG INDEX
        TAX
        LDA   R0L,X      ;TEST FOR ZERO
        ORA   R0H,X      ;(BOTH BYTES)
        BEQ   BR1        ;BRANCH IF SO
        RTS
BNZ     ASL              ;DOUBLE RESULT-REG INDEX
        TAX
        LDA   R0L,X      ;TEST FOR NON-ZERO
        ORA   R0H,X      ;(BOTH BYTES)
        BNE   BR1        ;BRANCH IF SO
        RTS
BM1     ASL              ;DOUBLE RESULT-REG INDEX
        TAX
        LDA   R0L,X      ;CHECK BOTH BYTES
        AND   R0H,X      ;FOR $FF (MINUS 1)
        EOR   #$FF
        BEQ   BR1        ;BRANCH IF SO
        RTS
BNM1    ASL              ;DOUBLE RESULT-REG INDEX
        TAX
        LDA   R0L,X
        AND   R0H,X      ;CHECK BOTH BYTES FOR NO $FF
        EOR   #$FF
        BNE   BR1        ;BRANCH IF NOT MINUS 1
NUL     RTS
RS      LDX   #$18       ;12*2 FOR R12 AS STACK POINTER
        JSR   DCR        ;DECR STACK POINTER
        LDA   (R0L,X)    ;POP HIGH RETURN ADDRESS TO PC
        STA   R15H
        JSR   DCR        ;SAME FOR LOW-ORDER BYTE
        LDA   (R0L,X)
        STA   R15L
        RTS
RTN     JMP   RTNZ

 ;-------------------------------
 ACC    .byte 0
 XREG   .byte 0
 YREG   .byte 0
 STATUS .byte 0
 ;-------------------------------
 SAVE16
    STA ACC
    STX XREG
    STY YREG
    PHP
    PLA
    STA STATUS
    CLD
    RTS
 ;------------------------------
 RESTORE16
    LDA STATUS
    PHA
    LDA ACC
    LDX XREG
    LDY YREG
    PLP
    RTS
;


I added some of the suggested "save" and "restore" suggested by others.


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 25, 2021 1:19 am 
Offline
User avatar

Joined: Sat Dec 01, 2018 1:53 pm
Posts: 727
Location: Tokyo, Japan
Jmstein7 wrote:
There is a "PLA" after A is already pulled off the stack once, after the save routine...
On a fresh call to Sweet16, what could it be pulling off the stack?

It's pulling off the LSB† of the address pushed on the stack by the JSR to this code. A later PLA will grab the MSB. (Remember, this address is one less than the actual return address.) This is how it figures out the location of the Sweet 16 opcodes that immediately follow the JSR to the interpreter. The interpreter doesn't return with an RTS (since there's no longer an address on the stack) but instead just does an indirect jump to its current PC (R15) which will be pointing after the last Sweet 16 opcode executed.

This is all intermixed with the other complexities of the interpreter, so if the above technique isn't something you understand well it would be worthwhile to leave the interpreter aside for the moment and just implement this technique in simpler code. For example, you could write one that takes as a parameter a single byte after the JSR, puts that into the A register (or copies it to a memory location), and then try calling it to make sure it's returning correctly. E.g.:

Code:
test_call   LDA #$00        ; ensure A does not have test data in it
            JSR test_sub
            DB  $AE         ; parameter to test_sub
            STA $02         ; test_sub should return to here
                            ; value returned in A stored in $02
            RTS             ; or BRK


As far as SAVE and RESTORE go, my suggestion would be for the moment to have both of these simply RTS, as I do in my unit tests. This will avoid one possible source of error or problems so long as you don't depend on the registers and flags being preserved across a Sweet 16 interpreter call.

But that said, you can also check check your SAVE and RESTORE routines against any Apple II or II+ Monitor ROM listing. There's a copy of it in my file, but it's probably better to go back to the original as my copy has never actually been tested.

And yes, for the SAVE and RESTORE that are actually supposed to work, your
ACC, XREG etc. must be in RAM. Otherwise what happens when it reads ACC etc. and puts those values in the registers and flags?

You may also find it worth comparing your copy of the source to mine, which is confirmed working (at least for some basic instructions) with tests. This is most easily done with a good diff program.

__________
† Corrected from MSB; thanks barrym95838.

_________________
Curt J. Sampson - github.com/0cjs


Last edited by cjs on Wed Aug 25, 2021 3:31 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 25, 2021 3:16 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1948
Location: Sacramento, CA, USA
cjs wrote:
Jmstein7 wrote:
There is a "PLA" after A is already pulled off the stack once, after the save routine...
On a fresh call to Sweet16, what could it be pulling off the stack?

It's pulling off the MSB of the address pushed on the stack by the JSR to this code. A later PLA will grab the LSB.


Or vice-versa :wink:

PRIMM is a simple and useful example of this technique.

Further down in the SWEET16 dispatcher is a different angle on this concept, where the high and low bytes of the address (minus one) for the appropriate instruction handler routine are pushed on the stack and then executed with an RTS.

_________________
Got a kilobyte lying fallow in your 65xx's memory map? Sprinkle some VTL02C on it and see how it grows on you!

Mike B. (about me) (learning how to github)


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 25, 2021 3:33 am 
Offline
User avatar

Joined: Sat Dec 01, 2018 1:53 pm
Posts: 727
Location: Tokyo, Japan
barrym95838 wrote:
Or vice-versa :wink:

Ha ha, yes. I was sitting there thinking, "I need to reverse MSB and LSB here because the stack shrinks upwards," and ended up reversing again what I'd already reversed. Anyway, that's fixed now. Thanks.

_________________
Curt J. Sampson - github.com/0cjs


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 25, 2021 8:08 am 
Offline
User avatar

Joined: Wed Feb 14, 2018 2:33 pm
Posts: 1467
Location: Scotland
I simply re-wrote it, although it's hard to do a total re-write since 90% of the code comes out the same... But I wanted to get rid of the one-page dependency thing and make it a little faster for the C02...

https://project-downloads.drogon.net/misc6502/

-Gordon

_________________
--
Gordon Henderson.
See my Ruby 6502 and 65816 SBC projects here: https://projects.drogon.net/ruby/


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 25, 2021 1:40 pm 
Offline

Joined: Sun May 30, 2021 2:16 am
Posts: 374
There is another implementation in Github (https://github.com/BruceMcF/Sweeter16/blob/master/Sweet16c2.asm), called "Sweeter16", by "BruceMcF," but it has some conventions I don't get, like this:
Code:
CALL:   ; Pointer to 65C02 machine code is
   ; in R11. Branch via OP to support
   ; embedded data
   JSR +
   BRA BR
+   JMP (CALLV)

another example:
Code:
OFFSET:
   LDY #0      ;16bit sign extension
   LDA  (IP)      ;Branch Offset
   BPL  +
   DEY
+   CLC
   ADC  REG,X        ;ADD TO IP
   STA  REG,X
   TYA
   ADC  REG+1,X
   STA  REG+1,X
NEXTOP:
   INC IP
   BNE  +      ; ++IP
   INC IP+1
NEXTOP1:
+   LDA (IP)

What are these "+" signs? Local labels?

Jon


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 25, 2021 1:43 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
yes, local labels.


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 25, 2021 1:52 pm 
Offline

Joined: Sun May 30, 2021 2:16 am
Posts: 374
BigEd wrote:
yes, local labels.

Is there something else they can be changed to that will be recognized by most assemblers? Mine doesn't do "+". (I'm using RetroAssembler in VS). I guess the one-shot "@label" will do?

Jon


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 25, 2021 2:02 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10938
Location: England
I think you need to make something unique (for many assemblers) for example L089 for a label on line 89 of the file might do it. But possibly your assembler does have local labels - always worth reading the documentation!


Top
 Profile  
Reply with quote  
PostPosted: Wed Aug 25, 2021 3:56 pm 
Offline

Joined: Sun May 30, 2021 2:16 am
Posts: 374
BigEd wrote:
I think you need to make something unique (for many assemblers) for example L089 for a label on line 89 of the file might do it. But possibly your assembler does have local labels - always worth reading the documentation!

Yes. The "disposable" labels in my assembler start with "@", such as "@loop", for example.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 9 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: