6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 8:54 am

All times are UTC




Post new topic Reply to topic  [ 58 posts ]  Go to page Previous  1, 2, 3, 4  Next
Author Message
PostPosted: Wed Feb 18, 2015 8:08 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
granati wrote:
BigDumbDinosaur

Of course i posted just few simple examples for educational use, for beginners, and for show the power of the 65816 in stack managment and direct page addressing. Obviously the best way is to use your set of macros.
About the fact if is better push Always 16 bit value, i think yes, even if 65816 don't suffer of word alignment problem. For example the PEI instruction too is useful for push 16 bit variables, especially if parameters are no constants. Anyway sometimes happen that variable parameters are pushed with registers (for example local variables that are on stack). Anyway the fact that stack can be addressed with direct page addressing too make the PEI istruction very powerful.

Something that I had fooled around with was temporarily changing DP to point to SP+1 as direct page so DP addressing could be used instead of stack-relative. The problem comes in calling other functions that also use DP. Unless all functions define a local DP in this fashion you end up with a big mess.

From a performance standpoint, nothing is gained by setting DP to SP+1, unless SP+1 coincidentally aligns with a page boundary. If DP is $xxYY, where YY is not $00, DP accesses take as much time as absolute ones.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 18, 2015 8:48 pm 
Offline

Joined: Mon Jun 24, 2013 8:18 am
Posts: 83
Location: Italy
BigDumbDinosaur wrote:
granati wrote:
BigDumbDinosaur

Of course i posted just few simple examples for educational use, for beginners, and for show the power of the 65816 in stack managment and direct page addressing. Obviously the best way is to use your set of macros.
About the fact if is better push Always 16 bit value, i think yes, even if 65816 don't suffer of word alignment problem. For example the PEI instruction too is useful for push 16 bit variables, especially if parameters are no constants. Anyway sometimes happen that variable parameters are pushed with registers (for example local variables that are on stack). Anyway the fact that stack can be addressed with direct page addressing too make the PEI istruction very powerful.

Something that I had fooled around with was temporarily changing DP to point to SP+1 as direct page so DP addressing could be used instead of stack-relative. The problem comes in calling other functions that also use DP. Unless all functions define a local DP in this fashion you end up with a big mess.

From a performance standpoint, nothing is gained by setting DP to SP+1, unless SP+1 coincidentally aligns with a page boundary. If DP is $xxYY, where YY is not $00, DP accesses take as much time as absolute ones.


Access stack with DP register can be useful just if the sum of the locals and parameters is above 255 bytes or if a local is an array and need to be indexed, otherwise is better of course use directly the S register. As alternate, can be useful access the stack with absolute indexed address in bank 0 using X or Y like "base pointer"; i think all depend on real situation. Example: if you want write a "strcat" function that accept 2 long pointer to 2 strings maybe is better to use the DP access (hmmm.... bad thing that don't exist the LDA [$XX,S],Y addressing...) and take advantage of the existence of the LDA [$XX],Y addressing. In this case the alternative is: or use long pointer in direct page (but reentrancy...) or use self-modify code and "long absolute indexed" addressing (storing in the fly the long pointer in the code, i.e. replace on an LDA $BB:AAAA,X the BB and AAAA with true values taken from parameters... of course if the routine is not recursive).

_________________
http://65xx.unet.bz/ - Hardware & Software 65XX family


Top
 Profile  
Reply with quote  
PostPosted: Wed Feb 18, 2015 11:00 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
granati wrote:
Access stack with DP register can be useful just if the sum of the locals and parameters is above 255 bytes or if a local is an array and need to be indexed, otherwise is better of course use directly the S register. As alternate, can be useful access the stack with absolute indexed address in bank 0 using X or Y like "base pointer"; i think all depend on real situation. Example: if you want write a "strcat" function that accept 2 long pointer to 2 strings maybe is better to use the DP access (hmmm.... bad thing that don't exist the LDA [$XX,S],Y addressing...) and take advantage of the existence of the LDA [$XX],Y addressing. In this case the alternative is: or use long pointer in direct page (but reentrancy...) or use self-modify code and "long absolute indexed" addressing (storing in the fly the long pointer in the code, i.e. replace on an LDA $BB:AAAA,X the BB and AAAA with true values taken from parameters... of course if the routine is not recursive).

Recursion with the 65C816 implicitly requires that DP not be used by more that one function at a time. Relocating DP to SP+1 of course satisfies that requirement, as long as every function understands what is going on. Your only concern then is the rate at which stack space is being consumed. The key to controlling that would be to shift the stack pointer only by the number of DP bytes that are actually needed, and making sure that indexing doesn't go above that arbitrary range.

As for a strcat function (my 65C816 string library has strcat), this is a case where MVN and MVP are far more efficient than load/store via DP or SP-relative addressing. There's no way you can write a load/store loop that can perform as quickly as the seven Ø2 cycles per byte capability of MVN and MVP. The only caveat is that strcat can't be recursive, since self-modifying code is required to set the banks for the MVN or MVP instruction.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Thu Feb 19, 2015 5:31 am 
Offline

Joined: Mon Jun 24, 2013 8:18 am
Posts: 83
Location: Italy
BigDumbDinosaur

I see your string library: a very nice work. I think your next effort will be a string library with long pointer; why limit string just in one bank? And why avoid spanning over bank?

About MVN/MVP.... no doubts....these are more fast of any load-and-store sequence. But.... need to know in advance the bytes counting to move. In your implementation of "strcat" function you do 2 loop: first loop to find the ending of first string, the second loop for find the lenght of second string; after a MVP for append second string to the first one. I think that second loop can be used to directly append bytes to first string. Anyway, just 2 different standpoint of 2 different "brains" about the implementation.

Marco

_________________
http://65xx.unet.bz/ - Hardware & Software 65XX family


Top
 Profile  
Reply with quote  
PostPosted: Thu Feb 19, 2015 6:10 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
granati wrote:
BigDumbDinosaur

I see your string library: a very nice work. I think your next effort will be a string library with long pointer; why limit string just in one bank? And why avoid spanning over bank?

About MVN/MVP.... no doubts....these are more fast of any load-and-store sequence. But.... need to know in advance the bytes counting to move. In your implementation of "strcat" function you do 2 loop: first loop to find the ending of first string, the second loop for find the lenght of second string; after a MVP for append second string to the first one. I think that second loop can be used to directly append bytes to first string. Anyway, just 2 different standpoint of 2 different "brains" about the implementation.

Marco

The prohibition against spanning banks has to do with MVN and MVP. Neither can cross bank boundaries.

I'll probably revisit the string library soon, at which time I may reorganize some of the code. My implementation isn't necessarily the most elegant, as I wrote the functions to support some of my other programming activities. I was looking more for quick development than greatest flexibility.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Fri Feb 20, 2015 10:37 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
Anyone who has more than 15 minutes experience with 6502 assembly language knows about zero page, aka page zero.  For the benefit of those new to the 6502, zero page is so-called because the most significant byte (MSB) of the address is $00.  That this is so is used to advantage by the 6502 in the form of the zero page addressing modes.

Reads and writes on zero page are on average about 25 percent faster that reads and writes on higher addresses, mainly because the instruction's operand has only one byte, not two.  Hence the 6502 doesn't have to load an MSB when it fetches the address from the program, eliminating a clock cycle from program execution.

Aside from the faster execution of zero page loads and stores, there are some addressing modes that only work with zero page locations, such as (<dp>,X) and (<dp>),Y.  Hence usage of zero page in many cases is heavy and in some systems, much of zero page is dedicated to the operating system and in the case of machines with resident BASIC interpreters, BASIC run-time variables.

The 65C816 also has zero page addressing, but refers to that memory range as "direct page" because the MPU's notion of zero page doesn't necessarily have to be in the physical zero page.  One of the 65C816's registers is the direct page register, DP, which holds a 16-bit address that points to the start of the “logical” zero page.  Following power-on or reset, DP will contain $0000, which makes the 65C816 see direct page at the physical zero page.

It is possible to change DP with a simple instruction sequence, such as the following:

Code:
         rep #%00100000        ;16 bit accumulator
         lda #<new_dp>         ;new 16 bit direct page address
         tcd                   ;transfer it to DP

Prior to doing so, you can save the current DP setting on the stack with PHD and later restore it with PLD.

The ability to change the location of direct page gives rise to several potential programming tricks that are unique to the 65C816.  Subroutines can be given ephemeral direct pages so they can take advantage of quicker execution, as well as a 65C816-unique addressing mode called “indirect long.”

An indirect long instruction is notated as [<dp>], in which <dp> is the location of a 24-bit address stored on direct page in the usual 6502 little-endian style.  Since the address stored at <dp> is, in effect, a 24-bit pointer, a fetch or store can occur anywhere in the 65C816's 16 megabyte addressing range without regard to bank boundaries.  Further to this, an “indirect long indexed” addressing mode, notated as [<dp>],Y, is also available.  If the index registers are set to 16 bits, it is possible to access a wide address range with succinct code.

In a subroutine, DP can be pointed at space that has been allocated on the stack, making the use of [<dp>] and [<dp>],Y practical and easy within a function (subroutine) without “clobbering” the main direct page.  In general, the code to do so would be as follows:

Code:
         rep #%00110000        ;16-bit registers
         phd                   ;save currect DP for later restoration
         sec
         tsc                   ;copy SP to accumulator
         sbc !#4               ;allocate 4 bytes on the stack...
;
;   —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
;   The ‘!#’ notation means assemble a 16-bit operand.
;   —-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-—-
;
         tcs                   ;update stack pointer
         inc A                 ;point to offset $00 in stack workspace
         tcd                   ;that becomes the start of direct page
         ldx !#targ & $FFFF    ;target address least significant word (LSW)
         ldy !#targ >> 16      ;target address most significant word (MSW)
         stx $00               ;set LSW of target address
         sty $02               ;set MSW of target address
         sep #%00100000        ;8-bit accumulator
         lda [$00]             ;fetch byte from remote location
;
;   ...or, could write the above instruction as...
;
         lda [$00],y           ;if indexing over data source
;
;         ...process data as required...
;
;   ...here we clean up the stack before moving onward...
;
         rep #%00100000        ;16-bit accumulator if not already selected
         clc
         tsc                   ;current SP to accumulator
         adc !#4               ;reclaim workspace
         tcs                   ;update SP
         pld                   ;restore old DP location
;
         ...program continues...

The above example makes use of the notation supported by the Kowalski assembler.

A local direct page also makes it possible to temporarily set up indexes and counters that can be manipulated more rapidly than if they were in absolute locations.  So tinkering with DP can produce all sorts of interesting programming scenarios.

Before you start going nuts and giving every function in your program an ephemeral direct page, consider that when DP does not point to the physical zero page, a direct page access is really an absolute access.  For example, if I/O hardware in your system is at $00D000, DP is changed to point to $D000 in order to speed up I/O hardware accesses and an index that is needed by a device driver is located in the real zero page, that index will not be accessible.  Such indexing is common with UART drivers to index the queues that temporarily hold inbound and outbound data.  So you can see that tinkering with DP is not advisable in all cases.

Something to consider when moving DP to the stack is when an interrupt occurs, your interrupt handler may be expecting DP to be somewhere other than where you currently have it.  Needless to say, you must arrange for the interrupt handler to save the state of DP and reset it to the system default before doing any processing that accesses direct page—and then restore DP upon exit.  Failing to correctly account for the state of DP could cause your interrupt handler to inadvertently scribble on some part of the active stack space and make a major mess.

Lastly, while DP can be set to any address in bank $00, some of the speed advantage of direct page addressing will be lost if DP is not pointing at a page boundary.  Hence setting DP to $D040, for example, to have it align with a device register will accomplish little in the way of improving performance, as a one clock cycle penalty will be applied to all direct page accesses.  On the other hand, if DP is set to $D000 and the device register at $D040 is accessed with an instruction such as LDA $40, the instruction will execute in three clock cycles, versus the four required if DP is not page-aligned.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Last edited by BigDumbDinosaur on Tue Nov 21, 2023 1:57 am, edited 3 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Fri Feb 20, 2015 10:50 pm 
Offline

Joined: Mon Jun 24, 2013 8:18 am
Posts: 83
Location: Italy
A possible COP handler to implement system calls

Code:
; This COP software interrupt handler is intended to be used as
; interface to system call for bios/o.s.
; This handler can accept parameters passed by register and
; parameter passed by stack and in this case make stack cleanup.
; The COP instruction accept a signature byte so is possible
; handle 256 system calls (can be expanded with a second signature byte).
; The handler is table-driven: a table of 1024 bytes can hold the long
; pointer to implementation function (3 bytes) plus one byte that hold
; the bytes count of parameters on stack (4 bytes per function).
;
; For example suppose that we will implement a function that write N bytes
; to a file handle H from a buffer B, we need 3 parameters:
; 1) the handle H of file (2 byte)
; 2) the long pointer to buffer B (4 bytes)
; 3) the count N of bytes to write (2 bytes)
; the assumption here is that the max. number of bytes to write is $FFFF
; we suppose that the system call is the function number $xx, and that:
; H is stored in direct page location $hh and $hh+1
; long pointer to buffer is stored in direct page locations $bb, $bb+1, $bb+2
; N is stored in direct page locations $nn, $nn+1
; the sequence for call the function "write" is:
;
;   pei   ($hh)   ; push H
;   pei   ($bb+2)   ; push bank that hold buffer B
;   pei   ($bb)   ; push address of buffer B
;   pei   ($nn)   ; push N
;   cop   $xx   ; call function "write"
;   bcs   ERROR   ; carry mean error
;   ...      ; here ok, no failure
;   ...
; ERROR:      ; error handler
;   ; Y hold the error code
;
; The handler use a table in bank 0 that hold the effective address
; of the routine that implement the function plus the count of bytes
; passed as parameters on stack; this table, labeled SYSTBL, need so
; of 4 bytes per function: 256*4 = 1024 bytes.
; Suppose that the implementation of the function "write" is
; at address $FFA673, and we know that the bytes counting of parameters
; is 8, at address SYSTBL + ($xx*4) we have stored the bytes:
;
;   $73   $A6   $FF   $08
;
; The handler call the right function and restore the stack before exit.
; It use 3 location in true page 0 (COPPtr, COPPtr+1, COPPtr+2) and modify
; the code itself (for call the right function) so is reentrant only if not
; called by an interrupt handler. Take care about this. But not need to call
; a system function in an interrupt handler. This long pointer in true page 0
; is used just to fetch the signature byte, while others variables are stored
; on stack so the effective implementation subroutine can call safety others
; system functions by way of the cop instruction (of course the implementation
; subroutine must be reentrant).
;
; below the stack frame after the handler save registers on the stack:
;
;   ---------
;   |  PBR  |   0F
;   ---------
;   |  PCH  |   0E
;   ---------   
;   |  PCL  |   0D
;   ---------
;   |   P   |   0C
;   ---------
;   |   B   |   0B
;   ---------
;   |   A   |   0A
;   ---------
;   |  XH   |   09
;   ---------
;   |  XL   |   08
;   ---------
;   |  YH   |   07
;   ---------
;   |  YL   |   06
;   ---------
;   |  DPH  |   05
;   ---------
;   |  DPL  |   04
;   ---------
;   |  DBR  |   03
;   ---------
;   | CNTH  |   02
;   ---------          --> CNT bytes count of parameters
;   | CNTL  |   01
;   ---------
;
; equates for access stack offset data
STKCNT      .SET   $01
STKYR      .SET   $06
STKXR      .SET   $08
STKCR      .SET   $0A
STKBR      .SET   $0B
STKSR      .SET   $0C
STKPCL      .SET   $0D
STKPBR      .SET   $0F
STKNVAR      .SET   $0F

_COPhndl:
   rep   #$30      ; A/MEM/X/Y -> 16 bit
   .LONGA   on
   .LONGI   on
   pha         ; save C in stack
   phx         ; save X(16) in stack
   phy         ; save Y(16) in stack
   phd         ; save DPR in stack
   phb         ; save DBR in stack
   lda   #0
   tax         ; X = 0
   pha         ; params byte count in the stack ( = 0)
   tcd         ; set DPR = $0000
   phk         ; set DBR = PBR = $00
            ; remember that cop handler is in bank 0 !
   plb
   lda   STKPCL,s   ; load PC saved in stack
   dec   a      ; pointer to signature byte
   sta   COPPtr      ; save long pointer
   sep   #$30      ; A/MEM/X/Y -> 8 bit
   .LONGA   off
   .LONGI   off
   txa
   xba         ; B = 0
   lda   STKPBR,s   ; PBR bank where COP was executed
   sta   COPPtr+2
   lda   STKSR,s      ; fetch saved P in stack
   and   #$FE      ; clear carry in saved P
   sta   STKSR,s
   bit   #40      ; check if IRQ was enabled
   bne   ?04      ; NO
   cli         ; enable IRQ
?04:   lda   [COPPtr]   ; fetch signature byte
   rep   #$30      ; now C = $00XX (B was cleared above)
   .LONGA   on
   .LONGI   on
   asl   a      ; index * 4   
   asl   a
   tax         ; index to access SYSTBL
   ldy   SYSTBLE_ADDR,x   ; address of function
   lda   SYSTBLE_ADDR+2,x ; A = bank, B = count
?06:   sty   ?08+1      ; modify code on the fly
   sep   #$30      ; all 8 bit
   .LONGA   off
   .LONGI   off
   sta   !?08+3
   xba         ; A = bytes count of params
   sta   STKCNT,s
?08:   jsl   $000000      ; here call the function
            ; will return with RTL
   bcc   ?16      ; no error
   sta   STKYR,s      ; return error in Y
   lda   #0
   sta   STKYR+1,s
   lda   STKSR,s      ; saved P in stack
   ora    #$01      ; set carry in saved P
   sta   STKSR,s
?16:   ; epilogue code   
   rep   #$30      ; all 16 bit
   .LONGA   on
   .LONGI   on
   lda   STKCNT,s   ; number of params bytes in the stack
   beq   ?20      ; no params -- skip stack cleaning
   clc
   tsc         ; C = stack pointer
   adc   #STKNVAR   ; add size of stack vars
   tax         ; source pointer for data move 
   adc   STKCNT,s   ; add params bytes count
   tay         ; dest pointer for data move
   lda   #STKNVAR-1   ; move bytes count
   mvp   #0, #0      ; cleanup stack
   tya         ; new stack pointer
   tcs
?20:   pla         ; skip STKCNT
   plb         ; restore DBR
   pld         ; restore DPR
   ply         ; restore Y
   plx         ; restore X
   pla         ; restore C
   rti         ; restore P and return



_________________
http://65xx.unet.bz/ - Hardware & Software 65XX family


Top
 Profile  
Reply with quote  
PostPosted: Sat Feb 21, 2015 2:19 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
granati wrote:
A possible COP handler to implement system calls

I discuss a different way of doing this in my 65C816 interrupt article, in which the API index is passed in the accumulator and all parameters are passed via the stack. This is the method used by both UNIX and Linux kernel APIs, and avoids the gyrations needed to retrieve COP's signature from the bank in which the caller is running.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Sat Feb 21, 2015 7:31 am 
Offline

Joined: Mon Jun 24, 2013 8:18 am
Posts: 83
Location: Italy
BigDumbDinosaur wrote:
granati wrote:
A possible COP handler to implement system calls

I discuss a different way of doing this in my 65C816 interrupt article, in which the API index is passed in the accumulator and all parameters are passed via the stack. This is the method used by both UNIX and Linux kernel APIs, and avoids the gyrations needed to retrieve COP's signature from the bank in which the caller is running.



As Always....different point of view. I preffered to leave free all registers beacuse in development of bios/o.s. for my 65816 machine i realized that for most system calls is enought pass parameters in registers. Fetch the signature byte have just a little little effect on performance. And have a pointer to signature byte make easy to coding parameters "online" (i.e.: a static string, null terminated, that follow the COP instruction).

_________________
http://65xx.unet.bz/ - Hardware & Software 65XX family


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 22, 2015 5:21 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
granati wrote:
As Always....different point of view. I preffered to leave free all registers beacuse in development of bios/o.s. for my 65816 machine i realized that for most system calls is enought pass parameters in registers. Fetch the signature byte have just a little little effect on performance. And have a pointer to signature byte make easy to coding parameters "online" (i.e.: a static string, null terminated, that follow the COP instruction).

Well, you could push the API index number along with the API parameters stack frame and pick it up inside the API front end. That would eliminate having to get the COP signature.

Over the years I've seen where operating system kernel designers go through considerable trouble to maintain a uniform API no matter which operating system service is being called. It makes life easier for those folks who develop the standard API library—all the code works the same, with only the parameter stack frame and API index varying from call to call. Using the registers in one call and a stack frame in another complicates library development and increases the likelihood of unexpected side effects.

As for in-lining data in a program, that is a Commodore-inspired aberration that I hope to never encounter.¹ :lol:

———————————————————
¹Of course, Commodore wasn't the only one, but they may have started it, as examples of this sort of thinking can be found in all of their BASIC ROMs, going back to the first PET.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Last edited by BigDumbDinosaur on Sun Feb 22, 2015 6:14 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 22, 2015 7:58 am 
Offline

Joined: Mon Jun 24, 2013 8:18 am
Posts: 83
Location: Italy
BigDumbDinosaur wrote:
granati wrote:
As Always....different point of view. I preffered to leave free all registers beacuse in development of bios/o.s. for my 65816 machine i realized that for most system calls is enought pass parameters in registers. Fetch the signature byte have just a little little effect on performance. And have a pointer to signature byte make easy to coding parameters "online" (i.e.: a static string, null terminated, that follow the COP instruction).

Well, you could push the API index number along with the API parameters stack frame and pick it up inside the API front end. That would eliminate having to get the COP signature.

Over the years I've seen where operating system kernel designers go through considerable trouble to maintain a uniform API no matter which operating system service is being called. It makes life easier for those folks who develop the standard API library—all the code works the same, with only the parameter stack frame and API index varying from call to call. Using the registers in one call and a stack frame in another complicates library development and increases the likelihood of unexpected side effects.

As for in-lining data in a program, that is a Commodore-inspired aberration that I hope to never encounter. :lol:



Ehehehe....right....aberration.... Apple too inspired this aberration. Anyway, when parameters are constants, from assembler point of view programming, is very useful this aberration, at least i find useful. Of course this will be avoided in writing functions for high level Language.
In fact any machine implement system call in own way and the common interface, for portability, is the wrapper, for example, in "libc" library. No matter the way the system call was implemented in machine Language.

_________________
http://65xx.unet.bz/ - Hardware & Software 65XX family


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 22, 2015 12:25 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
granati wrote:
BigDumbDinosaur wrote:
granati wrote:
... coding parameters "online" (i.e.: a static string, null terminated, that follow the COP instruction).
... As for in-lining data in a program, that is a Commodore-inspired aberration that I hope to never encounter. :lol:


Ehehehe....right....aberration.... Apple too inspired this aberration...

Acorn did the same thing, both with a routine to print out a string following a JSR (surely quite a common trick) and also BRK.


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 22, 2015 3:52 pm 
Offline

Joined: Mon Jan 26, 2015 6:19 am
Posts: 85
BigDumbDinosaur wrote:
As for in-lining data in a program, that is a Commodore-inspired aberration that I hope to never encounter. :lol:

??? What's wrong with in-lining constants? That is standard practice in Forth (using (LIT) or (SLIT) ). In-lining variable data (self modifying code) is, of course, a sin.

Actually, standard Forths go a little too far by combining the name, code and data in the same word. It makes for efficient allocation of RAM but makes ROMming almost impossible. That's why my version separates all three.


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 22, 2015 5:43 pm 
Offline
User avatar

Joined: Wed Feb 13, 2013 1:38 pm
Posts: 589
Location: Michigan, USA
theGSman wrote:
... In-lining variable data (self modifying code) is, of course, a sin.


May I ask why, please?


Top
 Profile  
Reply with quote  
PostPosted: Sun Feb 22, 2015 6:07 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
Self modifying code...

  • must necessarily reside (or be copied into) RAM
  • has the potential to be confusing, but only if the author hasn't bothered to include adequate comments
  • mustn't call itself (recurse), or have potential to be called in multiple contexts (eg foreground as well as interrupt-service). IOW reentrancy is a no-no.

These issues hardly make its usage a sin. I suspect theGSman was being humorous, although some folks do have strong feelings on the subject. IMO it's a just another tradeoff, worthwhile in some circumstances but not in others.

-- Jeff

Edit: add 3rd point

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Last edited by Dr Jefyll on Mon Aug 22, 2016 1:52 pm, edited 2 times in total.

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

All times are UTC


Who is online

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