Close

Self Modifying Code

A project log for A SUBLEQ CPU

Yet Another Minimalistic One Instruction CPU SUBLEQ means SUBtraction jump on Less than or EQual to zero.

agp.cooperagp.cooper 06/11/2017 at 03:030 Comments

Self Modifying Code - Part 1

TTA (Transport Triggered Architecture) and SUBLEQ can use pointer but it requires the use self modifying code. Reading data from a memory location to a variable called DATA from an address stored in (pointed to by) a variable called ADDR is an example. We can write it as:

Not to be confused with copy or move:

DATA = [ADDR] can be coded as:

T T ?       ; T=0
PTR PTR ?   ; PTR=0
ADDR T ?    ; T=-ADDR
T PTR ?     ; PTR=ADDR
T T ?       ; T=0
PTR: T T ?  ; T=-PTR (self modifying code)
DATA DATA ? ; DATA=0
T DATA ?    ; DATA=[ADDR]

Although the assembler thinks the first T on the PTR: line is real and initially set with the address of "T", the code above overwrites the address with the value held in ADDR. The only problem is that code cannot reside in ROM (as it is self modifying).

A more general form would be:

This would be coded as:

SRC_PTR SCR_PTR ?         ; Copy SRC to SRC_PTR
T T ?
SRC T ?
T SRC_PTR ?

DST_PTR DST_PTR ?         ; Copy DST to DST_PTR
T T ?
DST T ?
T DST_PTR ?

NDATA NDATA ?             ; COPY [SRC] TO NDATA TO [DST]
SRC_PTR: SRC_PTR NDATA ?  ; SELF MODIFYING CODE
NDATA DST_PTR: DST_PTR ?  ; SELF MODIFYING CODE

T T RTN                   ; RETURN

Getting code in ROM to RAM without self modifying code is tricky, but first an assembler update.

Assembler Updated

SYNTAX

A space is required between tokens.

SUBLEQ defined variables:

SUBLEQ defined constants (value should not be changed):

Comments:

Address Labels:

Constants and Literals:

Examples of code (note: line numbers are not part of the assembler code):

  1. ( HELLO WORLD! )
  2. E OUTPUT ?
  3. L OUTPUT ?
  4. L OUTPUT ?
  5. O OUTPUT ?
  6. BLANK OUTPUT ?
  7. W OUTPUT ?
  8. O OUTPUT ?
  9. R OUTPUT ?
  10. L OUTPUT ?
  11. D OUTPUT ?
  12. BANG OUTPUT ?
  13. Z Z HALT ; And end program
  14. ( ASCII characters )
  15. .H 72
  16. .E 69
  17. .L 76
  18. .O 79
  19. .BLANK 32
  20. .W 87
  21. .R 82
  22. .D 68
  23. .BANG 33
  24. ( Predined variables and addresses )
  25. .Z 0
  26. .T 0
  27. .P 1
  28. .N -1
  29. .SP -17
  30. @OUTPUT -1 ; On my system
  31. @INPUT -2 ; On my system
  32. @HALT 0 ; Return to monitor

Example assembler output (note: line numbers are not part of the assembler output):

  1. 39 -1 3
  2. 41 -1 6
  3. 43 -1 9
  4. 43 -1 12
  5. 45 -1 15
  6. 47 -1 18
  7. 49 -1 21
  8. 45 -1 24
  9. 51 -1 27
  10. 43 -1 30
  11. 53 -1 33
  12. 55 -1 36
  13. 57 57 0
  14. 72
  15. 69
  16. 76
  17. 79
  18. 32
  19. 87
  20. 82
  21. 68
  22. 33
  23. 0
  24. 0
  25. 1
  26. -1
  27. -17

Note that the ".label" command exports variable values one per line while the "label:" command exports as a triplet (i.e. a SUBLEQ instruction).

Self Modifying Code - Part 2

The following code fragments sets up a pointer [ADDR1] to pointer [ADDR2] copy that returns the DATA copied:

( SET SYSTEM DEFAULTS) @INPUT -1 @OUTPUT -2 @HALT 0 @Z -9 @T -10 @SP -11 ( VARIABLES ) @A -12 @B -13 @C -14 @D -15 @E -16 @F -17 @L -18 @H -19 @I -20 @J -21 @K -22 @TOP_OF_FREE_RAM -33 ( POINTER TO POINTER COPY EQUATES ) @PPC -32 @NDATA -23 @SRC -32 @DST -28 @RTN -24 ( POINTER TO POINTER COPY ROUTINE LINES ) @PPC_L1 -32 ; SRC @PPC_L2 -31 ; NDATA @PPC_L3 -30 ; ? (=PPC_L4) @PPC_L4 -29 ; NDATA @PPC_L5 -28 ; DST @PPC_L6 -27 ; ? (=PPC_L7) @PPC_L7 -26 ; T @PPC_L8 -25 ; T @PPC_L9 -24 ; RTN ( COPY ROM CODE TO RAM - THE HARD WAY ) PPC_L1 PPC_L1 ? T T ? PPC_D1 T ? T PPC_L1 ? PPC_L2 PPC_L2 ? T T ? PPC_D2 T ? T PPC_L2 ? PPC_L3 PPC_L3 ? T T ? PPC_D3 T ? T PPC_L3 ? PPC_L4 PPC_L4 ? T T ? PPC_D4 T ? T PPC_L4 ? PPC_L5 PPC_L5 ? T T ? PPC_D5 T ? T PPC_L5 ? PPC_L6 PPC_L6 ? T T ? PPC_D6 T ? T PPC_L6 ? PPC_L7 PPC_L7 ? T T ? PPC_D7 T ? T PPC_L7 ? PPC_L8 PPC_L8 ? T T ? PPC_D8 T ? T PPC_L8 ? PPC_L9 PPC_L9 ? T T ? PPC_D9 T ? T PPC_L9 ?

T T JMP ( POINTER TO POINTER COPY CODE TO BE MOVED ) .PPC_D1 SRC .PPC_D2 NDATA .PPC_D3 PPC_L4 .PPC_D4 NDATA .PPC_D5 DST .PPC_D6 PPC_L7 .PPC_D7 T .PPC_D8 T .PPC_D9 RTN

JMP: ( CALL POINTER TO POINTER COPY WITH DATA COPY ) SRC SRC ? ; SET SOURCE ADDRESS T T ? ADDR1 T ? ; ADDR1 IS LOCAL T SRC ? DST DST ? ; SET DESTINATION ADDRESS T T ? ADDR2 T ? ; ADDR2 IS LOCAL T DST ? RTN RTN ? ; SET RETURN ADDRESS T T ? RETURN T ? ; RETURN IS LOCAL T RTN ? T T PPC ; JUMP TO POINTER TO POINTER COPY DATA DATA RETURN: ? ; RETURN ADDRESS NDATA DATA ? ; SAVE COPY IN LOCAL DATA

This seems to complete self modifying code as DATA=[ADDR] and [ADDR]=DATA can be generated with PPC (Pointer to Pointer Copy) and existing assembler tools (i.e. getting the address of the DATA variable).

AlanX

Discussions