Simple Array Manager

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

Simple Array Manager

Post by MarcWalters » Wed Jan 07, 2015 9:50 am

Description
Simple Array Manager is a simplified version of the Array Manager utility I posted in the forum a while ago. It provides a way to coerce a block of memory within a 24-bit address space to a fixed item-length array.
* Each array has an unattached "header" defined statically in memory, accessed using a Handle system.
* An Array can contain 0 to 256 Items.
* An Item is 1 to 256 bytes in length.

A variety of string termination types can be used for the data transfers, including Item Size (default), zero-terminated, 255-terminated and Pascal-style run-length.

There is simple internalised program-flow support for both the data source/destination and the array index. Both are preserved and optionally incremented, exposed through the CPU registers.

The Interface is simple and lightweight - accessed via CPU registers and user-defined vectors.

Integration
To get the code running you'll need to include some of the files I've posted previously, such as Globals.asm and Helper.asm.

Design Overview
This was written as a testbed for some experiments with binary arrays and sets, and independent indexes. The main aim was to write a tool that allows a programmer to think about design and data structures instead of muck about with "plumbing" code.

Function parameters are consistent: rA = Array Handle, rX = Array Index, rY = zero-page vector that points to the source or destination for array data.

For example, assume an array contains a list of five variable length menu options that are to be dumped to the screen, aligned vertically:
The Tab feature is set to 40, location $FB/$FC is set with the screen location ($0400).
Index mode is set to Increment.
Register A is set with the array handle (you can create as many arrays as you want).
Register X is set with the index of the first menu entry (0).
Register Y is set with $FB (the destination for the data to be read from the array.

Code: Select all

...
lda Array_Handle
ldx #File_Menu_Index
ldy #$FB
Loop jsr Array_Read
     cpx #End_Of_File_Menu
bne Loop
... 
The Array code preserves the parameters, and increments the Index if multiple sequential items are to be read from OR WRITTEN TO the array (most operational features are bi-directional).
The result is five menu entries printed vertically, starting at the top left of the screen.

The code is patchy, and there are some sections that I want to rewrite. But it was a case of pushing out now something that worked, or trying to perfect it for an undetermined future date. Emphasis is on a small clean code footprint over speed of execution. The general interface to the array is designed so that a minimal amount of code is needed to use it, and much of the information can be emplaced statically (tables, etc) instead of code.

Only useful functions are included. For example, there is no Insert() function because a planned Index feature will make it unnecessary to order the actual array data. Basically, this utility makes it simple to push structured data around memory. The data read/write code is compatible with 65816 extended addressing.

Example

Code: Select all

         jsr SimAry_Init$

         ; Create
         lda #<Descriptor1
         ldx #>Descriptor1
         ldy #0
         jsr SimAry_Create$
         sta Test_Handle

         ; Write
         lda Test_Handle
         ldx #3            ; Increment data source and Array Index
         jsr SimAry_SetIndexMode$

         ldy #$FB          ; Set Y with ZP vector
         ldx #<MyData      ; Populate vector
         stx $00,Y
         ldx #>MyData
         stx $01,Y

         lda Test_Handle
         ldx #$00          ; Index 0
         jsr SimAry_Write$   

         ; After the write, X will be returned incremented to 1
         ; The address at $FB will have 8 added to it
         rts
         

Descriptor1 word Array1    ; Base Address - 16 bits
         byte 0   ; Base Address - Bank
         byte 7   ; Item Size
         byte 3   ; Max Index
         byte 3   ; Top Index
         byte 0   ; Index Mode
         byte 0   ; Termination
         byte 0   ; Tab

Array1   byte 0,0,0,0,0,0,0,0
         byte 0,0,0,0,0,0,0,0
         byte 0,0,0,0,0,0,0,0
         byte 0,0,0,0,0,0,0,0

MyData   byte 3,2,1,0,1,2,3,4
CODE

Code: Select all

;*=$C600
; --------------------------
; Simple Array Manager
; --------------------------

; ARRAY OPERATIONS
; Init Array
; Create Array (rAXY Descriptor Address) : Handle
; Delete Array (Handle)
;
; INTERROGATION
; Get Array Base (rA Handle) : rAXY
; Get Item Size (rA Handle) : rX
; Get Max Index (rA Handle) : rA    ; useful for an iterator
; Get Item Address (rA Handle, rX Index) : rAXY       ; Calculated
; Get Tab (rA Handle) : rA
;
; CONFIGURATION
; Set Base Bank (ra Handle, rX Bank)
; Set Base Address (ra Handle, rXY Address)
; Set Tab (rA Handle, rX Tab Value) 
;   If >0 this replaces ItemSize when Index Incr
; Set Index Mode (rA Handle, rX mode )
;   0=None, 1 = Index, 2 = Data, 3 = Both
; Set Top Index (rA Handle, rX Value)

; ITEM OPERATION - READ
; Read (rA Handle, rX Index, rY Indirect Destination Address) : rX

; ITEM OPERATION - WRITE
; Add (rA Handle, rY Indirect Source Address) : rX ; rX is set with TopIndex
; Write (rA Handle, rX Index, rY Indirect Source Address) : rX
; Clear (rA Handle, rX Index, rY Value) :rX
; Delete (rA Handle, rX Index) : rX

; DESCRIPTOR
; E Base Address
; B Item Size
; B Max Index
; B Top Index
; B Index Mode
; B Termination
; B Tab

; ----------
; ZERO-PAGE
zSimAryDesVec = zSimArrayMan$          ; 2 bytes

; ----------
; PUBLIC
SimAry_Init$         = Init
SimAry_Create$       = Create
SimAry_Delete$       = Delete

; Interrogation
SimAry_GetBase$      = SimAryGetBase
SimAry_GetTab$       = SimAryGetTab
SimAry_GetIndexMode$ = SimAryGetIndexMode
SimAry_GetItemAddress$ = SimAryGetItemAddress
SimAry_GetItemSize$  = SimAryGetItemSize
SimAry_GetMaxIndex$  = SimAryGetMaxIndex
SimAry_GetTopIndex$  = SimAryGetTopIndex

; Configuration
SimAry_SetBaseBank$  = SimArySetBaseBank
SimAry_SetBaseAddress$ = SimArySetBaseAddress
SimAry_SetTab$       = SimArySetTab
SimAry_SetIndexMode$ = SimArySetIndexMode
SimAry_SetTopIndex$  = SimArySetTopIndex

; Item Operations - Read
SimAry_Read$         = SimAryRead

; Item Operations - Write
SimAry_Add$          = SimAryAdd
SimAry_Clear$        = SimAryClear
SimAry_DeleteItem$   = SimAryDeleteItem
SimAry_Write$        = SimAryWrite

; ----------
; LOCAL
MaxSimArrays      = 16
SimAryDescAdr     words MaxSimArrays
SimArrayHdl       byte 0,0
                  bytes MaxSimArrays

; Temporary storage
SimAryItemSize    byte 0
SimAryMaxIndex    byte 0

SimAryDeleteIndex byte 0
SimAryDataVec     byte 0
SimAryReadOperFlag byte 0

CurSimAryA        byte 0
CurSimAryX        byte 0
CurSimAryY        byte 0

; ----------
; Simple Array Descriptor Indices: Use an index with zSimAryDesVec to fetch array info.
BaseAddress = 0                     ; L
ItemSize    = BaseAddress + 3       ; B
MaxIndex    = ItemSize + 1          ; B
TopIndex    = MaxIndex + 1          ; B
IndexMode   = TopIndex + 1          ; B
Term        = IndexMode + 1         ; B
Tab         = Term + 1              ; B
      
; SIMPLE ARRAY OPERATIONS

; ----------------------------------------------------------------------
; Array Management
; ----------------------------------------------------------------------
Init     ldx #<SimArrayHdl    
         ldy #>SimArrayHdl
         lda #MaxSimArrays
         jmp Hdl_Create$

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

         pla                        ; ERROR
         tax
         pla
         rts
         
         ; Copy Descriptor address into a list indexed by its Handle
@C1      asl                        ; Array Index x 2 for storing in Word list
         tay
         pla
         sta SimAryDescAdr + 1,Y
         pla
         sta SimAryDescAdr,Y
         tya
         lsr
         clc                        ; OKAY
         rts                        ; Return with Array Handle
                  
Delete   ldx #<SimArrayHdl
         ldy #>SimArrayHdl
         jsr Hdl_Deallocate$

; ----------------------------------------------------------------------
; Interrogation
; ----------------------------------------------------------------------

; ----------
; SimAryGetBase
;   Get base address of array
; ----------
SimAryGetBase jsr IniSimAryDesVec
         ldy #BaseAddress
         lda (zSimAryDesVec),Y
         pha
         iny
         lda (zSimAryDesVec),Y
         tax
         iny
         lda (zSimAryDesVec),Y
         tay
         pla
         rts

; ----------
; SimAryGetTab
;   Get Tab
; ----------
SimAryGetTab jsr IniSimAryDesVec
         ldy #Tab
         lda (zSimAryDesVec),Y
         rts

; ----------
; SimAryGetIndexMode
;   Get index mode
; ----------
SimAryGetIndexMode jsr IniSimAryDesVec
         ldy #IndexMode
         lda (zSimAryDesVec),Y
         rts

; ----------
; SimAryGetItemAddress
;   Get item address
; ----------
SimAryGetItemAddress jsr IniSimAryDesVec
         
         ; SimAryItemSize us set up here because SimAryInitXfer is bypassed
         ldy #ItemSize
         lda (zSimAryDesVec),Y
         sta SimAryItemSize
         
         jsr CalcItmAdr
         lda zA1$
         ldx zA1$ + 1
         ldy zA1$ + 2
         rts

; ----------
; SimAryGetItemSize
;   Get item size
; ----------
SimAryGetItemSize jsr IniSimAryDesVec
         ldy #ItemSize
         lda (zSimAryDesVec),Y
         rts

; ----------
; SimAryGetMaxIndex
;   Get max index
; ----------
SimAryGetMaxIndex jsr IniSimAryDesVec
         ldy #MaxIndex
         lda (zSimAryDesVec),Y
         rts

; ----------
; SimAryGetTopIndex
;   Get top index
; ----------
SimAryGetTopIndex jsr IniSimAryDesVec
         ldy #TopIndex
         lda (zSimAryDesVec),Y
         rts

; ----------------------------------------------------------------------
; Configuration
; ----------------------------------------------------------------------

; ----------
; SimArySetBaseBank
;   Set Bank (Ext byte)
; ----------
SimArySetBaseBank jsr IniSimAryDesVec
         ldy #BaseAddress
         iny
         iny
         txa
         sta (zSimAryDesVec),Y
         rts

; ----------
; SimArySetBaseAddress
;   Set Address (16-bit)
; ----------
SimArySetBaseAddress jsr IniSimAryDesVec
         ldy #BaseAddress
         txa
         sta (zSimAryDesVec),Y
         lda CurSimAryY
         sta (zSimAryDesVec),Y
         rts

; ----------
; SimArySetTab
;   Set Tab
; ----------
SimArySetTab jsr IniSimAryDesVec
         ldy #Tab
         txa
         sta (zSimAryDesVec),Y
         rts

; ----------
; SimArySetIndexMode
;   Set index mode
; ----------
SimArySetIndexMode jsr IniSimAryDesVec
         ldy #IndexMode
         txa
         sta (zSimAryDesVec),Y
         rts

; ----------
; SimArySetTopIndex
;   Set top index
; ----------
SimArySetTopIndex jsr IniSimAryDesVec
         ldy #TopIndex
         txa
         sta (zSimAryDesVec),Y
         rts

; ----------------------------------------------------------------------
; Array Item Operations - Read
; ----------------------------------------------------------------------

; ----------
; SimAryRead
;   Read from array
; ----------
SimAryRead jsr IniSimAryDesVec
         lda #1                     ; For the Read Operation Flag
         jmp SimAryWriteJ
         
; ----------------------------------------------------------------------
; Array Item Operations - Write
; ----------------------------------------------------------------------

; ----------
; SimAryClear
;   Clear array item
; ----------
SimAryClear jsr IniSimAryDesVec
         tya
         pha                        ; Preserve Clear value
         jsr SimAryInitXfer
         ldy SimAryItemSize

         pla                        ; Restore Clear value      
@Loop    sta (zTW1$),Y
         dey
         cpy #255
         bne @Loop

@Exit    jmp SimAryCleanExit

; ----------
; SimAryDeleteItem
;   Delete Item (Note: No range testing - allows new data to be dragged in from above)
; ----------
SimAryDeleteItem jsr IniSimAryDesVec
         stx SimAryDeleteIndex 
         jsr SimAryInitXfer

         ldx CurSimAryX
         inx
         jsr CalcItmAdr             ; Set Data address to zA1$ - safe if not using math routines

         jmp @LEntry                ; Entry point avoids incr of Src and Dst

@LMain   lda SimAryItemSize         ; Add ItemSize to ItemAddress         
         ldx #zTW1$
         jsr ZPWAddB
         lda #1
         jsr ZPWAddB

         lda SimAryItemSize         ; Add ItemSize to Data
         ldx #zA1$
         jsr ZPWAddB
         lda #1
         jsr ZPWAddB

         inc SimAryDeleteIndex

@LEntry  ldy SimAryItemSize
@LInner  lda (zA1$),Y               ; 16-bit address at index (24-bit with SCPU)
         sta (zTW1$),Y
         dey
         cpy #255
         bne @LInner

         lda SimAryDeleteIndex
         cmp SimAryMaxIndex 
         bne @LMain

         ; Test TopIndex for possible Decr.
@Exit    ldy #TopIndex
         lda (zSimAryDesVec),Y
         beq @ExitC
         sec
         sbc #1
         sta (zSimAryDesVec),Y
         
@ExitC   jmp SimAryCleanExit

; ----------
; SimAryWrite
;   Write to array
;   Termination conditions handled: 0 (default, 1 and 2)
; ----------
SimAryWrite jsr IniSimAryDesVec
         lda #0
         
SimAryWriteJ sta SimAryReadOperFlag
         jsr SimAryInitXfer

         ldy #Term
         lda (zSimAryDesVec),Y

         pha

         lda SimAryReadOperFlag
         bne @ReadOper

         ldy CurSimAryY
         ldx #ztW1$
         bne @Cont1                 ; Branch Always

@ReadOper ldx CurSimAryY
         ldy #ztW1$

         ; Termination conditions
@Cont1   pla

         cmp #0
         beq @Term0
         cmp #1
         beq @Term1
         cmp #2
         beq @Term2
         cmp #3
         beq @Term3

@Term0   sty @T0LoopR + 1  
         stx @T0LoopW + 1
         ldy SimAryItemSize

@T0LoopR lda ($00),Y                ; 16-bit address at index (24-bit with SCPU)
@T0LoopW sta (zTW1$),Y
         dey
         cpy #255
         bne @T0LoopR
         beq @Exit

         ; End marker = 0
@Term1   lda #0
@Term1J  sty @T1LoopR + 1 
         stx @T1LoopW + 1 
         sta @Term1W + 1
         
@T1LoopR lda ($00),Y                ; 16-bit address at index (24-bit with SCPU)
@Term1W  cmp #0                     ; Termination condition
         beq @Exit
@T1LoopW sta (zTW1$),Y
         iny
         bne @T1LoopR
@Exit    jmp SimAryCleanExit

         ; End marker = 255
@Term2   lda #255
         bne @Term1J                ; Always

         ; Run-length value 0-255
@Term3   sty @Term3R + 1
         ldy #0
@Term3R  lda ($00),Y
         sta SimAryItemSize
         ldy @Term3R + 1
         jmp @Term0

; ----------
; SimAryAdd
;   Write to array with TopIndex as index
; ----------
SimAryAdd jsr SimAryGetTopIndex
         sta CurSimAryX

         ldy #TopIndex
         lda (zSimAryDesVec),Y
         ldy #MaxIndex
         cmp (zSimAryDesVec),Y
         bne @Exit
         ; Incr TopIndex if <MaxIndex
         clc
         adc #1
         sta (zSimAryDesVec),Y
@Exit    tax
         ldy CurSimAryY
         jmp SimAryWriteJ

; Handle Incr flags, restore CPU registers.
SimAryCleanExit ldy #IndexMode
         lda (zSimAryDesVec),Y
         beq @Exit
         jsr SimAryDataIdxInc
@Exit    jmp SimAryExit

; ----------------------------------------------------------------------
; Subroutines
; ----------------------------------------------------------------------

; ----------
; SimAryInitXfer : rY SimAryItemSize
;   Used by methods that xfer data between array item and memory. 
; ----------
SimAryInitXfer 
         ; Store Max Index
         ldy #MaxIndex
         lda (zSimAryDesVec),Y
         sta SimAryMaxIndex

         ; rY = Item size
         ldy #ItemSize
         lda (zSimAryDesVec),Y
         sta SimAryItemSize

         ; Set SimAryDataVec
         ldx CurSimAryX
         jsr CalcItmAdr
         
         ldx CurSimAryY
         stx SimAryDataVec

         ; Set zTW1$
         ldx #zTW1$

         lda zA1$
         sta $00,X
         lda zA1$ + 1
         sta $01,X
         lda zA1$ + 2
         sta $02,X

         rts

; ----------
; SimAryDataIdxInc
;   Increment data vector and/or Index. On entry, rA contains the incr flag.
; ----------
SimAryDataIdxInc lsr                ; Test Bit 0 (Incr Index)
         bcc @SimAryDataInc
                  
         ; Incr index to be returned in rX
         inc CurSimAryX    

@SimAryDataInc lsr                  ; Test Bit 1 (Incr Data)
         bcc @Exit

         ldx SimAryDataVec
         ldy #Tab
         lda (zSimAryDesVec),Y
         bne @Tab

         ; Incr data address in zp vector to which rY points
         lda SimAryItemSize 
         jsr ZPWAddB
         lda #1                     ; +1 needed because item byte size is 1-256 
@Tab     jmp ZPWAddB
         
@Exit    rts

; ----------
; ZPWAddB
;   Add rA to rX ZP Word
; ----------
ZPWAddB  clc
         adc $00,X
         sta $00,X
         lda #0
         adc $01,X
         sta $01,X
         rts

; Clean exit, restore registers
SimAryExit lda CurSimAryA
         ldx CurSimAryX
         ldy CurSimAryY
         rts


; ----------
; IniSimAryDesVec
;   Copy Descriptor address into its ZP vector
; ----------
IniSimAryDesVec sta CurSimAryA
         stx CurSimAryX
         sty CurSimAryY

         tya
         pha
         lda CurSimAryA
         asl                        ; Array Handle * 2
         tay
         lda SimAryDescAdr,Y
         sta zSimAryDesVec
         lda SimAryDescAdr + 1,Y
         sta zSimAryDesVec + 1

         pla
         tay
         lda CurSimAryA
         rts

; ----------
; CalcItmAdr( rX Index ) : rAXY
;   Multiply rX + 1 by Item Size
;   ItemSize begins at 1 but is 0-based, so add 1 before it is used as a multiplier.
; ----------
CalcItmAdr stx zA1$
         lda #0
         sta zA1$ + 1

         clc
         lda SimAryItemSize
         adc #1
         sta zA2$
         
         lda #0                     ; Add 0, only affected by a carry
         adc #0
         sta zA2$ + 1
         
         jsr MultWWL$               ; Mult Index by Item size, Long result

         ; Add Base Address to zA1$
         ldy #BaseAddress
         clc
@Loop    lda (zSimAryDesVec),Y
         adc zA1$ - BaseAddress,Y                  
         sta zA1$ - BaseAddress,Y
         iny
         cpy #3
         bne @Loop
         rts




Who is online

Users browsing this forum: No registered users and 1 guest