Array Manager

JMP $FCE2
MarcWalters
Member
Member
Posts: 55
Joined: Wed Jun 11, 2014 2:33 pm
Location: Lake Macquarie, NSW, Australia
Contact:

Array Manager

Post by MarcWalters »

This is a work in progress, but useable and bug-free as it is. Format is CBM Prg Studio.

Description
Array Manager provides a way to coerce a block of memory within a 24-bit address space to a fixed item-length array.
An Array can contain 0 to 65535 Items.
An Item can be 1 to 65536 bytes in length, although that length is the same for each item in the Array.
Each Array can have a unique Record Type associated with it and there are operations to support Record Operations on the Items.

Read/Write operations are supported by a dynamic Cursor.
The Cursor Step is a signed 8-bit integer that steps each operation. The Cursor operation modes include constraints - in which Lower and Upper constraints are recognised, and Loop Flag - which lets the Cursor either Wrap or Stop at a Constraint or Array Boundary.

Caching is used for commonly accessed information that would normally be calculated. Also, the most recently used Array Handle is stored, and is used by some routines.

Why?
It tames memory and serves as a structural base for related tools.

Integration
Although presented here in isolation, the Array Manager slots neatly into a suite of tools I've written such as Record Manager and Function Manager. Plus there are the soon-to-come goodies including Search/Replace, Binary Set Operations and a General Purpose Serialiser.

Design Overview
The Array Descriptor (as well as the actual Array data) can be created in a static block by the user in order to retain direct access to its elements. It maintains an external reference to itself, which allows other programs to access its information via a vector/index system. This minimises the amount of memory the Array Manager reserves to just the handle list and a table of addresses.

Final Notes
The code is spread across several Project Files, and so some refitting will have to be done to get them to work. Once it's all complete I'll make the full set of project files available for download.

The Item Insert, Delete and Clear subroutines are not present, but are listed in the comments.
The Transfer Routine is temporary. It is a safe 16-bit only transfer routine and works only in the first 64K of RAM.

Some of the subroutines in the main Array code may seem wasteful, but were written like that for bug-testing purposes. I'll optimise the code for the final release, and will update the older comments.

Bonus: The Record system can be used as an indexed linked list.

Subroutines
The table below, plus the examples elsewhere, should be self-explanatory.

Code: Select all

; ARRAY OPERATIONS
; Init
; Create array: Create ( rAX Base ) : rA Handle, rSC ErrorF 
; Delete array: Delete ( rA Handle ) : rSC ErrorF 
; Clear array:  Clear ( rA Handle )

; Get Array Address: GetAryAdr ( rA Handle ) : rAXY Address
; Get Array Max Index: GetAryMaxIdx ( rA Handle ) : rAX Address
; Get Array Top Index: GetAryTopIdx ( rA Handle ) : rAX Address
; Get Current Array: GetCurAry : rA Handle

; Set Array Top Index: SetAryTopIdx ( rA Handle, rXY Top Index )
; Set Current Array: SetCurAry ( rA Handle )

; ITEM OPERATIONS
; Get Array Item Size: GetAryItmSiz ( rA Handle ) : rAX Address
; Get Array Item Address: GetAryItmAdr ( rA Array Handle, rXY Item Index ) : rAXY Address

; Set Array Item Size: SetAryItmSiz ( rA Handle, rXY Item Size )

; CURSOR OPERATIONS
; Get Array Cursor Position: GetAryCsrPos ( rA Handle ) : rAX
; Get Array Cursor Address: GetAryCsrAdr ( rA Handle ) : rAXY
; Get Array Cursor Mode: GetAryCsrMod ( rA Handle ) : rA
; Get Array Cursor Step: GetAryCsrStp ( rA Handle ) : rA
; Get Array Cursor Min: GetAryCsrMin ( rA Handle ) : rAX
; Get Array Cursor Max: GetAryCsrMax ( rA Handle ) : rAX

; Set Array Cursor Position: SetAryCsrPos (.A Handle, rXY Cursor Position )
; Set Array Cursor Mode: SetAryCsrMod ( rA Handle, rX Cursor Mode )
; Set Array Cursor Step: SetAryCsrStp ( rA Handle, rX Cursor Step )
; Set Array Cursor Min: SetAryCsrMin ( rA Handle, rXY Cursor Min )
; Set Array Cursor Max: SetAryCsrMax ( rA Handle, rXY Cursor Max )

; RECORD OPERATIONS
; Get Array Record Type: GetAryRecType ( rA Handle ) : rA
; Get Current Field: GetAryCurFld ( rA Handle ) : rA
; Get Current Field Datatype: GetAryCurFldDat ( rA Handle ) :  rA (via Record Manager)
; Get Current Field Length: GetAryCurFldLen ( rA Handle ) :  rAX (via Record Manager)
; Get Current Field Offset: GetAryCurFldOs ( rA Handle ) : rAX (via Record Manager)
; Get Cursors' Current Field Address: GetAryCsrFldAdr ( rA Handle ) : rAXY (Calculated)

; Set Array Record Type: SetAryRecType ( rA Handle B, rX Record Type ) 
; Set Current Field: SetAryCurFld ( rA Handle, rX Field )

; FIELD-CURSOR OPERATIONS
; Write Field: CsrFldWrite ( rAXY 24-bit Source (uses Current Array) )
; Read Field: CsrFldRead ( rAXY 24-bit Destination (uses Current Array) )

; ITEM-CURSOR OPERATIONS
; Write Item: CsrWrite ( rAXY 24-bit Source (uses Current Array) )
; Read Item: CsrRead ( rAXY 24-bit Destination (uses Current Array) )
; ***TODO
; DeleteItem: DelItem ( rA Handle )
; InsertItem: InsItem ( rAXY 24-bit Source (uses Current Array) )
; Clear Item: ClrItem ( rA Handle, rX Value, rY Direction )
Example: Create An Array

Code: Select all

         jsr Ary_Init$
         
         ; Ary_Create
         lda #<Array1Des
         ldx #>Array1Des
         jsr Ary_Create$

         ; Set the Cursor to the 2nd Item
         lda Array1Des
         ldx #<$0001
         ldy #>$0001
         jsr Ary_SetAryCsrPos$
         
         ; Copy the 2nd Array Item to Text Screen Line 1 (24-bit address)
         lda #<$0400
         ldx #>$0400
         ldy #0
         jsr Ary_CsrRead$

         ; The Cursor automatically stepped forward. This copies the 3rd Array Item to Screen line 2
         lda #<$0428
         ldx #>$0428
         ldy #0
         jmp Ary_CsrRead$


Array1Des
@Id      byte 255
@Base    word Array1Base
         byte 0
@ItmSiz  word 5                     ; Actual length in bytes
@MaxIdx  word 4
@TopIdx  word 3
@CleafF  byte 0
@RecTyp  byte 255
@CurFld  byte 0
@CurFldOs  word 0
@CsrPos  word 0
@CsrAdr  byte 0,0,0
@CsrMod  byte 0   ; Bit 1 = Wrap, Bit 2 = Constrain, Bit
@CsrStp  byte 1
@CsrMin  word 0
@CsrMax  word 0

Array1Base ; 5 Items, each 6 bytes in size 
         byte 00,01,02,03,04,06     ; Index 0
         byte 10,11,12,13,14,15     ; Index 1
         byte 20,21,22,23,24,26     ; Index 2
         byte 30,31,32,33,34,36     ; Index 3
         byte 00,00,00,00,00,00     ; Index 4

Code: Select all

;* = $C600

; --------------------------
; Array Manager
; --------------------------

; zArrayManager$ = $FB ; If isolated

; ----------
; ZERO-PAGE
zAryDesVec = zArrayMan$             ; 2 bytes
zAryDesVal = zAryDesVec + 2         ; 3 bytes, usually address in reverse E,H,L order
; ----------
; PUBLIC
Ary_Init$         = Init
Ary_Create$       = Create
Ary_Delete$       = Delete
Ary_Clear$        = Clear

Ary_GetAryAdr$    = GetAryAdr
Ary_GetAryMaxIdx$ = GetAryMaxIdx
Ary_GetAryTopIdx$ = GetAryTopIdx
Ary_GetCurAry$ = GetCurAry

Ary_SetAryTopIdx$ = SetAryTopIdx
Ary_SetCurAry$    = SetCurAry

Ary_GetAryItmSiz$ = GetAryItmSiz
Ary_GetAryItmAdr$ = GetAryItmAdr

Ary_SetAryItmSiz$ = SetAryItmSiz

Ary_GetAryCsrPos$ = GetAryCsrPos
Ary_GetAryCsrAdr$ = GetAryCsrAdr
Ary_GetAryCsrMod$ = GetAryCsrMod
Ary_GetAryCsrStp$ = GetAryCsrStp
Ary_GetAryCsrMin$ = GetAryCsrMin
Ary_GetAryCsrMax$ = GetAryCsrMax

Ary_SetAryCsrPos$ = SetAryCsrPos
Ary_SetAryCsrMod$ = SetAryCsrMod
Ary_SetAryCsrStp$ = SetAryCsrStp
Ary_SetAryCsrMin$ = SetAryCsrMin
Ary_SetAryCsrMax$ = SetAryCsrMax

Ary_GetAryRecType$         = GetAryRecType
Ary_GetAryCurFld$          = GetAryCurFld
Ary_GetAryCurFldDat$       = GetAryCurFldDat
Ary_GetAryCurFldLen$       = GetAryCurFldLen
Ary_GetAryCurFldOs$        = GetAryCurFldOs
Ary_GetAryCsrFldAdr$       = GetAryCsrFldAdr

Ary_SetAryRecType$ = SetAryRecType
Ary_SetAryCurFld$ = SetAryCurFld

Ary_CsrFldWrite$  = CsrFldWrite
Ary_CsrFldRead$    = CsrFldRead

Ary_CsrWrite$     = CsrWrite
Ary_CsrRead$      = CsrRead

Ary_DelItem$      = DelItem
Ary_InsItem$      = InsItem
Ary_ClrItem$      = ClrItem
; ----------
; LOCAL
MaxArrays = 16
AryDescAdr words MaxArrays
ArrayHdl byte 0,0
         bytes MaxArrays    
CurArray byte 0            ; Current array. Negates need to pass in Array Handle for some operations
; ----------

#Region ; Description

; ARRAY OPERATIONS
; Init
; Create array: Create ( rAX Base ) : rA Handle, rSC ErrorF 
; Delete array: Delete ( rA Handle ) : rSC ErrorF 
; Clear array:  Clear ( rA Handle )

; Get Array Address: GetAryAdr ( rA Handle ) : rAXY Address
; Get Array Max Index: GetAryMaxIdx ( rA Handle ) : rAX Address
; Get Array Top Index: GetAryTopIdx ( rA Handle ) : rAX Address
; Get Current Array: GetCurAry : rA Handle

; Set Array Top Index: SetAryTopIdx ( rA Handle, rXY Top Index )
; Set Current Array: SetCurAry ( rA Handle )

; ITEM OPERATIONS
; Get Array Item Size: GetAryItmSiz ( rA Handle ) : rAX Address
; Get Array Item Address: GetAryItmAdr ( rA Array Handle, rXY Item Index ) : rAXY Address

; Set Array Item Size: SetAryItmSiz ( rA Handle, rXY Item Size )

; CURSOR OPERATIONS
; Get Array Cursor Position: GetAryCsrPos ( rA Handle ) : rAX
; Get Array Cursor Address: GetAryCsrAdr ( rA Handle ) : rAXY
; Get Array Cursor Mode: GetAryCsrMod ( rA Handle ) : rA
; Get Array Cursor Step: GetAryCsrStp ( rA Handle ) : rA
; Get Array Cursor Min: GetAryCsrMin ( rA Handle ) : rAX
; Get Array Cursor Max: GetAryCsrMax ( rA Handle ) : rAX

; Set Array Cursor Position: SetAryCsrPos (.A Handle, rXY Cursor Position )
; Set Array Cursor Mode: SetAryCsrMod ( rA Handle, rX Cursor Mode )
; Set Array Cursor Step: SetAryCsrStp ( rA Handle, rX Cursor Step )
; Set Array Cursor Min: SetAryCsrMin ( rA Handle, rXY Cursor Min )
; Set Array Cursor Max: SetAryCsrMax ( rA Handle, rXY Cursor Max )

; RECORD OPERATIONS
; Get Array Record Type: GetAryRecType ( rA Handle ) : rA
; Get Current Field: GetAryCurFld ( rA Handle ) : rA
; Get Current Field Datatype: GetAryCurFldDat ( rA Handle ) :  rA (via Record Manager)
; Get Current Field Length: GetAryCurFldLen ( rA Handle ) :  rAX (via Record Manager)
; Get Current Field Offset: GetAryCurFldOs ( rA Handle ) : rAX (via Record Manager)
; Get Cursor's' Current Field Address: GetAryCsrFldAdr ( rA Handle ) : rAXY (Calculated)

; Set Array Record Type: SetAryRecType ( rA Handle B, rX Record Type ) 
; Set Current Field: SetAryCurFld ( rA Handle, rX Field )

; FIELD-CURSOR OPERATIONS
; Write Field: CsrFldWrite ( rAXY 24-bit Source (uses Current Array) )
; Read Field: CsrFldRead ( rAXY 24-bit Destination (uses Current Array) )

; ITEM-CURSOR OPERATIONS
; Write Item: CsrWrite ( rAXY 24-bit Source (uses Current Array) )
; Read Item: CsrRead ( rAXY 24-bit Destination (uses Current Array) )
; ***TODO
; DeleteItem: DelItem ( rA Handle )
; InsertItem: InsItem ( rAXY 16-bit Source (uses Current Array) )
; Clear Item: ClrItem ( rA Handle, rX Value, rY Direction )

; ----------

; NOTES
; Array Info is a static block of data that describes an array.
; The AryDescAdr vectors point to it, indexed by a Handle.
;
; Before using routines that use the Array Desc Index, set the vector
;  - Use PIniAryDesVec to preserve registers, or UIniAryDesVec which will modify registers.
;
; To fetch a value from the Array Info, set .Y with the Array Desc Index, eg Base=0
;   then call GetAryDesX[Y], where X=L,W or B, and  Y is the A,X or Y - the first Register
;   in which to place the sequence.
;   If left clear, the values can be obtained from zAryDesVal.
;To set a value, from Array Info, set .Y with the Array Desc Index, eg Base=0
;   then call SetAryDesX[Y]. Y can be A or X only. In most cases it's easier to
;   just set zAryDesVal first then call SetAryDesX.

#EndRegion

; Array Descriptor Indices: Use an index with zAryDesVec to fetch array info.
ArrayId     = 0            ; B
BaseAddress = ArrayID + 1  ; L
ItemSize    = BaseAddress + 3 ; W
MaxIndex    = ItemSize + 2 ; W
TopIndex    = MaxIndex + 2 ; W - Highest used, used by Add() and Cursor loop
ClearF      = TopIndex + 2 ; B - If no values Added
; Record indices
RecType  = ClearF + 1      ; B
CurField = RecType + 1     ; B
; Record cache
CurFldOs = CurField + 1    ; W - Cached when RecordType or CurField changes. Needed to get address at field
; Cursor indices
CsrPos  = CurFldOs + 2     ; W 
CsrAdr  = CsrPos + 2       ; L
CsrMode = CsrAdr + 3       ; B ; Bit 1 = Wrap, Bit 2 = Constrain, Bit 
CsrStep = CsrMode + 1      ; B      
CsrMin  = CsrStep + 1      ; W   
CsrMax  = CsrMin + 2       ; W

#Region ; Array Operations

; ARRAY OPERATIONS

; Array Management
Init     ldx #<ArrayHdl    
         ldy #>ArrayHdl
         lda #MaxArrays
         jmp Hdl_Create$

Create   pha
         txa
         pha
         ldx #<ArrayHdl
         ldy #>ArrayHdl
         jsr Hdl_Allocate$
         bcc @C1                    ; OKAY

         pla                        ; ERROR
         tax
         pla
         rts
         
@C1      asl                        ; Array Index x 2 for storing in Word list
         tay
         pla
         sta AryDescAdr + 1,Y
         sta zAryDesVec + 1
         pla
         sta AryDescAdr,Y
         sta zAryDesVec

         ; Store valid Array Id (Handle). It's useful for user code to fetch the handle from here.
         ; A value of 255 means it is unallocated.
         tya
         lsr
         ldy #ArrayId
         sta (zAryDesVec),Y

         pha                        ; Preserve Handle

         ; Initialise the Cursor Address cache
         jsr ICalcCsrPosAdr         ; Calculate the Cursor Address
         jsr ISetAryCsrAdr          ; Put rAXY into the Cursor Address cache

         pla                        ; Retrieve Handle
         clc                        ; OKAY
         rts                        ; Return with Array Handle
                  
Delete   ldx #<ArrayHdl
         ldy #>ArrayHdl
         jsr Hdl_Deallocate$

         ; Set ArrayId to 255
@C1      jsr PIniAryDesVec          ; NOTE: This sets Current Array to the deallocated ID.   
         lda #255
         ldy #ArrayId
         sta (zAryDesVec),Y
         rts

         rts

Clear    jsr PIniAryDesVec
         ; ClearF = 1
         ldy #ClearF
         lda #1
         sta (zAryDesVec),Y
         
         lda #0
         ldx #3
@L1      ldy @Table,X               ; Clear a set of value caches
         sta (zAryDesVec),Y
         iny
         sta (zAryDesVec),Y
         dex
         bpl @L1
         rts

@Table   byte TopIndex, CsrPos, CsrMin, CsrMax        ; Lookup table of some Array Descriptor indices  

; Array Interrogation        
 
GetAryAdr jsr PIniAryDesVec
IGetAryAdr ldy #BaseAddress
         jmp GetAryDesLA

GetAryMaxIdx jsr PIniAryDesVec
IGetAryMaxIdx ldy #MaxIndex
         jmp GetAryDesWA

GetAryTopIdx jsr PIniAryDesVec
IGetAryTopIdx ldy #TopIndex
         jmp GetAryDesWA

GetCurAry lda CurArray
         rts

; Array Modification

SetAryTopIdx jsr PIniAryDesVec
ISetAryTopIdx stx zAryDesVal
         sty zAryDesVal + 1
         ldy #TopIndex
         jmp SetAryDesW

SetCurAry sta CurArray
         rts

#EndRegion

#Region ; Item Operations
; ITEM OPERATIONS

; Item Interrogation         

GetAryItmSiz jsr PIniAryDesVec
IGetAryItmSiz ldy #ItemSize
         jmp GetAryDesWA

GetAryItmAdr jsr PIniAryDesVec ; slow, brute-force calculation. Use if Item <> Cursor Position 
IGetAryItmAdr jmp CalcAryXYAdr

SetAryItmSiz jsr PIniAryDesVec
ISetAryItmSiz stx zAryDesVal
         sty zAryDesVal + 1
         ldy #ItemSize
         jmp SetAryDesW
#EndRegion

#Region ; Cursor Operations

; CURSOR OPERATIONS

; Cursor Interrogation

GetAryCsrPos jsr PIniAryDesVec
IGetAryCsrPos ldy #CsrPos
         jmp GetAryDesWA

GetAryCsrAdr jsr PIniAryDesVec
IGetAryCsrAdr ldy #CsrAdr
         jmp GetAryDesLA

GetAryCsrMod jsr PIniAryDesVec
IGetAryCsrMod ldy #CsrMode
         jmp GetAryDesBA

GetAryCsrStp jsr PIniAryDesVec
IGetAryCsrStp ldy #CsrStep
         jmp GetAryDesBA

GetAryCsrMin jsr PIniAryDesVec
IGetAryCsrMin ldy #CsrMin
         jmp GetAryDesWA

GetAryCsrMax jsr PIniAryDesVec
IGetAryCsrMax ldy #CsrMax
         jmp GetAryDesWA

; Cursor Modification

SetAryCsrPos jsr PIniAryDesVec
ISetAryCsrPos stx zAryDesVal         ; NOTE: New Item Address Info has to be set
         sty zAryDesVal + 1
         ldy #CsrPos
         jsr SetAryDesW

         ; Calculate new Cursor Address, Long result in zA1
         
         jsr CalcAryItemAdr          

         ; Set Cursor Address
ISetAryCsrAdr sta zAryDesVal
         stx zAryDesVal + 1
         sty zAryDesVal + 2
         ldy #CsrAdr
         jmp SetAryDesL

SetAryCsrMod jsr PIniAryDesVec
ISetAryCsrMod stx zAryDesVal
         ldy #CsrMode
         jmp SetAryDesB

SetAryCsrStp jsr PIniAryDesVec
ISetAryCsrStp stx zAryDesVal
         ldy #CsrStep
         jmp SetAryDesB

SetAryCsrMin jsr PIniAryDesVec
ISetAryCsrMin stx zAryDesVal
         sty zAryDesVal + 1
         ldy #CsrMin
         jmp SetAryDesW

SetAryCsrMax jsr PIniAryDesVec
ISetAryCsrMax stx zAryDesVal
         sty zAryDesVal + 1
         ldy #CsrMax
         jmp SetAryDesW

#EndRegion

#Region ; Record Operations
; RECORD OPERATIONS
 
; Record interrogation

GetAryRecType jsr PIniAryDesVec
IGetAryRecType ldy #RecType
         jmp GetAryDesBA

GetAryCurFld jsr PIniAryDesVec
IGetAryCurFld ldy #CurField
         jmp GetAryDesBA

GetAryCurFldDat jsr PIniAryDesVec
IGetAryCurFldDat ldy #RecType
         jsr GetAryDesBA
         pha
         ldy #CurField
         jsr GetAryDesBA
         tax
         pla
         
         jmp Rec_GetFldDt$           ; A=RecType, X=Field, Result in A

GetAryCurFldLen jsr PIniAryDesVec
IGetAryCurFldLen ldy #RecType
         jsr GetAryDesBA
         pha
         ldy #CurField
         jsr GetAryDesBA
         tax
         pla
         
         jmp Rec_GetFldLen$          ; A=RecType, X=Field, Result in AX

; This is calculated, but I've decided to cache it instead. Will require a rename for its use.
GetAryCurFldOs jsr PIniAryDesVec
IGetAryCurFldOs ldy #RecType
         jsr GetAryDesBA
         pha
         ldy #CurField
         jsr GetAryDesBA
         tax
         pla
         
IGetAryFldOs jsr Rec_GetFldOs$      ; A=RecType, X=Field, Result in AX

         ; Store in cache, return result in rAX
         ldy #CurFldOs
         sta (zAryDesVec),Y
         pha
         txa
         iny
         sta (zAryDesVec),Y
         tax
         pla
         rts

         ; Gets address of field at current Cursor
GetAryCsrFldAdr jsr PIniAryDesVec
IGetAryCsrFldAdr jsr IGetAryCsrAdr  ; Address of Item at Cursor
         sta zA1$          
         stx zA1$ + 1
         sty zA1$ + 2

         ldy #CurFldOs              ; Get Field Offset
         jsr GetAryDesWA
         sta zA2$
         stx zA2$ + 1
         
         ; Add Field Offset to Item address 
         jmp AddLWLA$               ; Long + Word = Long, return in Registers

; Record modification

SetAryRecType jsr PIniAryDesVec
         ldy #RecType
         txa
         jsr SetAryDesBA
         
         lda #0
         ldy #CurField
         jsr SetAryDesBA            ; Set Current Field to 0 
         jmp IGetAryCurFldOs        ; Cache the Offset for the Current Field

SetAryCurFld jsr PIniAryDesVec
         txa
         ldy #CurField
         jsr SetAryDesBA
         jmp IGetAryCurFldOs        ; Cache the Offset for this Field

#EndRegion

#Region ; Field-Cursor Operations

; FIELD-CURSOR OPERATIONS

; Note, incomplete. Does not use Field Datatype to constrain or convert.
; *** To use callbacks for conversion?

AryOpMode         byte 0
CsrWrapF          byte 0
CsrConstF         byte 0
CsrStepValue      byte 0
CsrLim            word 0
CsrLimWrap        word 0
CsrValue          word 0

AOWrite           = 0
AORead            = 1
AOVerify          = 2
AOStep            = 3

; Write to Cursor Item Field from Long Address, AXY = Source Address, uses Current Array
CsrFldWrite jsr AIniAryDesVec
ICsrFldWrite sta zTFerS$
         stx zTFerS$ + 1
         sty zTFerS$ + 2

         jsr IGetAryCsrFldAdr       ; Get Long Address of Field at Cursor Position

         sta zTFerD$
         stx zTFerD$ + 1
         sty zTFerD$ + 2

         jsr IGetAryCurFldLen       ; Get Field Size in AX 
         pha
         txa
         tay
         pla
         tax

         jmp CsrWriteC1 

; Read from Cursor Item Field to Long Address, AXY = Source Address, uses Current Array
CsrFldRead jsr AIniAryDesVec
ICsrFldRead sta zTFerD$
         stx zTFerD$ + 1
         sty zTFerD$ + 2

         jsr IGetAryCsrFldAdr       ; Get Long Address of Field at Cursor Position

         sta zTFerS$    
         stx zTFerS$ + 1
         sty zTFerS$ + 2

         jsr IGetAryCurFldLen       ; Get Field Size in AX 
         pha
         txa
         tay
         pla
         tax

         jmp CsrReadC1 
         
#EndRegion

#Region ; Item-Cursor Operations
; ITEM-CURSOR OPERATIONS (Done)
; Write Item: CsrWrite ( .X.Y 16-bit Source (uses Current Array) )
; Read Item: CsrRead ( .A.X.Y 16-bit Destination (uses Current Array) ) : .A.X.Y Length
; ***TODO
; DeleteItem: DelItem ( .A Handle )
; InsertItem: InsItem ( .A.X.Y 16-bit Source (uses Current Array) )
; Clear Item: ClrItem ( .A Handle, .X Value, .Y Direction )

; Write from Word Address, A = Array, XY = Source Address
CsrWriteWA jsr PIniAryDesVec
         sta CurArray
         lda #0                     ; Ext byte 0

; Write AXY to Ary Csr Pos
; NOTE: Uses Current Array
; NOTE: Set up 16-bit transfer (temporary, until 24-bit transfer routine is written)

; Write to Cursor Item from Long Address, AXY = Source Address, uses Current Array
CsrWrite jsr AIniAryDesVec
ICsrWrite sta zTFerS$
         stx zTFerS$ + 1
         sty zTFerS$ + 2
         
         ldy #CsrAdr                ; Get Long Address at Cursor Position
         jsr GetAryDesLA

         sta zTFerD$
         stx zTFerD$ + 1
         sty zTFerD$ + 2

         ldy #ItemSize
         jsr GetAryDesWX

CsrWriteC1 stx zTFerL$
         sty zTFerL$ + 1
         lda #0
         sta zTFerL$ + 2

         ; Setup for Array Data Operation subroutine
         lda #AOWrite               ; Operation mode, eg Read, Write or Verify
         ldx #<TFer$                ; Setup Callback
         ldy #>TFer$
         jmp AryDatOper

; Read from Word Address, A = Array, XY = Destination Address
CsrReadWA jsr PIniAryDesVec
         sta CurArray
         lda #0                     ; Ext byte 0

; Read to Long Address, AXY = Source Address, uses Current Array
CsrRead  jsr AIniAryDesVec
ICsrRead sta zTFerD$
         stx zTFerD$ + 1
         sty zTFerD$ + 2
         
         ldy #CsrAdr                ; Get Long Address at Cursor Position
         jsr GetAryDesLA

         sta zTFerS$
         stx zTFerS$ + 1
         sty zTFerS$ + 2

         ldy #ItemSize              ; Get Item Size
         jsr GetAryDesWX

CsrReadC1 stx zTFerL$
         sty zTFerL$ + 1
         lda #0
         sta zTFerL$ + 2

         ; Setup for Array Data Operation subroutine
         lda #AORead                ; Operation mode, eg Read, Write or Verify
         ldx #<TFer$              ; Setup Callback
         ldy #>TFer$
         jmp AryDatOper

#EndRegion


#Region ; Data Subroutines

; OPERATIONS
; Thee are a series of operations that are common to many of the routines (read, write, etc).
; For example, all operations that use the cursor share step movement, step constraints and wrap.
; The operation that uses these features is passed in as a Callback address to AryDatOper.

; NOTE 1: The design of AryDatOper is not optimal and I should try a different approach SITF.
; NOTE 2: There is no OOB range testing. It's left up to the user to ensure their step size
;           does not go past a limit. Thus, beyond a step size of 1 there be dragons.
; NOTE 3: Single steps fwd or back could be optimised by adding/subbing field length 
;           instead of using the multiply routine, but I'm unsure how beneficial this will be.

; Manage cursor operation
AryDatOper sta AryOpMode            ; Operation mode, eg Read, Write, Verify or Step
         stx @Operation + 1         ; Setup Callback
         sty @Operation + 2

         lda AryOpMode
         cmp #AOWrite
         beq @Write

         cmp #AOStep                ; No Operation but still Step
         beq @C1                    
         bne @Operation             ; Read and Verify operation

; This first section updates TopIndex if a write operation occurs,
;   and so assumes that the operation 
;   may have been directed at an index higher than TopIndex. 
@Write   ldy #TopIndex              ; If CsrPos > TopIndex then TopIndex = CsrPos 
         jsr GetAryDesWA
         sta zTW1$
         stx zTW1$ + 1
         
         ldy #CsrPos
         jsr GetAryDesWA
         sta zTW2$
         stx zTW2$ + 1

         ldx #zTW1$
         ldy #zTW2$
         jsr CompareZpW
         
         bcc @Operation             ; Branch if Cursor Position <= Top Index
         
         ; Set new Top Index
         lda zTW2$
         ldx zTW2$ + 1
         ldy #MaxIndex
         jsr SetAryDesWA

@Operation jsr $0000; Callback for operation. Could be a Read, Write or Verify
 
         ; Get the Curser Step value. If it -1 or then apply Loop, Constraint or MinMax
@C1      ldy #CsrStep
         jsr GetAryDesBA
         beq @C1a

         jmp StepExit   
              
@C1a     sta CsrStepValue

         ; Setup Cursor's min and max limits
         ldy #CsrPos
         jsr GetAryDesWA
         sta CsrValue
         stx CsrValue + 1

         lda #0
         sta CsrWrapF
         sta CsrConstF

         ldy #CsrMode
         jsr GetAryDesBA
         
         lsr                         
         rol CsrWrapF
         lsr
         rol CsrConstF

         ; Check directiom
         lda CsrStepValue
         bpl StepFwd
         
; Cursor step backward - test for constraint, then test for loop
StepBkwd lda CsrConstF
         bne @ConstLim

         lda #0
         tay
         jmp @ConstLimC1

@ConstLim ldy #CsrMin
         jsr GetAryDesWA
@ConstLimC1 sta CsrLim
         stx CsrLim + 1

         ; Test Cursor Position against limit
         lda CsrValue
         cmp CsrLim
         bne @BackStep
         lda CsrValue + 1
         cmp CsrLim + 1
         beq @BackLimit

@BackStep clc
         lda #0
         sbc CsrStepValue 
         sta CsrStepValue
         
         sec
         lda CsrValue
         sbc CsrStepValue
         tax
         lda CsrValue + 1
         sbc CsrValue + 1
         tay
              
         jmp ISetAryCsrPos          ; XY = New CsrPos

@BackLimit lda CsrWrapF
         bne @BackLimit_C1
         jmp StepExit               ; Stop cursor

@BackLimit_C1 lda CsrConstF
         bne @ConstWrap

         ldy #MaxIndex
         jsr GetAryDesWX

         jmp ISetAryCsrPos          ; XY = New CsrPos

@ConstWrap ldy #CsrMax
         jsr GetAryDesWX

         Jmp ISetAryCsrPos          ; XY = New CsrPos

; Cursor step forward - test for constraint, then test for loop
StepFwd lda CsrConstF
         bne @ConstLim

         ldy #MaxIndex
         jsr GetAryDesWA
         jmp @ConstLimC1

@ConstLim ldy #CsrMax
         jsr GetAryDesWA
@ConstLimC1 sta CsrLim
         stx CsrLim + 1

         ; Test Cursor Position against limit
         ; NOTE: This does not test for Cursor Position outside constrained range.
         ;         I think this should be retained as a "feature" because sometimes
         ;         the user will want to temporarily break out from any MinMax constraints.
         lda CsrValue
         cmp CsrLim
         bne @FwdStep
         lda CsrValue + 1
         cmp CsrLim + 1
         beq @FwdLimit

         ; Add step value to Cursor Position
@FwdStep clc
         lda CsrValue
         adc CsrStepValue
         tax
         lda CsrValue + 1
         adc CsrValue + 1
         tay

         jmp ISetAryCsrPos          ; XY = New CsrPos

@FwdLimit lda CsrWrapF
         beq StepExit               ; Stop cursor

         lda CsrConstF
         bne @ConstWrap

         ldx #0
         ldy #0
         Jmp ISetAryCsrPos          ; XY = New CsrPos

@ConstWrap ldy #CsrMin
         jsr GetAryDesWX

         Jmp ISetAryCsrPos          ; XY = New CsrPos

StepExit rts

; --------------------------------------------------
#Region ; Array Helper Subroutines

; HELPER SUBROUTINES

; The following routines are general get and set 
; for Long, Word or Byte from Array Descriptor lookup.

GetAryDes stx zTB1$
         tya
         clc
         adc zTB1$
         tay
@Loop    lda (zAryDesVec),Y
         sta zAryDesVal,X
         dey
         dex
         bpl @Loop
         rts

; .A Handle, .Y index to Info item
GetAryDesLA ldx #2
         jsr GetAryDes
         lda zAryDesVal + 0
         ldx zAryDesVal + 1
         ldy zAryDesVal + 2
         rts

GetAryDesWA ldx #1
         jsr GetAryDes
         lda zAryDesVal + 0
         ldx zAryDesVal + 1
         rts
GetAryDesWX ldx #1
         jsr GetAryDes
         ldx zAryDesVal + 0
         ldy zAryDesVal + 1
         rts

GetAryDesBA ldx #0
         jsr GetAryDes
         lda zAryDesVal + 0
         rts

; Set Long, Word or Byte from Array Information
SetAryDes stx zTB1$
         tya
         clc
         adc zTB1$
         tay
@Loop    lda zAryDesVal,X
         sta (zAryDesVec),Y
         dey
         dex
         bpl @Loop
         rts

SetAryDesLA sta zAryDesVal
         stx zAryDesVal + 1
         sty zAryDesVal + 2
SetAryDesL ldx #2
         jmp SetAryDes

SetAryDesWA sta zAryDesVal
         stx zAryDesVal + 1
SetAryDesW ldx #1
         jmp SetAryDes
         
SetAryDesBA sta zAryDesVal
SetAryDesB ldx #0
         jmp SetAryDes


; Multiply .X.Y by Item Size then Add the 16-bit Base address, result returned in rAXY
; NOTE: The Mult Result may be > 16-bit, but the 17th bit is discarded.

CalcAryItemAdr ldx zAryDesVal
         ldy zAryDesVal + 1

CalcAryXYAdr stx zA1$                ; 16-bit Index
         sty zA1$ + 1

         ; ItemSize begins at 1 but is 0-based, so add 1 before it is used as a multiplier.
         ldy #ItemSize
         clc
         lda (zAryDesVec),Y
         adc #1
         sta zA2$
         iny
         lda (zAryDesVec),Y
         adc #0
         sta zA2$ + 1

         jsr MultWWL$           ; Mult Index by Item size, Long result

         ; Add Result to base address of array
         ldx #2
         ldy #BaseAddress
         clc
@Loop    lda (zAryDesVec),Y
         adc zA1$ - BaseAddress,Y                  
         sta zA1$ - BaseAddress,Y
         iny
         dex
         bpl @Loop
         
         lda zA1$
         ldx zA1$ + 1
         ldy zA1$ + 2
         rts       

; Calculate Address at current Cursor Position
ICalcCsrPosAdr ldy #CsrPos 
         lda (zAryDesVec),Y
         tax
         iny
         lda (zAryDesVec),Y
         tay
         jmp CalcAryXYAdr

; Assign Arrays Descriptor to the vector. AXY preserved. Current Array byte is used. 
AIniAryDesVec pha
         txa
         pha
         tya
         pha
         lda CurArray
         jmp PInArDeVeC

; Assign Arrays Descriptor to the vector. AXY preserved. Array handle in .A. 
PIniAryDesVec sta CurArray
         pha
         txa
         pha
         tya
         pha
         lda CurArray
         
PInArDeVeC jsr UIniAryDesVec         
         pla
         tay
         pla
         tax
         pla
         rts

UIniAryDesVec asl                   ; Array Handle
         tay
         lda AryDescAdr,Y
         sta zAryDesVec,Y
         lda AryDescAdr + 1,Y
         sta zAryDesVec + 1,Y
         rts

#EndRegion

Helper Routines
These are in a seperate project file. There is little optimisation on the Multiply routines, and they will be replaced when I get time to do so. The transfer routine is 16-bit and will also be replaced soon.

Code: Select all

;* = $C110

#Region ; Handle Manager

; --------------------
; HANDLE MANAGER
; ----------
; PUBLIC
Hdl_Create$       = Hdl_Create
Hdl_Allocate$     = Hdl_Allocate
Hdl_Deallocate$   = Hdl_Deallocate
; ----------
; LOCAL
TermFlag$         byte 0
Profile$          byte 0
; ----------

; Create Handle
;  Address = <.X >.Y
;  Max Amount = .A (1..253)

Hdl_Create stx zTW1$
         sty zTW1$ + 1
         ldy #0
         sta (zTW1$),Y       ; Write Max
         iny
         sta (zTW1$),Y       ; Write 
         tax
         dex
@L1      iny               ; Write sequence 0..n
         txa
         sta (zTW1$),Y
         dex
         cpx #255
         bne @L1
         rts


; Allocate Handle
;  Address = <.X >.Y
;  Return = .A

Hdl_Allocate stx zTW1$
         sty zTW1$ + 1
         ldy #1
         lda (zTW1$),Y
         bne @C1           
         sec
         bcs @C2           ; ERROR
@C1      sec
         sbc #1
         sta (zTW1$),Y
         tay               ; Inc index to correct position
         iny
         iny
         lda (zTW1$),Y

         clc
@C2      rts


; Deallocate Handle
;  Address = <.X >.Y
;  Handle = .A

Hdl_Deallocate stx zTW1$
         sty zTW1$ + 1
         tax
         ldy #1
         lda (zTW1$),Y
         dey
         cmp (zTW1$),Y
         bne @C1 
         sec               ; ERROR
         bcs @C2
@C1      clc
         adc #1            ; Inc pointer
         iny
         sta (zTW1$),Y
         tay
         iny
         txa               ; Handle to return
         sta (zTW1$),Y

         clc
@C2      rts

#endregion

#Region ; Maths

; --------------------
; MATHS ROUTINES
; ----------
; PUBLIC
MultWWW$ = MultWWW
MultWWL$ = MultWWL
MultWWE$ = MultWWE
; ----------
; LOCAL
Z        = 8
PreCalc_Mul16L$
         byte <0*Z, <1*Z, <2*Z, <3*Z, <4*Z, <5*Z, <6*Z, <7*Z 
         byte <8*Z, <9*Z, <10*Z, <11*Z, <12*Z, <13*Z, <14*Z, <15*Z
PreCalc_Mul16H$
         byte >0*Z, >1*Z, >2*Z, >3*Z, >4*Z, >5*Z, >6*Z, >7*Z
         byte >8*Z, >9*Z, >10*Z, >11*Z, >12*Z, >13*Z, >14*Z, >15*Z
; ----------

; Multiply the 16-bit contents of zp Accu 1 & 2, result in 1 (16-bit result)
MultWWW  ldx #0
         stx zA3$
         stx zA3$ + 1
         ldy #16
         bne @C2           ; Always
@C1      clc
         lda zA3$
         adc zA2$
         sta zA3$

         lda zA3$ + 1
         adc zA2$ + 1
         sta zA3$ + 1

@C2      lsr zA3$ + 1
         ror zA3$

         ror zA1$ + 1
         ror zA1$

         dey
         bmi @Exit
         bcc @C2
         bcs @C1
@Exit    rts

; Multiply the 16-bit contents of zp Accu 1 & 2, result in 1 (24-bit result)
MultWWL  ldx #0

         stx zA1$ + 2       ; Clear Ext byte
         stx zA2$ + 2

         stx zA3$
         stx zA3$ + 1
         stx zA3$ + 2

         ldy #24
         bne @C2           ; Always

@C1      clc
         lda zA3$
         adc zA2$
         sta zA3$

         lda zA3$ + 1
         adc zA2$ + 1
         sta zA3$ + 1

         lda zA3$ + 2
         adc zA2$ + 2
         sta zA3$ + 2

@C2      lsr zA3$ + 2
         ror zA3$ + 1
         ror zA3$

         ror zA1$ + 2
         ror zA1$ + 1
         ror zA1$

         dey
         bmi @Exit
         bcc @C2
         bcs @C1
@Exit    rts

         
; Multiply the 32-bit contents of zp Accu 1 & 2, result in 1 (32-bit result)
MultWWE  ldx #0

         stx zA1$ + 2       ; Clear Ext byte
         stx zA2$ + 2
         stx zA1$ + 3       ; Clear 4th byte
         stx zA2$ + 3

         stx zA3$
         stx zA3$ + 1
         stx zA3$ + 2
         stx zA3$ + 3

         ldy #32
         bne @C2      ; Always

@C1      clc
         lda zA3$
         adc zA3$
         sta zA3$

         lda zA3$ + 1
         adc zA2$ + 1
         sta zA3$ + 1

         lda zA3$ + 2
         adc zA2$ + 2
         sta zA3$ + 2

         lda zA3$ + 3
         adc zA2$ + 3
         sta zA3$ + 3

@C2      lsr zA3$ + 3
         ror zA3$ + 2
         ror zA3$ + 1
         ror zA3$

         ror zA1$ + 3
         ror zA1$ + 2
         ror zA1$ + 1
         ror zA1$

         dey
         bmi @Exit
         bcc @C2
         bcs @C1
@Exit    rts

; --------------------

; 16-bit Addition : .X byte width pf values to add. Carries into higher byte, 32-bit cutoff

AddAcc$  ldy #0
         clc
@L1      lda zA1$,Y
         adc zA2$,Y
         sta zA3$,Y
         iny
         dex
         bne @L1
         cpy #4
         bne @Exit         ; cutoff at 32 bits
         txa               ; Carry into next byte
         rol
         sta zA3$,Y
@Exit    rts

SubAcc$ ldy #0
         sec
@L1      lda zA1$,Y
         sbc zA2$,Y
         sta zA3$,Y
         iny
         dex
         bne @L1
         cpy #4
         bne @Exit         ; cutoff at 32 bits
         txa
         sbc #0            ; Carry into next byte
         sta zA3$,Y
@Exit    lda zA3$          ; 4th byte will have to be recovered by the user
         ldx zA3$ + 1
         ldy zA3$ + 2
         rts

@Table   byte 3,2,1,0      ; Indexed to byte, word, long and extended

; --------------------

; Methods to add values
; .X = number of bytes to add 1=B, 2=W, 3=L 4=E
AddLLLA$ ldx #3            
         jsr AddAcc$
         jmp GetAccLA$

AddLWLA$ lda #0            ; Set 3rd byte to 0
         sta zA2$ + 2
         
         ldx #3            
         jsr AddAcc$
         jmp GetAccLA$

AddWWLA$ ldx #2
         jsr AddAcc$
         jmp GetAccLA$

AddWBLA$ lda #0            ; Set 2nd byte to 0
         sta zA2$ + 1
         
         ldx #2         
         jsr AddAcc$
         jmp GetAccLA$

; Methods to return Accumulator results
GetAccLA$ lda zA3$
         ldx zA3$ + 1
         ldy zA3$ + 2
         rts
 
GetAccWA$ lda zA3$ 
         ldx zA3$ + 1
         rts

GetAccWX$ ldx zA3$
         ldy zA3$ + 1
         rts

; Compare two zero-page 16-bit values, X and Y
CompareZpW lda $01,X       
         cmp $0001,Y
         bcc @Exit
         lda $00,X       
         cmp $0000,Y
         bcc @Exit        ; Branch if X < Y
@Exit    rts

#EndRegion

#Region ; Safe Memory Transfer

; SAFE MEMORY TRANSFER
; Currently 16-bit, but will eventually be full 24-bit and support SuperRAM and REU.

; 16-bit safe memory transfer
; W Source, W Dest, W Length 1-65535
; Uses zTW1$-3

; ----------
; ZERO-PAGE
; NOTE: These are aligned with the related 24-bit addresses
zTFerS            = zMemTransfer$
zTFerD            = zTFerS + 3
zTFerL            = zTFerD + 3
; ----------
; PUBLIC
TFer$             = Tfer16s
SwapTfrSD$        = SwapTfrSD
zTFerS$           = zTFerS
zTFerD$           = zTFerD
zTFerL$           = zTFerL
; ----------

; Swap Source and Destination
SwapTfrSD lda zTferS
         sta zTferD
         lda zTferS + 1
         sta zTferD + 1
         rts

Tfer16S  ; 16 bit comparison
         lda zTferS + 1       
         cmp zTferD + 1
         bcc TferHi
         lda zTferS
         cmp zTferD
         bcc TferHi        ; Branch if Source < Destination

         ; Copy to a lower address
TferLo   ldx zTferL + 1    ; Test > 255 bytes 
         beq @C1           ; Jump to the test for 0 length

         ; Copy 256-byte segments
         ldy #0

@L1      lda (zTferS),Y    ; First XFer Block - copies 256 bytes         
         sta (zTferD),Y    ;
         iny               ;
         bne @L1           ;
         inc zTferS + 1    ;
         inc zTferD + 1    ;
         dex               ;
         bne @L1           ;

@C1      lda zTferL        ; <256 bytes remaining?
         beq @Exit
         sta @TL1 + 1

         ; Copy remaining bytes
         ldy #0
@L2      lda (zTferS),Y    ;          
         sta (zTferD),Y    ;
         iny               ;
@TL1     cpy #0            ;
         bne @L2           ;

@Exit    rts

; -----------

         ; Copy to a higher address
TferHi   ldx zTferL + 1   ; Test > 255 bytes 
         beq @C2           ; Jump to the test for 0 length
         
         dex

         clc
         lda zTferL
         adc zTferS
         sta zTFerS
         txa
         adc zTFerS + 1
         sta zTFerS + 1

         clc
         lda zTferL
         adc zTferD
         sta zTFerD
         txa
         adc zTFerD + 1
         sta zTFerD + 1

         ; Copy 256-byte segments
         inx
         ldy #255

@L1      lda (zTferS),Y    ; First XFer Block - copies 256 bytes         
         sta (zTferD),Y    ;
         dey               ;
         bne @L1           ;
         lda (zTferS),Y    ;         
         sta (zTferD),Y    ;
         dec zTferS + 1    ;
         dec zTferD + 1    ;
         dex               ;
         bne @L1           ;

@C1      ldx zTFerL
         beq @Exit
         lda #0            ; Set Y to the remainder
         clc
         sbc zTferL
         tay
         
         ; Copy remaining bytes
         ldy #255
@L2      lda (zTferS),Y    ;          
         sta (zTferD),Y    ;
         dey               ;
         dex               ;
         bne @L2           ;
@Exit    rts

@C2      lda zTferL        ; < 256 byte transfer
         tax
         tay
         dey
         jmp @L2

#EndRegion
Global File
This provides the zero-page base addresses used by other Project Files, and also lists common ZP addresses such as the 32-bit accumulators and temporary local workspaces.

Code: Select all

;* = $C100

; Workspace
; Other routines can break this up into useful spaces, eg zTW1$
zFunctionMan$     = $60             ; 20 bytes
zRecordMan$       = $74             ; 8 bytes allocated
zArrayMan$        = $7C             ; 5 bytes allocated
zMemTransfer$     = $81             ; 9 bytes
zResShared$       = $8A

; 3 32-bit accumulators. 12 bytes
zA1$     = zResShared$     ; 4 bytes
zA2$     = zA1$ + 4        ; 4 bytes
zA3$     = zA2$ + 4        ; 4 bytes

; Temporary workspace for bytes. 4 bytes
zTB1$    = zA3$ + 4        ; 1 byte
zTB2$    = zTB1$ + 1       ; 1 byte
zTB3$    = zTB2$ + 1       ; 1 byte
zTB4$    = zTB3$ + 1       ; 1 byte

; Temporary workspace for words. 4 bytes
zTW1$    = zTB4$ + 1       ; 2 bytes
zTW2$    = zTW1$ + 2       ; 2 bytes

; Temporary workspace for Longs. 6 bytes
zTL1$    = zTB4$ + 1       ; 3 bytes
zTL2$    = zTL1$ + 3       ; 3 bytes



; Global Ext byte for read and write operations for which the lower 16-bits are provided.
ExtReadS$ byte 0
ExtWrite$ byte 0

; The CPU-Memory layout
; 0 = C64
; Bit 1 = SCPU + SuperRAM
; Bit 2 = SCPU + REU
; Bit 3 = SCPU
; Bit 4 = REU
CpuMem$  byte 8

; General Globals
ErrorF$  byte 0            ; Error Flag for most recent operation. 
                           ; Can be an index to an optional global error text message (useful for debugging).


User avatar
Shaun_B
Member
Member
Posts: 179
Joined: Tue May 06, 2014 12:12 pm
Location: UK
Contact:

Re: Array Manager

Post by Shaun_B »

Hi Marc,

The Wheels OS allows for SuperRAM + REU RAM as a possibility, it means that you can run Wheels in REU memory which frees up all of the SuperRAM for the few applications that require the SuperRAM (for instance, geoZIP and The Wave).

Would this array manager work with REU RAM and SuperRAM if both are detected?

Regards,

Shaun.
BASIC Programming - making the mistakes so that you don't have to.
Circles and Squares.
Nothing I post here will stand up in a court of law.
MarcWalters
Member
Member
Posts: 55
Joined: Wed Jun 11, 2014 2:33 pm
Location: Lake Macquarie, NSW, Australia
Contact:

Re: Array Manager

Post by MarcWalters »

The RAM expansion switching scheme I've developed for the Function Manager will be used by the replacement transfer routine. SuperRAM is faster than the REU and, by default, will have priority over the REU for those general-purpose storage routines in which expansion RAM is treated as a big bag of bytes. However, it will be possible for the user to override this.

Also, a non-related but useful point:
The example that shows how to create an array uses the basic subroutines and a statically assigned Array Descriptor block.
The array creation can be wrapped in a function that took arguments for the Array location, Item length, Max Index and Top Index (all that's needed to assign an initially populated array), and which stored the Descriptor block in another array hidden from the user (which is why a Handle-based system is so useful!). A function for transferring an array item to a screen line could also be written.
The example in the first post would then look like this:

Code: Select all

         jsr CreateArray
         word Array1Base, 5, 4, 3

         jsr SetCursor
         word 1

         jsr CursorRead_ToScreenLine
         byte #Line_1
 
         jsr CursorRead_ToScreenLine
         byte #Line_2
         ...
Array1Base ; 5 Items, each 6 bytes in size 
         byte 00,01,02,03,04,06     ; Index 0
         byte 10,11,12,13,14,15     ; Index 1
         byte 20,21,22,23,24,26     ; Index 2
         byte 30,31,32,33,34,36     ; Index 3
         byte 00,00,00,00,00,00     ; Index 4
There. Nice and tidy.
Post Reply Previous topicNext topic

Who is online

Users browsing this forum: No registered users and 12 guests