6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Thu Nov 21, 2024 2:03 pm

All times are UTC




Post new topic Reply to topic  [ 38 posts ]  Go to page Previous  1, 2, 3
Author Message
 Post subject: Re: Self Modifying Code
PostPosted: Tue Apr 14, 2020 7:32 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
Fleet Forth has a word, WHERE , to show where an error occurred. If the value of BLK is zero, WHERE displays the string pointed to by TIB with the length stored in #TIB . If BLK is non zero, WHERE prints the block and line numbers and displays the text on that line. Since I/O is involved (if the block is not in memory) there is a possibility of WHERE causing another error which would lead to WHERE being called which would cause another error and so on.
The solution I went with looks like this:
Code:
NH VARIABLE WHERE?  TRUE WHERE? !
: WHERE  ( -- )
   WHERE? @ IF
      WHERE? OFF
      // The main body of WHERE
            .
            .
            .
   THEN
   WHERE? ON ;

NH is a metacompiler directive that makes the following word headless.
If any error occurs while WHERE executes, WHERE does nothing but set the variable WHERE? to true.
Here's a solution involving self modifying code:
Code:
HEX
: WHERE  ( -- )
   // SWITCH WHERE OFF
   ['] EXIT (IS) RECURSE
   // The main body of WHERE
         .
         .
         .

(IS) is the primitive compiled by IS and RECURSE compiles the CFA of the latest word so the phrase
Code:
   ['] EXIT (IS) RECURSE

makes EXIT the first word in the body of WHERE , effectively switching it off. All error handling in Fleet Forth eventually goes through ABORT . A slight modification to ABORT switches WHERE back on. The original ABORT :
Code:
: ABORT  ( -- )
   ERR SP! AP!
   QUIT ; -2 ALLOT

and the new version :
Code:
: ABORT  ( -- )
   ERR SP! AP!  ['] LIT (IS) WHERE
   QUIT ; -2 ALLOT

WHERE becomes eight bytes smaller while ABORT becomes eight bytes bigger. No net loss or gain there. The headless variable WHERE? is no longer needed for a total savings of four bytes.
By the way, the word ERR is a deferred word to allow extending the error handling. It is normally set to the word NOOP , a no-op.


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Wed Apr 15, 2020 2:26 am 
Offline

Joined: Sat Aug 21, 2010 7:52 am
Posts: 231
Location: Arlington VA
I recall QUAN structures in MMSForth, a syntactically cleaner albeit nonstandard replacement for VARIABLE. The way it worked in your code was:
Code:
quan foo
42 is foo
foo .
at foo .
: compiledfoo   ( -- )
   37 is foo   foo .    at foo . ;

Under the hood, FOO has three different code field addresses, and the words IS and AT are immediate words to select either the 'assignment CFA' or 'address-of CFA'. If neither IS nor AT prefixes FOO, then the 'value-of CFA' is used.


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Mon Jun 15, 2020 7:54 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
chitselb wrote:
I recall QUAN structures in MMSForth, a syntactically cleaner albeit nonstandard replacement for VARIABLE. The way it worked in your code was:
Code:
quan foo
42 is foo
foo .
at foo .
: compiledfoo   ( -- )
   37 is foo   foo .    at foo . ;

Under the hood, FOO has three different code field addresses, and the words IS and AT are immediate words to select either the 'assignment CFA' or 'address-of CFA'. If neither IS nor AT prefixes FOO, then the 'value-of CFA' is used.

I was thinking that maybe instead of IS , use TO.
TO and AT would be used with QUAN's or any QUAN like word ( double QUAN's, floating point QUAN's , etc. ) and IS could still be used to set DEFERred words.


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Tue Jun 16, 2020 8:48 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
I was thinking that QUANs could be a replacement for variable if the default action is to return a QUAN's data's address ( like a variable ). TO could select the set value CFA and AT could select the fetch value CFA.
Code:
QUAN FOO
AT FOO U.  \ get the data AT FOO
137 TO FOO \ send the data TO FOO
FOO U.     \ where is the data ( just like VARIABLE )

Here is some prototype code I wrote last night.
Code:
SCR# 1076
// QUAN -- CODE FOR CODE FIELDS
HEX
SUBR DO.VAR
   CLC,
   6 # LDA,  W ADC,  PHA,
   TYA,   W 1+ ADC,
   PUSH JMP,  END-CODE
SUBR TO.Q
   CLC,  DEX,  DEX,
   4 # LDA,  W ADC,  0 ,X STA,
   TYA,   W 1+ ADC,  1 ,X STA,
   ' ! @ JMP,  END-CODE
SUBR AT.Q
   ' BL @ JMP,  END-CODE

SCR# 1077
// TO AT
HEX
// SET A QUAN
: TO ( N -- )  // PARSE TEXT STREAM
   2 ' DUP @ DO.VAR <>
   ABORT" NOT A QUAN"
   +  STATE @
   IF  , EXIT  THEN
   EXECUTE ; IMMEDIATE
// GET A QUAN'S VALUE
: AT  ( -- N )  // PARSE TEXT STREAM
   4 BRANCH [ ' TO >BODY 2+ , ] ;
   -2 ALLOT IMMEDIATE

SCR# 1078
// QUAN
HEX
: CFA-ALIGN
   >IN @ BL WORD  // AVOID INDIRECT
   SWAP >IN !     // JUMP BUG IN
   COUNT + 1 AND  // NMOS 6510
   ALLOT ;        // PROCESSOR
: QUAN
   CFA-ALIGN CREATE -2 ALLOT
   DO.VAR ,  TO.Q ,  AT.Q ,
   0 , ;
;S
CREATE MAKES SURE THE FIRST CFA
DOES NOT STRADDLE A PAGE BOUNDARY.
CFA-ALIGN HANDLES THE OTHER TWO.

SCR# 1079
// 2QUAN
HEX
SUBR TO.2Q
   CLC,  DEX,  DEX,
   4 # LDA,  W ADC,  0 ,X STA,
   TYA,   W 1+ ADC,  1 ,X STA,
   ' 2! @ JMP,  END-CODE
SUBR AT.2Q
   CLC,  DEX,  DEX,
   2 # LDA,  W ADC,  0 ,X STA,
   TYA,   W 1+ ADC,  1 ,X STA,
   ' 2@ @ JMP,  END-CODE
: 2QUAN
   CFA-ALIGN  CREATE -2 ALLOT
   DO.VAR , TO.2Q ,  AT.2Q ,
   0 , 0 , ;

With this behavior, QUAN could be renamed VARIABLE and 2QUAN could be renamed 2VARIABLE. As long as TO and AT were not used, these versions of VARIABLE and 2VARIABLE would behave just like the original versions.
I was thinking about removing the ABORT" in TO and have it ( and AT ) execute or compile the word's only CFA if the word is not a 'QUAN' .
[Edit: fixed incorrect stack comment. TO does not return an address, it parses the text stream for the next word.]


Last edited by JimBoyd on Mon Jan 18, 2021 10:35 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Wed Jun 17, 2020 8:54 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
There are some things I neglected to mention in my previous post.
The defining word SUBR creates a variable with no space alloted, but it switches on the assembler. A word created with SUBR returns its address.
The word CFA-ALIGN is only needed for Forth's running on NMOS 6502's or 6510's.
That funny looking word ;S ends loading of a block ( it's an alias for EXIT ).
And since this is for a Commodore 64, just read \ ( backslash ) for each // ( double forward slash ).
Here is the code for new style variables ( VARs ) cleaned up a little:
Code:

SCR# 1076
// VAR -- CODE FOR CODE FIELDS
HEX
: DO.VAR  // PRIMARY CODE FIELD
   ;CODE
   CLC,
   6 # LDA,  W ADC,  PHA,
   TYA,   W 1+ ADC,
   PUSH JMP,  END-CODE
SUBR TO.VAR
   CLC,  DEX,  DEX,
   4 # LDA,  W ADC,  0 ,X STA,
   TYA,   W 1+ ADC,  1 ,X STA,
   ' ! @ JMP,  END-CODE
SUBR AT.VAR
   ' BL @ JMP,  END-CODE

SCR# 1077
// TO AT
HEX
// SET A VAR
: TO ( N -- )
   ' DUP @ [ ' DO.VAR 4 + ] LITERAL
   <> ABORT" NO TO BEHAVIOR"
   2+  STATE @
   IF  , EXIT  THEN
   EXECUTE ; IMMEDIATE
// GET A VAR'S VALUE
: AT  ( -- N )
   ' DUP @ [ ' DO.VAR 4 + ] LITERAL
   <> ABORT" NO AT BEHAVIOR"
   2+ 2+  STATE @
   IF  , EXIT  THEN
   EXECUTE ; IMMEDIATE

SCR# 1078
// VAR
HEX
: CFA-ALIGN
   >IN @ BL WORD  // AVOID INDIRECT
   SWAP >IN !     // JUMP BUG IN
   COUNT + 1 AND  // NMOS 6510
   ALLOT ;        // PROCESSOR
: VAR
   CFA-ALIGN CREATE
   TO.VAR ,  AT.VAR ,
   0 ,  DO.VAR ;
;S
CREATE MAKES SURE THE FIRST CFA
DOES NOT STRADDLE A PAGE BOUNDARY.
CFA-ALIGN HANDLES THE OTHER TWO.

SCR# 1079
// 2VAR
HEX
SUBR TO.2VAR
   CLC,  DEX,  DEX,
   4 # LDA,  W ADC,  0 ,X STA,
   TYA,   W 1+ ADC,  1 ,X STA,
   ' 2! @ JMP,  END-CODE
SUBR AT.2VAR
   CLC,  DEX,  DEX,
   2 # LDA,  W ADC,  0 ,X STA,
   TYA,   W 1+ ADC,  1 ,X STA,
   ' 2@ @ JMP,  END-CODE
: 2VAR
   CFA-ALIGN  CREATE
   TO.2VAR ,  AT.2VAR ,
   0 , 0 ,  DO.VAR ;

Since ANS Forth uses TO to set the data of a VALUE, if one wanted to ad ANS Forth style VALUEs to Forth:
Code:
: VALUE
   CONSTANT ;CODE
   ' BL @ JMP,
END-CODE
: TO   
   ' DUP VALUE-CFA <> // TEST IF NOT A VALUE
   IF   [COMPILE] TO EXIT  THEN
   // PERFORM VALUE RELATED BEHAVIOR
; IMMEDIATE

[Edit: I made some mistakes when changing the code. Sorry, I was away from my desktop. I've corrected the errors. Hopefully. I'm fighting with a weak data connection.]


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Tue Jan 19, 2021 12:06 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
JimBoyd wrote:
I was thinking that QUANs could be a replacement for variable if the default action is to return a QUAN's data's address ( like a variable ). TO could select the set value CFA and AT could select the fetch value CFA.


At one time I thought that this behavior ( the default action being that of a VARIABLE rather than that of a VALUE would be the only easy way to tell if a word being parsed by TO or AT was a multi code field word. I no longer feel this is necessary.
I just realized that a clever implementation would allow TO and AT to fetch the address of the first code field, to get to the parent word, and backup to find if there is a word unique to multi code field defining words ( even if that word is a no-op ). This word's address could be the flag used to tell if a word is a multi code field word.


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Tue Mar 02, 2021 1:05 am 
Offline

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

I'm not sure if this would qualify as self modifying code. The following word modifies itself without modifying the running code.
Fleet Forth has a word CHAR that is used by the following:
Code:
.(  (  ,"  "
.( ABC)  displays the string ABC
( ABC)  comment -- discards the string
," ABC"  compiles the string ABC
" ABC"   If interpreting, stores ABC as a counted string at PAD
         If compiling, compiles helper word (") and ABC as a counted string

CHAR takes the ASCII code for a character to use as a delimiter and parses the text stream until that delimiter is found. It returns the address and count of the string that was parsed. CHAR aborts with the following message if the delimiter was not found:
'X' MISSING
Where 'X' is the delimiter used. For example:
Code:
.( THIS IS A TEST
^^
) MISSING

This is the most streamlined version I had:
Code:
: CHAR  ( C -- ADR CNT )
   DUP>R HERE C!
   'STREAM 2DUP R>
   SCAN DUP 0=
   IF
      WHERE
      CR HERE C@ EMIT ."  MISSING"
      ABORT
   THEN
   ADJUST ;

This version is 13 bytes smaller
Code:
: CHAR  ( C -- ADR CNT )
   DUP>R LIT [ HERE >A 0 , ] C!
   'STREAM 2DUP R>
   SCAN DUP 0=
   [ HERE 3 + A> ! ]
   ABORT"   MISSING"
   ADJUST ;

CHAR modifies the inline text used by (ABORT") , which is compiled by ABORT" , by storing the ASCII code for the delimiter at the address of the first character of the string.


Top
 Profile  
Reply with quote  
 Post subject: Re: Self Modifying Code
PostPosted: Sat Oct 29, 2022 12:38 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
JimBoyd wrote:
What about manipulating the return stack to control program flow?
I was just reading Dynamically Structured Codes by M. L. Gassanenko. Does this count as self modifying code?


Since the actual code does not get modified, I have concluded that this is not self modifying code.


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

All times are UTC


Who is online

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