Image Map Image Map
Page 3 of 4 FirstFirst 1234 LastLast
Results 21 to 30 of 37

Thread: FLEX for the 6502 or building a compatible operating system...

  1. #21

    Default

    You also need a size identifier for those times when an address is loaded a byte at a time:

    Code:
    LDA #<ProcAddr
    STA TMP
    LDA #>ProcAddr
    STA TMP+1

  2. #22

    Default

    Quote Originally Posted by resman View Post
    You also need a size identifier for those times when an address is loaded a byte at a time:

    Code:
    LDA #<ProcAddr
    STA TMP
    LDA #>ProcAddr
    STA TMP+1
    The CP/M trick moves code in 256 byte increments, so only the upper bytes of addresses need to be patched.

  3. #23

    Default

    Quote Originally Posted by BillGee View Post
    The CP/M trick moves code in 256 byte increments, so only the upper bytes of addresses need to be patched.
    That will certainly simplify the procedure. Looking forward to seeing an implementation.

  4. #24

    Default

    At long last, I am finally able to load and run a program from a binary file. A surprising amount of the file system had to be implemented in order to be able to do that. I am very thankful to be developing this using emulation. Using real hardware will have taken much, much longer.

    It is often said that code on a 6502 tends to be faster but bigger.

    The following subroutine in the FLEX file system copies an 8.3 file name to a temporary save area in a file control block.

    The original 6809 code:


    Code:
     D540 BE D413		      [6] 00177	MOVNAM   LDX    CURFCB    MOVE FILE NAME TO TEMP
     D543 C6 0B		      [2] 00178	         LDB    #$0B
     D545 A6 04		      [5] 00179	MOVNM1   LDA    $04,X
     D547 A7 88 24		      [5] 00180	         STA    $24,X
     D54A 30 01		      [5] 00181	         LEAX   $01,X
     D54C 5A		      [2] 00182	         DECB
     D54D 26 F6 (D545)	      [3] 00183	         BNE    MOVNM1
     D54F 39		      [5] 00184	         RTS
    The 6502 code:


    Code:
    .C57A			  01901	MOVNAM
    .C57A 18	      [2] 01902	         clc              ; Copy file name to temp
    .C57B A5 04	      [3] 01903	         lda    FCBPtr
    .C57D 69 20	      [3] 01904	         adc    #FCBWrk-FCBNam   ; Offset to temp area
    .C57F 85 06	      [3] 01905	         sta    FMSPtr
    .C581 A5 05	      [3] 01906	         lda    FCBPtr+1
    .C583 69 00	      [2] 01907	         adc    #0
    .C585 85 07	      [3] 01908	         sta    FMSPtr+1
    .			  01909
    .C587 A2 0B	      [2] 01910	         ldx    #8+3
    .C589 A0 04	      [2] 01911	         ldy    #FCBNam
    .			  01912
    .C58B B1 04	    [5/6] 01913	MOVNM1   lda    (FCBPtr),Y
    .C58D 91 06	      [6] 01914	         sta    (FMSPtr),Y
    .			  01915
    .C58F C8	      [2] 01916	         iny
    .C590 CA	      [2] 01917	         dex
    .C591 D0 F8 (C58B)  [2/3] 01918	         bne    MOVNM1
    .			  01919
    .C593 60	      [6] 01920	         rts
    In this example, the 6502 code is 20 cycles faster, but 10 bytes bigger.

  5. #25

    Default

    I can now view a catalog of files on a disk, type out the contents of text files, delete and rename files.

    Overall, I am very pleased with the progress of this project; it was started on April 6, less than a month ago.

    Next up, testing all of the ways to write files. That should keep me busy over the weekend.

    While working on file deletion, it became obvious that a very safe and reliable file undelete utility can be built. Should I decide to develop that, I'll do it first on the 6502, then migrate it back to the 6800 and 6809.

  6. #26

    Default

    This is a bit of a one month progress report.

    The FLEX file system (File Management System or FMS) is feature complete except for the portions dealing with the creation, reading and writing of random access files. FLEX stores data on disk as a linked list of sectors. Reading or writing an arbitrary location in a file is not a simple arithmetic calculation; a naive implementation would have to read every sector of the file to follow the list until the needed sector is found. To solve this problem, creating a random file adds two special sectors which contain the addresses of the sectors in the file as they are allocated. Reading a byte from random location in a file requires first reading this sector map then the sector.

    The FLEX user interface is feature complete except for enhanced error reporting and background printing. When a random file named ERRORS.SYS is present, its contents is used to present a meaningful error message instead of an error code number. This capability is dependent upon FMS random access file support. Background printing is an option which requires a source of periodic interrupts. I have not investigated this feature very much yet; there are hooks for it in various parts of the system.

    The third leg of the FLEX system triad is the Utility Command Set, a collection of small programs on disk which provide a large majority of the user commands. The following commands have been implemented:

    ASN
    BUILD
    CAT
    DATE
    DELETE
    JUMP
    LINK
    LIST
    RENAME
    TTYSET
    VERIFY
    VERSION

    leaving these yet to be implemented:

    APPEND
    COPY
    EXEC
    I
    NEWDISK
    O
    P
    PRINT
    QCHECK
    SAVE
    XOUT

    The bootstrap loaders work so the operating system can be loaded from a disk image.

    The system total so far is about 9K bytes of machine code. That is an average of around 300 bytes per day. It may not seem like much, but remember that it is all written in assembly language.

    The current memory map is:

    $0000..$00FF - Zero page, locations at $12 and above are free for application programs to use
    $0100..$017F - FLEX line buffer
    $0180..$01FF - Stack
    $0200..$033F - FLEX entry points, variables and printer driver
    $0340..$047F - System File Control Block
    $0480..$0AFF - FLEX Utility Command Space
    $0B00..MEMEND - User memory

    Somewhere above that is about 6K of FLEX itself.

    Unlike the 680x versions, the UCS area has been intentionally placed adjacent to free RAM so that a program needing maximum memory can easily use both.

    The User's Guide is almost ready to publish; this is slightly modified from an original FLEX manual. The Programming Guide is about halfway done; it is a heavily modified version of an existing FLEX manual.

    Finally, some preliminary work has been done on an editor and an assembler. The assembler subproject is actually comprised of four smaller projects:

    * enhance the existing 6800 assembler to add features such as conditional assembly directives

    * convert the 6800 assembler into a 6502 cross assembler running on the 6800

    * convert the 6800 assembler into a 6800 cross assembler running on the 6502

    * combine the three into a 6502 native assembler

  7. #27

    Default

    Quote Originally Posted by BillGee View Post
    * enhance the existing 6800 assembler to add features such as conditional assembly directives
    I dove headlong into the assembler. Implementing conditional assembly does not initially appear to be very easy.

    So to learn the code, I made a few changes to fix some things which have always bothered me about this assembler:

    * The assembler does not allow placing a colon after a label. It now allows but does not require it.

    * The assembler distinguishes between upper and lower case in symbols. That is now a selectable option.

    * The assembler reformats the source code when it generates a listing. It originally printed "ldaa" as "lda a"; it now preserves both forms of the mnemonic as written. I am still investigating making the reformatting a selectable option.

  8. #28

    Default

    Quote Originally Posted by BillGee View Post
    I am still investigating making the reformatting a selectable option.
    A simple and elegant solution presented itself after I slept on it and came back to look at the problem from outside of the box: format each line of code, or not, in this case, as if the whole thing was a comment.

    This is ideal for those of you on the spaces side of the Great Spaces versus TABs Debate. FLEX already provides automagic space compression on disk as sequences of two or more spaces (up to 255) are replaced with two bytes: a tag and a count. You may now make your code listings look exactly like you want.

    Despite having this feature, many early FLEX programmers got into the unusual habit of separating fields in their assembly language programs with a single space and relying on the assembler to make listings legible.

    Those on the TAB side were left out because the tag byte was, you guessed it, the hard TAB character. FLEX text files cannot contain hard TABs the way the tools were configured. Editors responded to the TAB key by inserting an appropriate number of spaces.

  9. #29

    Default

    I have been known to say that programming a 6502 in assembly language is tedious compared with other processors. However, I just encountered an example in which the 6502 absolutely blows away the 6800.

    One of my current projects is to convert the original 6800 FLEX assembler into a cross assembler running on the 6502.

    Its symbol table is an array of eight byte entries: two bytes for the value and six for the symbol name. The symbol name is hashed to obtain an index into the array. In case of a collision, the name is rehashed up to a maximum of forty times to try other locations.

    At the end of the assembly process, the table is packed and sorted, then the entries are printed in alphabetical order.

    A subroutine swaps two entries addressed by the variables I and J, a task which the 6502 does with ease. It has just enough registers to avoid unnecessary memory accesses. I have observed in the past that the 6800 can be severely hampered by having only a single index register and that the 6502 addressing modes are particularly well suited for marching in lockstep through two parallel arrays.

    The 6502 version of the subroutine consumes less than half the cycles while also being much smaller.

    The 6502 code:

    Code:
    .1832                     04047 XCHNG
    .                         04048 ; LDX I
    .1832 A0 07           [2] 04049          ldy    #8-1      ; SET COUNT and index
    .                         04050
    .1834                     04051 XCHNG1                    ;PSHB ; SAVE COUNT
    .1834 B1 22         [5/6] 04052          lda    (I),Y     ; GET CHAR FROM I
    .1836 AA              [2] 04053          tax              ; Stash I[Y]
    .                         04054 ; STX I
    .                         04055 ; LDX J
    .1837 B1 24         [5/6] 04056          lda    (J),Y     ; GET CHAR FROM J
    .1839 91 22           [6] 04057          sta    (I),Y     ; Replace in I
    .                         04058 ; INX
    .                         04059 ; STX J ; SET NEW J
    .                         04060 ; LDX I
    .183B 8A              [2] 04061          txa              ; Recover I[Y]
    .183C 91 24           [6] 04062          sta    (J),Y     ; Replace in J
    .                         04063 ; INX
    .                         04064
    .                         04065 ; PULB ; RESTORE COUNT
    .                         04066
    .183E 88              [2] 04067          dey              ; DECREMENT IT
    .183F 10 F3 (1834)  [2/3] 04068          bpl    XCHNG1    ; LOOP IF NOT -1TH BYTE
    .                         04069
    .                         04070 ; BSR XSUB8 ; FIX I POINTER
    .                         04071 ; STX I
    .                         04072 ; LDX J
    .                         04073 ; BSR XSUB8 ; FIX J POINTER
    .                         04074 ; STX J
    .                         04075
    .1841 60              [6] 04076          rts
    The original 6800 code:

    Code:
    .151F 09              [4] 02889 XSUB8    DEX              DECREMENT X BY 8
    .1520 09              [4] 02890          DEX
    .1521 09              [4] 02891          DEX
    .1522 09              [4] 02892          DEX
    .1523 09              [4] 02893          DEX
    .1524 09              [4] 02894          DEX
    .1525 09              [4] 02895          DEX
    .1526 09              [4] 02896          DEX
    .1527 39              [5] 02897          RTS
    .                         02898 *
    .1528 DE 20           [4] 02899 XCHNG    LDX    I
    .152A C6 08           [2] 02900          LDAB   #$08      SET COUNT
    .152C 37              [4] 02901 XCHNG1   PSHB             SAVE COUNT
    .152D E6 00           [5] 02902          LDAB   0,X       GET CHAR FROM I
    .152F DF 20           [5] 02903          STX    I
    .1531 DE 22           [4] 02904          LDX    J
    .1533 A6 00           [5] 02905          LDAA   0,X       GET CHAR FROM J
    .1535 E7 00           [6] 02906          STAB   0,X       REPLACE WITH I CHAR
    .1537 08              [4] 02907          INX
    .1538 DF 22           [5] 02908          STX    J         SET NEW J
    .153A DE 20           [4] 02909          LDX    I
    .153C A7 00           [6] 02910          STAA   0,X       REPLACE WITH J CHAR
    .153E 08              [4] 02911          INX
    .153F 33              [4] 02912          PULB             RESTORE COUNT
    .1540 5A              [2] 02913          DECB             DECREMENT IT
    .1541 26 E9 (152C)    [4] 02914          BNE    XCHNG1    LOOP IF NOT 8TH BYTE
    .1543 8D DA (151F)    [8] 02915          BSR    XSUB8     FIX I POINTER
    .1545 DF 20           [5] 02916          STX    I
    .1547 DE 22           [4] 02917          LDX    J
    .1549 8D D4 (151F)    [8] 02918          BSR    XSUB8     FIX J POINTER
    .154B DF 22           [5] 02919          STX    J
    .154D 39              [5] 02920          RTS
    On further examination, the 6800 version can be made substantially faster than the 6502 version by completely unrolling the loop but the code is almost twice as big. (The XSUB8 subroutine is also used elsewhere, so it cannot be eliminated in the process.) A small speed gain by a similar transformation of the 6502 version does not justify the massive increase in code size required.

  10. #30

    Default

    Quote Originally Posted by BillGee View Post
    On further examination, the 6800 version can be made substantially faster than the 6502 version by completely unrolling the loop but the code is almost twice as big. (The XSUB8 subroutine is also used elsewhere, so it cannot be eliminated in the process.) A small speed gain by a similar transformation of the 6502 version does not justify the massive increase in code size required.
    I have to partially retract that statement. Somehow, I managed to forget that the 6800 only has one index register; the X register must to be ping ponged between I and J. Still, completely unrolling that loop makes the 6800 code about as fast as the 6502 version, but with much bigger code size. The result would look something like this:

    Code:
     0100 DE 00	      [4] 00006	         ldx    I
                              00007 *
     0102 E6 00	      [5] 00008	         ldab   0,X
     0104 DE 02	      [4] 00009	         ldx    J
     0106 A6 00	      [5] 00010	         ldaa   0,X
     0108 E7 00	      [6] 00011	         stab   0,X
     010A DE 00	      [4] 00012	         ldx    I
     010C A7 00	      [6] 00013	         staa   0,X
                              00014 *
     010E E6 01	      [5] 00015	         ldab   1,X
     0110 DE 02	      [4] 00016	         ldx    J
     0112 A6 01	      [5] 00017	         ldaa   1,X
     0114 E7 01	      [6] 00018	         stab   1,X
     0116 DE 00	      [4] 00019	         ldx    I
     0118 A7 01	      [6] 00020	         staa   1,X
    
    etc.
    There are two other service subroutines for the symbol table sorter.

    CMPLBL compares two symbols, pointed to by the variables I and J. Note that the 6800 version uses a couple of temporary variables instead of modifying I and J, then fixing them after the loop is finished; this same approach would have made the exchange subroutine better. Completely unrolling the loop is again the fastest implementation.

    The original 6800 code:

    Code:
    .154E DE 20           [4] 02922 CMPLBL   LDX    I
    .1550 DF 76           [5] 02923          STX    XTEMP     GET I INTO XTEMP
    .1552 DE 22           [4] 02924          LDX    J
    .1554 DF 80           [5] 02925          STX    XTEMP5    GET J INTO XTEMP5
    .1556 C6 06           [2] 02926          LDAB   #$06      SET COMPARE COUNT
    .1558 DE 76           [4] 02927 CMPLB1   LDX    XTEMP
    .155A A6 00           [5] 02928          LDAA   0,X       GET CHAR FROM I
    .155C 08              [4] 02929          INX
    .155D DF 76           [5] 02930          STX    XTEMP
    .155F DE 80           [4] 02931          LDX    XTEMP5
    .1561 A1 00           [5] 02932          CMPA   0,X       COMPARE WITH J CHAR
    .1563 26 06 (156B)    [4] 02933          BNE    CMPLB2    EXIT IF NOT EQUAL
    .1565 08              [4] 02934          INX
    .1566 DF 80           [5] 02935          STX    XTEMP5
    .1568 5A              [2] 02936          DECB             ELSE DECREMENT COUNT
    .1569 26 ED (1558)    [4] 02937          BNE    CMPLB1    LOOP UNTIL DONE
    .156B 39              [5] 02938 CMPLB2   RTS
    The 6502 code:

    Code:
    .1981                     04172 CMPLBL
    .                         04173 ; LDX I
    .                         04174 ; STX XTEMP ; GET I INTO XTEMP
    .                         04175 ; LDX J
    .                         04176 ; STX XTEMP5 ; GET J INTO XTEMP5
    .1981 A0 00           [2] 04177          ldy    #0        ; SET index
    .1983                     04178 CMPLB1                    ;LDX XTEMP
    .1983 B1 22         [5/6] 04179          lda    (I),Y     ; GET CHAR FROM I
    .                         04180 ; INX
    .                         04181 ; STX XTEMP
    .                         04182 ; LDX XTEMP5
    .1985 D1 24         [5/6] 04183          cmp    (J),Y     ; COMPARE WITH J CHAR
    .1987 D0 05 (198E)  [2/3] 04184          bne    CMPLB2    ; EXIT IF NOT EQUAL
    .                         04185 ; INX
    .                         04186 ; STX XTEMP5
    .                         04187
    .1989 C8              [2] 04188          iny              ; ELSE inCREMENT index
    .198A C0 06           [2] 04189          cpy    #6
    .198C D0 F5 (1983)  [2/3] 04190          bne    CMPLB1    ; LOOP UNTIL DONE
    .                         04191
    .198E 60              [6] 04192 CMPLB2   rts
    PUSH pushes an address onto a software stack. This code is an even test which illustrates shortcomings in both processors. The 6800 does not provide easy access to the index register; this is corrected in the 6809. The 6502 does not provide an easy way to perform 16-bit arithmetic.

    The original 6800 code:

    Code:
    .14B5 DF 80           [5] 02823 PUSH     STX    XTEMP5    PUT THE VALUE IN
    .14B7 DE 28           [4] 02824          LDX    SRSP      THE X REGISTER ONTO THE
    .14B9 96 80           [3] 02825          LDAA   XTEMP5    SORT REQUEST STACK AND
    .14BB A7 00           [6] 02826          STAA   0,X       UPDATE THE SORT REQUEST
    .14BD 08              [4] 02827          INX              STACK POINTER
    .14BE 96 81           [3] 02828          LDAA   XTEMP5+1
    .14C0 A7 00           [6] 02829          STAA   0,X
    .14C2 08              [4] 02830          INX
    .14C3 DF 28           [5] 02831          STX    SRSP
    .14C5 39              [5] 02832          RTS
    The 6502 code:

    Code:
    .18AB                     03977 PUSH
    .                         03978 ; STX XTEMP5 ; PUT THE VALUE IN
    .                         03979 ; LDX SRSP ; THE X REGISTER ONTO THE
    .                         03980 ; LDAA XTEMP5 ; SORT REQUEST STACK AND
    .                         03981
    .                         03982 ; Address in A:X
    .18AB A0 01           [2] 03983          ldy    #1
    .18AD 91 2A           [6] 03984          sta    (SRSP),Y  ; UPDATE THE SORT REQUEST
    .18AF 88              [2] 03985          dey              ; STACK POINTER
    .18B0 8A              [2] 03986          txa
    .18B1 91 2A           [6] 03987          sta    (SRSP),Y
    .                         03988
    .18B3 18              [2] 03989          clc              ; Update "stack pointer"
    .18B4 A5 2A           [3] 03990          lda    SRSP
    .18B6 69 02           [2] 03991          adc    #2
    .18B8 85 2A           [3] 03992          sta    SRSP
    .18BA A5 2B           [3] 03993          lda    SRSP+1
    .18BC 69 00           [2] 03994          adc    #0
    .18BE 85 2B           [3] 03995          sta    SRSP+1
    .                         03996
    .18C0 60              [6] 03997          rts
    At this time, the symbol table sorter has been completely coded. Wish me luck as I begin to test it...

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •