6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Apr 27, 2024 1:19 pm

All times are UTC




Post new topic Reply to topic  [ 36 posts ]  Go to page Previous  1, 2, 3
Author Message
PostPosted: Mon Apr 29, 2019 10:00 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
Dr Jefyll wrote:
BTW, I'll quickly inject a comment of my own. Ragsdale's assembler (and yours, I think) check to see that conditionals are properly paired, which means (for example) that BEGIN leaves both an address and an error-check code on stack and UNTIL removes these two items. Usually that's fine, but in certain situations the error-check code becomes a nuisance, leading to extra SWAPs ROTs etc.

I'd like to add that the compiler security isn't meant to be restrictive. It is modeled on high level forth control flow structures where the security is there to make sure that >MARK is resolved by >RESOLVE and <MARK is resolved by <RESOLVE . There is no assembler version of the mark and resolve words, but in the assembler, any word that needs a forward branch or jump resolved can be paired with any word that resolves a forward branch or jump. Any word that leaves an address for a backward branch or jump can be paired with any word that uses that address for a backward branch or jump. For example, ELSE, , ELIF, , and WHILE, are defined like this:
Code:
: ELSE,  ( ADR1 CS -- ADR2 CS )
   [COMPILE] AHEAD, 2SWAP
   [COMPILE] THEN, ; IMMEDIATE

: ELIF,  ( ADDR1 CS1 -- ADDR2 CS2 )
   [COMPILE] IF, 2SWAP
   [COMPILE] THEN, ; IMMEDIATE

: WHILE,  ( A1 C1 -- A2 C2 A1 C1 )
   [COMPILE] IF, 2SWAP ; IMMEDIATE

Which means that, oddly, any number of ELSE, or ELIF, clauses can be between an IF, and a THEN,. But then, no restrictions, just making sure that forward and backward references are properly resolved.


Top
 Profile  
Reply with quote  
PostPosted: Tue Apr 30, 2019 9:12 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
Dr Jefyll wrote:
JimBoyd wrote:
That's why I've got CS-DUP CS-DROP CS-SWAP and CS-ROT which also work with high level Forth conditionals. I just treat the address and security number as a single unit.
Yes, you have a solution of sorts but it's not one I like much, and I thought perhaps I could do a little better.

Unfortunately, after refreshing myself on the subject (it's been years since I involved myself with this) I have no dramatic improvement to offer. In my notes I did find the following...
Code:
: IF[WITHIN], ( like IF, but used within an assembler structured conditional )
    >R >R [COMPILE] IF,
    R> R> ; IMMEDIATE
... but this is less flexible than what you're doing, and certainly no prettier. :|

Now that I have an Auxiliary stack, there is also CS>A , control stack to auxiliary, and A>CS , auxiliary to control stack to transfer control flow data ( address and security code ) between the control flow stack ( data stack ) and the auxiliary stack. They also work with high level code since all the control flow data in Fleet Forth ( address and security code ) are two cells. Even the "sys" used by colon and semicolon ( as well as CODE and END-CODE ) is two cells.
Quote:
Code:
:            -- sys                        M,79          "colon"

   sys is balanced with its corresponding ;



;            --                            C,I,79   "semi-colon"

             sys --   (compiling)         

               Stops compilation of a colon definition, allows the <name>
   sys is balanced with its corresponding :



Top
 Profile  
Reply with quote  
PostPosted: Wed May 05, 2021 11:52 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
barrym95838 wrote:
GARTHWILSON wrote:
(For ZP, there's LDA_ZP,Y.)

And what op-code do you comma in for that one? :wink:


In the past it has slipped my mind that there is no LDA ZP,Y instruction. I wondered why my PICK was two bytes bigger than I thought it would be.
It turns out that the NMOS 6502 has only two instructions which have the ZP ,Y addressing mode: LDX and STX .
This is one more thing I like about my assembler, I don't need to think about which instructions have a zero page addressing mode or if the address is small enough unless I'm counting bytes ( or cycles) to find the better of two or more ways to write a primitive.
For instructions with the ABSOLUTE ABSOLUTE,X or ABSOLUTE,Y addressing modes, if the address will fit in a single byte and if the instruction supports the zero page version then the assembler will use the zero page version.

[Edit: Fixed a mistake]


Top
 Profile  
Reply with quote  
PostPosted: Sun Jun 13, 2021 9:46 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851

I mentioned here that I was experimenting with removing the trailing commas from my assembler's mnemonics and control flow words.
After almost four months, I can report that I do not miss the old version with the trailing commas.


Top
 Profile  
Reply with quote  
PostPosted: Sun May 14, 2023 9:32 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851

I've uploaded to the head post the plain text source for the latest version of Fleet Forth's assembler in a zip file.
The control flow data is the same size as the control flow data for Fleet Forth's high level control flow words. The control flow data is just an address followed by a security number. The security code is only there to be certain the branches are properly resolved. This is similar to how the Forth-83 words >MARK , >RESOLVE , <MARK and <RESOLVE work.
For an example, here is the source for Fleet Forth's word BLK> from the system loader. It takes an absolute block number and returns the relative block number (relative to the drive where it is stored) and the drive number.
Code:
CODE BLK>    ( BLK#1 -- BLK#2 DR# )
   BEGIN
      SEC  1 ,X LDA
      0 1 DR+ SPLIT NIP # SBC
   CS WHILE
      1 ,X STA  INY
      0 RAM  0 1 DR+  / # CPY
   0= UNTIL
   THEN
   TYA
   APUSH JMP  END-CODE

and the disassembly.
Code:
SEE BLK>
BLK>
 14216          SEC
 14217     1 ,X LDA
 14219     8  # SBC
 14221 14230    BCC
 14223     1 ,X STA
 14225          INY
 14226     8  # CPY
 14228 14216 ^^ BNE
 14230          TYA
 14231  3176    JMP APUSH
18
 OK

The largest CODE word written for Fleet Forth is the find primitive (FIND) .
Note: CS-DUP is just an immediate version of 2DUP .
Code:
CODE (FIND)  ( ADR VOC -- ADR2 F )
   DEY  N 1- STY
   SEC
   2 ,X LDA  2 # SBC  N 2+  STA
   3 ,X LDA  0 # SBC  N 3 + STA
   0 ,X LDY  1 ,X LDA
   INX  INX  XSAVE STX
   BEGIN
      N    STY  N 4 + STY
      N 1+ STA  N 5 + STA
      BEGIN
         0 # LDY
         N )Y LDA  TAX  INY
         N )Y LDA
      0= NOT WHILE
         N 1+ STA  N STX  INY
         N )Y LDA
         SBIT $1F OR # AND
         N 2+ )Y EOR
      CS-DUP 0= UNTIL // CONTINUE
         BEGIN
            INY
            N 2+ )Y LDA
            N    )Y EOR
         0= NOT UNTIL
         $7F # AND
      0= UNTIL
         XSAVE LDX  SEC
         TYA  N ADC  0 ,X STA
         0 # LDA  N 1+ ADC  1 ,X STA
         2 # LDY
         N )Y LDA  IBIT # AND
         0= NOT IF
            LABEL PUSH.ONE  //  1
            1 # LDA
            LABEL APUSH
            0 # LDY
            LABEL AYPUSH
            DEX  DEX
            LABEL AYPUT
            0 ,X STA  1 ,X STY
            NEXT JMP
         THEN
         LABEL PUSH.TRUE    // -1
         $FF # LDA  TAY
         AYPUSH 0= NOT BRAN
      THEN
      3 # LDY
      N 4 + )Y LDA
      N 1- AND
   0= NOT WHILE
      TAX  DEY
      N 4 + )Y LDA
      TAY  TXA
   0= UNTIL   // ALWAYS BRANCH
   THEN
   XSAVE LDX
   LABEL PUSH.FALSE         //  0
   0 # LDA
   APUSH 0= BRAN
END-CODE

// AYPUSH & AYPUT
// .A HOLDS LO BYTE
// .Y HOLDS HI BYTE

Here is the disassembly.
Code:
SEE (FIND)
(FIND)
  3086          DEY
  3087   132    STY  N 1-
  3089          SEC
  3090     2 ,X LDA
  3092     2  # SBC
  3094   135    STA  N 2+
  3096     3 ,X LDA
  3098     0  # SBC
  3100   136    STA  N 3 +
  3102     0 ,X LDY
  3104     1 ,X LDA
  3106          INX
  3107          INX
  3108   141    STX XSAVE
  3110   133    STY  N
  3112   137    STY  N 4 +
  3114   134    STA  N 1+
  3116   138    STA  N 5 +
  3118     0  # LDY
  3120   133 )Y LDA  N
  3122          TAX
  3123          INY
  3124   133 )Y LDA  N
  3126  3192    BEQ
  3128   134    STA  N 1+
  3130   133    STX  N
  3132          INY
  3133   133 )Y LDA  N
  3135    63  # AND
  3137   135 )Y EOR  N 2+
  3139  3118 ^^ BNE
  3141          INY
  3142   135 )Y LDA  N 2+
  3144   133 )Y EOR  N
  3146  3141 ^^ BEQ
  3148   127  # AND
  3150  3118 ^^ BNE
  3152   141    LDX XSAVE
  3154          SEC
  3155          TYA
  3156   133    ADC  N
  3158     0 ,X STA
  3160     0  # LDA
  3162   134    ADC  N 1+
  3164     1 ,X STA
  3166     2  # LDY
  3168   133 )Y LDA  N
  3170    64  # AND
  3172  3187    BEQ
  3174     1  # LDA
  3176     0  # LDY
  3178          DEX
  3179          DEX
  3180     0 ,X STA
  3182     1 ,X STY
  3184  2160    JMP NEXT
  3187   255  # LDA  W 1+
  3189          TAY
  3190  3178 ^^ BNE AYPUSH
  3192     3  # LDY
  3194   137 )Y LDA  N 4 +
  3196   132    AND  N 1-
  3198  3208    BEQ
  3200          TAX
  3201          DEY
  3202   137 )Y LDA  N 4 +
  3204          TAY
  3205          TXA
  3206  3110 ^^ BNE
  3208   141    LDX XSAVE
  3210     0  # LDA
  3212  3176 ^^ BEQ APUSH
128
 OK

Although everything in Fleet Forth's kernel is built with a metacompiler, the metacompiler's assembler is based on Fleet Forth's assembler.
The assembler's control flow words are not that different from their high level counterparts. Some require a condition code to assemble the correct branch while the high level versions require a flag on the data stack.
Here is a high level example of control flow in Fleet Forth using CS-DUP to manipulate the control flow data.
Code:
: QUIT  ( -- )
   [COMPILE] [
   BEGIN
         RP!
         ['] LIT (IS) WHERE
         CR QUERY INTERPRET
         STATE @ 0=
      CS-DUP UNTIL  // CONTINUE
      ."  OK"
   AGAIN -;



Top
 Profile  
Reply with quote  
PostPosted: Sun May 14, 2023 11:37 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
GARTHWILSON wrote:
If I implement the structured conditionals, I might do something like:
Code:
HEX

CODE ACLOSE  ( -- )         \ Close all open files.
   STX_ZP  XSAVE  C,
   BEGIN,
      LDY_ZP  98  C,        \ (but give a name, as Jeff suggests)
      0<>
   WHILE,
      LDA_ABS   258  C,     \ LAST OPENED
      JSR      FFC3   ,     \ CLOSE
   REPEAT,
   LDX_ZP  XSAVE  C,
   JMP     NEXT    ,


I've been re-reading this thread and the commas at the end of the control flow words are, in my opinion, annoying.
If I were to implement an assembler for a Forth without vocabularies, I'd try the following:
Code:
: BEGIN
   STATE @
   IF  [COMPILE] BEGIN  EXIT  THEN
  <ASSEMBLER VERSION OF BEGIN> ; IMMEDIATE

The high level control flow words are redefined. BEGIN performs the original high level function of BEGIN If STATE is compiling. It's assembling If STATE is interpreting.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 36 posts ]  Go to page Previous  1, 2, 3

All times are UTC


Who is online

Users browsing this forum: No registered users and 10 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: