6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 2:18 am

All times are UTC




Post new topic Reply to topic  [ 19 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Wed Jan 06, 2021 9:25 pm 
Offline
User avatar

Joined: Wed Feb 23, 2005 9:20 am
Posts: 23
Location: Zurich, Switzerland
Hi All,

(My first post, I think!)

I have a question that I thought might be best considered here, even though it's not strictly 6502 related *ahem*, but bear with me.

I'm using Brad R's excellent CamelForth/6809 that I have running on the Vectrex video game console, from 1982. My current project consists of salvaging a 6809 binary from a late 1970's FLEX disk and porting it onto the Vectrex. CamelForth/6809 comes with the 'Chromium' cross-compiler/assembler and I've started converting the FLEX binary, which I've disassembled, into CamelForth assembly.

First tests are good, the assembly works as expected, but then I hit a number of flag tests/branches and associated forward jumps, which the cross-assembler can't handle. Luckily, CamelForth assembler has IF, ELSE, THEN, etc. that in most cases I can substitute in.

But now I'm a bit further into the code, I'm hitting routines where the code flow jumps all over the place, e.g. out of BEGIN, UNTIL, loops, including using out of sequence IF, THEN,. Clearly, if the code was built using IF, THEN, etc. in the first place, I wouldn't be seeing this issue, but it wasn't and it looks like a laborious major restructuring to make it assemble with CamelForth.

My current thought is to abandon the attempt to convert to CamelForth assembly and use a regular assembler with the code as-is and attach the assembled binary to my Forth cross compiled binary and jump to the routines instead.

But before I do that, I thought I'd just ask around if anyone else had done something similar or had any further words of wisdom that might switch a light on.

Thanks for reading.

(And sorry it's not pure 6502. Actually, I have the idea to create a new cartridge for the Vectrex that would halt the 6809 and instead contain an '816 and a program ROM, which could then take over the system. People have already done it with an ARM, why not a '816?)

_________________
P*h*i*l*l*i*p EEaattoon in real life


Top
 Profile  
Reply with quote  
PostPosted: Wed Jan 06, 2021 11:39 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
pjeaton wrote:
Hi All,

(My first post, I think!)

It's your 10th post, the first one in 27 months.

Quote:
I have a question that I thought might be best considered here, even though it's not strictly 6502 related *ahem*, but bear with me. [...] (And sorry it's not pure 6502. Actually, I have the idea to create a new cartridge for the Vectrex that would halt the 6809 and instead contain an '816 and a program ROM, which could then take over the system. People have already done it with an ARM, why not a '816?)

The 65816 part is the 65 content, which is good, because this is a 65 forum, and the subtitle for this Forth section of the forum, as shown on the front page of the forum, is "Topics relating to various Forth models on the 6502, 65816, and related microprocessors and microcontrollers."

Quote:
My current thought is to abandon the attempt to convert to CamelForth assembly and use a regular assembler with the code as-is and attach the assembled binary to my Forth cross-compiled binary and jump to the routines instead.

But before I do that, I thought I'd just ask around if anyone else had done something similar

Are you trying to come up with an assembly-language source code for a Forth kernel, to be assembled by a non-Forth assembler? This will have various pros and cons. I have to tried to disassemble anyone's Forth, but I've written my own '816 Forth source to assemble with the C32 cross-assembler. I've also assembled shorter pieces of code on the PC and had my already-running Forth (on the workbench computer) take it in as an Intel Hex file, then call it from the previously existing Forth. Can you be more specific about what problems you're having?

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 07, 2021 12:44 am 
Offline
User avatar

Joined: Wed Feb 23, 2005 9:20 am
Posts: 23
Location: Zurich, Switzerland
Oh wow, you're right, I'm not a newbie after all, although most of my posts were 16 years ago, I guess they slipped my mind!

Quote:
...and related[/u] microprocessors and microcontrollers."

I hesitated before posting that I was using a 6809 as this is really just a structured-assembly & Forth question and I knew structured-assembly was definitely on topic here, but I thought I'd just be transparent up front.

The '816 part is definitely real, though, as there are a lot of 6502 programmers out there and due to the 6809 not having the power to provide much in the way of on-the-fly animation, you need to pre-calculate animation vector lists and that quickly eats up the 48KiB of usable address space. The '816 expanded memory management could be a more elegant solution than is currently used.

So, my project...what I'm actually trying to do is port the first Sargon chess engine from the SWTPC 6809 to the Vectrex 6809. The custom user interface interface part I will strip out and initially I'll run the engine from the Forth interpreter via a terminal I have connected. Later, I'll create an interface for the vector monitor, using Forth.

I have an early non-working iteration of the 6809 code, but the actual working** binary code was updated quite a lot afterwards, but that later source code is lost, so I've disassembled the working binary to get something that resembles the source code and re-engineered it with the comments etc from the non-working early version.

**Actually it's mostly working, you can play a game on the SWTPC, but it doesn't make the same moves as the original Z80 real Sargon engine does, I need to fix that.

Quote:
I've also assembled shorter pieces of code on the PC and had my already-running Forth (on the workbench computer) take it in as an Intel Hex file, then call it from the previously existing Forth...

I do this with my CamelForth on the Vectrex, I call the BIOS ROM routines that allow me to draw on the screen, read the joystick, play music etc. via the 6522/AY38910/DAC, without having to write my own drivers.

One part I've already converted is this code below (almost assembles). The layout I'm not too sure about, but the problem is the MP15 branch half way down, it jumps out of a BEGIN, UNTIL, loop and that's going probably going to break an IF, THEN, compilation. The MP20 branch does the same thing again. I could probably fix this routine quite easily, either by restructuring the code or changing the Forth cross assembler to not use the same address variable for BEGIN, and IF, patching, but subsequent routines are much more complicated.

I guess I'm just batting round the pros and cons of Forth jumping to a separately assembled block of code as opposed to merging the assembly source with the Forth source, the latter being much neater and would mean I don't need to stitch the separate binary code together.

Code:
10 asm:
11 here equ MPIECE
12    COLOR                EORA,   \ Restore color of piece
13    $87 #                ANDA,   \ Clear all flags except color flag
14    BPAWN #              CMPA,   \ Is it a black Pawn?
15    EQ IF,                       \ Skip if not (BNE)
16                         DECA,   \ Decrement by one for black Pawn
17    THEN,                        \
18    7 #                  ANDA,   \ Clear color flag
19    M1                   STA,    \ Save piece type (M1+1 ??????, then xfer to Y?)
20    M1                   LDY,    \ Load index to DCOUNT/DPOINT
21    Y DCOUNT ,           LDB,    \ Get direction count
22    Y DPOINT ,           LDA,    \ Get direction pointer
23    INDX2                STA,    \ Save as index to direction table (INDX2+1 ????)
24    INDX2                LDY,    \ Load index to direction table
25    BEGIN,
26       Y DIRECT ,        LDA,    \ Get move direction and increment pointer
27       RC                STA,    \ Save it as parameter for PATH
28       M1                LDA,    \ Get "from" position (M1+1 ?????)
29       M2                STA,    \ Initialize "to" position (M1+2 ?????)
30       BEGIN,
31          PATH           JSR,    \ Calculate next position
32          #2             CMPA,   \ Ready for new direction?
33 \         MP15           BCC,    \ Branch if yes
34          RC             STA,    \ Check for empty square and save results
35          T1             LDA,    \ Get moved piece
36          PAWN+1 #       CMPA,   \ Is it a Pawn? ( THIS ISN'T RIGHT)
37          MP20           BCS,    \ Branch if yes
38          ADMOVE         JSR,    \ Add move to list
39          RC             LDA,    \ Restore previous test results
40          MP15           BNE,    \ Branch if "to" square not empty
41          T1+1           LDA,    \ Get piece type
42          #KING          CMPA,   \ Is it a King?
43          MP15           BEQ,    \ Branch if yes
44          #BISHOP        CMPA,   \ Is it a Bishop, Rook, or Queen?
45       LO UNTIL,                 \ Branch if any of the above (BHS Branch if Higher or Same)
46 ( MP15 )                DECB,   \ Decrement direction counter
47    EQ UNTIL,                    \ Do next direction, if any
48    T1+1                 LDA,    \ Get piece type
49    #KING                CMPA,   \ is it a King?
50    MERTN                BNE,
51    EQ IF,                       \ Return if not (BNE)
52        CASTLE           JMP,    \ Consider castling
53    THEN,
54                         RTS,    \ Return
55 ;c

_________________
P*h*i*l*l*i*p EEaattoon in real life


Last edited by pjeaton on Thu Jan 07, 2021 2:47 pm, edited 2 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 07, 2021 1:25 am 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
It sounds to as if the problem is that the 'Chromium' cross-compiler/assembler allows only structured control flow -- IOW, it will accept IF, ELSE, ENDIF, in the source code but not BNE BEQ and so on.

I have dealt with a similar situation when using Bill Ragsdale's RPN assembler for 6502. It sometimes happen that I want to use conditionals in an unstructured way, and I accomplish this by adding snippets in the source code, snippets which cause the necessary bytes to output. For example, ...
D0 C, DESIRED_DESTINATION HERE 1+ - C,
... will cause a BNE opcode then its 8-bit offset to be assembled.

This is somewhat messy, but it lets me "break the rules" and bypass the compiler security checking which otherwise insists that IF pair with ENDIF and so on... and the code Phillip is trying to reproduce breaks the rules in the same way.

If you search on this forum for "compiler security" then you'll find there's another (arguably less messy) way, and that involves juggling items the assembler has on stack instead. Here is one post in that vein.

In Brad R's documentation, does he talk about bypassing compiler security checking?

Returning to my example, it's a backward branch which I assemble. DESIRED_DESTINATION is a constant created previously, of course. But it'll save memory if the associated address can simply be left on the stack.

This is not a complete description; for example I haven't addressed the question of forward branches. If necessary I will, but I'm hoping you will instead find the necessary answer in Brad's doc or in other posts on this forum.

Edit: missed your latest post while I was typing, Phillip.

If you tell me what is the destination of the MP15 branch half way down then I'll try to illustrate a solution.

-- Jeff

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


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 07, 2021 3:36 pm 
Offline
User avatar

Joined: Wed Feb 23, 2005 9:20 am
Posts: 23
Location: Zurich, Switzerland
Jeff, thanks for your thoughts.

So you have a similar problem with an 'engineering' workaround, glad I'm not alone. The Forth assembler will handle BEQ, etc, but it can't handle a forward reference as the target. In the listing I gave (I now added line numbers) the BEQ,/BNE, on lines 33 and 40 jump out of the BEGIN, UNTIL, to line 46. Similarly, the BCS on line 37 jumps right past the code snippet I've gave.

I hadn't thought to review the documentation of the assembler, I guess I should have a look, but I'm not expecting it to be accommodated, I think it stated somewhere that it's not supposed to be a full-blown assembler, it's for putting together speed-up routines for Forth purposes. For new code design, I think it's control structures would be quite beneficial.

Perhaps I should look into changing the assembler to be able to handle forward references cleanly.

I just looked in the manual for MPEs VFX forth and it too offers both IF, THEN, etc. and labels, including forward referenced ones, it even has an example showing the same code written with each method. It can also work in prefix and postfix modes - oh the luxury!

I'll also checkout the links you provided - thanks!

Phil

_________________
P*h*i*l*l*i*p EEaattoon in real life


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 07, 2021 3:47 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3367
Location: Ontario, Canada
pjeaton wrote:
I hadn't thought to review the documentation of the assembler, I guess I should have a look, but I'm not expecting it to be accommodated

Myself, I expect Brad will have something to say on the subject, so start your investigation here. The problem you're experiencing is fairly common, I suspect.

-- Jeff

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


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 07, 2021 5:45 pm 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
Quote:
The layout I'm not too sure about, but the problem is the MP15 branch half way down, it jumps out of a BEGIN, UNTIL, loop and that's going probably going to break an IF, THEN, compilation. The MP20 branch does the same thing again. I could probably fix this routine quite easily, either by restructuring the code or changing the Forth cross assembler to not use the same address variable for BEGIN, and IF, patching, but subsequent routines are much more complicated.

Code:
25    BEGIN,
26       Y DIRECT ,        LDA,    \ Get move direction and increment pointer
27       RC                STA,    \ Save it as parameter for PATH
28       M1                LDA,    \ Get "from" position (M1+1 ?????)
29       M2                STA,    \ Initialize "to" position (M1+2 ?????)
30       BEGIN,
31          PATH           JSR,    \ Calculate next position
32          #2             CMPA,   \ Ready for new direction?
33 \         MP15           BCC,    \ Branch if yes
34          RC             STA,    \ Check for empty square and save results
35          T1             LDA,    \ Get moved piece
36          PAWN+1 #       CMPA,   \ Is it a Pawn? ( THIS ISN'T RIGHT)
37          MP20           BCS,    \ Branch if yes
38          ADMOVE         JSR,    \ Add move to list
39          RC             LDA,    \ Restore previous test results
40          MP15           BNE,    \ Branch if "to" square not empty
41          T1+1           LDA,    \ Get piece type
42          #KING          CMPA,   \ Is it a King?
43          MP15           BEQ,    \ Branch if yes
44          #BISHOP        CMPA,   \ Is it a Bishop, Rook, or Queen?
45       LO UNTIL,                 \ Branch if any of the above (BHS Branch if Higher or Same)
46 ( MP15 )                DECB,   \ Decrement direction counter
...
60 ( MP20 )

Since IF/THEN already handles forward branching, just rewrite the definitions and add them to the assembler.
Maybe something like this which allows for up to 3 forward branches that overlap:

: IF1 HERE 1- 0 ! ;
: IF2 HERE 1- 2 ! ;
: IF3 HERE 1- 4 ! ;
: THEN1 HERE 0 @ - 0 @ C! ;
: THEN2 HERE 2 @ - 2 @ C! ;
: THEN3 HERE 4 @ - 4 @ C! ;

The zero-page addresses 0,2,4 are locations that are free for use but can be made into variables instead if preferred.

Now the code becomes
Code:
25    BEGIN,
26       Y DIRECT ,        LDA,    \ Get move direction and increment pointer
27       RC                STA,    \ Save it as parameter for PATH
28       M1                LDA,    \ Get "from" position (M1+1 ?????)
29       M2                STA,    \ Initialize "to" position (M1+2 ?????)
30       BEGIN,
31          PATH           JSR,    \ Calculate next position
32          #2             CMPA,   \ Ready for new direction?
***
HERE EQU MP15   \ calculates a backward branch just to reserve the BCC opcode
***
33          MP15           BCC,    \ Branch if yes
***
              IF1         \ IF1 backs up the DP one byte so THEN1 overwrites the branch value after BCC
***
34          RC             STA,    \ Check for empty square and save results
35          T1             LDA,    \ Get moved piece
36          PAWN+1 #       CMPA,   \ Is it a Pawn? ( THIS ISN'T RIGHT)
***
HERE EQU MP20
***
37          MP20           BCS,    \ reserve the BCS opcode
***
              IF2       \ IF2 backs up the DP one byte so THEN2 overwrites the branch value after BCS
***
38          ADMOVE         JSR,    \ Add move to list
39          RC             LDA,    \ Restore previous test results
40          MP15           BNE,    \ Branch if "to" square not empty
41          T1+1           LDA,    \ Get piece type
42          #KING          CMPA,   \ Is it a King?
43          MP15           BEQ,    \ Branch if yes
44          #BISHOP        CMPA,   \ Is it a Bishop, Rook, or Queen?
45       LO UNTIL,                 \ Branch if any of the above (BHS Branch if Higher or Same)
***
46 ( MP15 ) THEN1       \ stores the forward offset difference at IF1
***
             DECB,   \ Decrement direction counter
...
***
60 ( MP20 ) THEN2    \ stores the forward offset difference at IF2
***


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 07, 2021 6:45 pm 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
Add these words to work with inline absolute code.

: IFABSL HERE 2- 0 ! ;
: IFABSH HERE 2- 2 ! ;
: THENABSL HERE 2- 0 @ ! ; \ absolute address points to lo-byte
: THENABSH HERE 1- 2 @ ! ; \ absolute address points to hi-byte


Code:
CALL   DW *+2
   STX XSAVE    ; ($F5)

   LDA 0,X
   STA CALL1+1
   LDA 1,X
   STA CALL1+2

   LDA 0      ; Acc
   LDX 1      ; X-reg
   LDY 2      ; Y-reg
CALL1   JSR $FF58   ; place holder
   STY 2
   STX 1
   STA 0

   LDX XSAVE    ; ($F5)
   INX
   INX
   JMP NEXT


becomes

Code:
CALL   DW *+2
   STX XSAVE    ; ($F5)

   LDA $0,X
   STA $0000
***
   IFABSL
***
   LDA $1,X
   STA $0000
***
   IFABSH
***
   LDA $6      ; Acc
   LDX $7      ; X-reg
   LDY $8      ; Y-reg
   JSR $0000   ; place holder
***
   THENABSL      \ store absolute pointer for lo-byte
   THENABSH   \ store absolute pointer for hi-byte
***
   STY $8
   STX $7
   STA $6

   LDX XSAVE    ; ($F5)
   INX
   INX
   JMP NEXT


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 07, 2021 8:25 pm 
Offline
User avatar

Joined: Wed Feb 23, 2005 9:20 am
Posts: 23
Location: Zurich, Switzerland
Thanks for your thoughts, guys.

I read the other threads mentioned and though Brad's assembler documentation and it's sparse, with nothing on forward references. In fact, the only reference I had seen was actually in the Camel Forth primitives declarations, where he uses HERE EQU <LABEL> to create backward references in few circumstances where structured programming might have been a bit verbose.

But I did come across this text below, regarding the Forth assembler, in one of Brad's papers:

Quote:
4. Labels

Even in the era of structured programming, some programmers
will insist on labels in their assembler code.

The principal problem with named labels in a Forth assembler
definition is that the labels themselves are Forth words.
They are compiled into the dictionary -- usually at an
inconvenient point, such as inside the machine code. For
example:

CODE TEST ... machine code ...
HERE CONSTANT LABEL1
... machine code ...
LABEL1 NZ JP,

will cause the dictionary header for LABEL1 -- text, links,
and all -- to be inserted in the middle of CODE. Several
solutions have been proposed:

a) define labels only "outside" machine code.
Occasionally useful, but very restricted.

b) use some predefined storage locations (variables) to
provide "temporary," or local, labels.

c) use a separate dictionary space for the labels, e.g.,
as provided by the TRANSIENT scheme [3].

d) use a separate dictionary space for the machine code.
This is common practice for meta-compilation; most
Forth meta- compilers support labels with little
difficulty.

So clearly, he wasn't a fan of labels and from what I can see of the source code, there's no specific functionality to accommodate them, but this does provide food for thought.

Now as I was thinking about this, I also came up with the idea of following a HERE EQU <LABEL> with a dummy C, address and then storing the target address using something like HERE <LABEL> C! (but with the subtraction to make it relative). I'm actually doing this a part of the regular CamelForth cross-compile, because the Vectrex has a hardcoded program start address, so I have to create a placeholder JMP address at that hardcoded address to then boot Forth and I backfill that placeholder when I know where it should JMP to.

And, now I see the suggested IF1, IF2, and IF3, as a less kludgy way of doing the same. It's not pretty, but it looks like it could do the job. I guess it would be something like the existing structured conditionals I found, but not using the stack for storage:
Code:
: IF,     \ br.opcode -- adr.next.instr  | reserve space
   TC, 0 TC, THERE ;
: ENDIF,  \ adr.instr.after.br -- | patch the forward ref.
   THERE OVER -  DUP 8BIT? 0= ?ADRERR  SWAP 1- TC! ;
: ELSE,   \ adr.after.br -- adr.after.this.br
   NVR IF,  SWAP ENDIF, ;
: BEGIN,  \ -- dest.adr
   THERE ;
: UNTIL,  \ dest.adr br.opcode --
   TC,  THERE 1+ -  DUP 8BIT? 0= ?ADRERR  TC, ;
: WHILE,  \ dest.adr br.opcode -- adr.after.this dest.adr
   IF, SWAP ;
: REPEAT, \ adr.after.while dest.adr.of.begin --
   NVR UNTIL,  ENDIF, ;
: THEN,  ENDIF, ;   : END,  UNTIL, ;


Now I need to do some more experiments - thanks again!

_________________
P*h*i*l*l*i*p EEaattoon in real life


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 07, 2021 9:36 pm 
Offline

Joined: Sun Apr 26, 2020 3:08 am
Posts: 357
IamRob wrote:
Since IF/THEN already handles forward branching, just rewrite the definitions and add them to the assembler.
Maybe something like this which allows for up to 3 forward branches that overlap:

: IF1 HERE 1- 0 ! ;
: IF2 HERE 1- 2 ! ;
: IF3 HERE 1- 4 ! ;
: THEN1 HERE 0 @ - 0 @ C! ;
: THEN2 HERE 2 @ - 2 @ C! ;
: THEN3 HERE 4 @ - 4 @ C! ;

The zero-page addresses 0,2,4 are locations that are free for use but can be made into variables instead if preferred.

Now the code becomes
Code:
25    BEGIN,
26       Y DIRECT ,        LDA,    \ Get move direction and increment pointer
27       RC                STA,    \ Save it as parameter for PATH
28       M1                LDA,    \ Get "from" position (M1+1 ?????)
29       M2                STA,    \ Initialize "to" position (M1+2 ?????)
30       BEGIN,
31          PATH           JSR,    \ Calculate next position
32          #2             CMPA,   \ Ready for new direction?
***
HERE EQU MP15   \ calculates a backward branch just to reserve the BCC opcode
***
33          MP15           BCC,    \ Branch if yes
***
              IF1         \ IF1 backs up the DP one byte so THEN1 overwrites the branch value after BCC
***
34          RC             STA,    \ Check for empty square and save results
35          T1             LDA,    \ Get moved piece
36          PAWN+1 #       CMPA,   \ Is it a Pawn? ( THIS ISN'T RIGHT)
***
HERE EQU MP20
***
37          MP20           BCS,    \ reserve the BCS opcode
***
              IF2       \ IF2 backs up the DP one byte so THEN2 overwrites the branch value after BCS
***
38          ADMOVE         JSR,    \ Add move to list
39          RC             LDA,    \ Restore previous test results
40          MP15           BNE,    \ Branch if "to" square not empty
41          T1+1           LDA,    \ Get piece type
42          #KING          CMPA,   \ Is it a King?
43          MP15           BEQ,    \ Branch if yes
44          #BISHOP        CMPA,   \ Is it a Bishop, Rook, or Queen?
45       LO UNTIL,                 \ Branch if any of the above (BHS Branch if Higher or Same)
***
46 ( MP15 ) THEN1       \ stores the forward offset difference at IF1
***
             DECB,   \ Decrement direction counter
...
***
60 ( MP20 ) THEN2    \ stores the forward offset difference at IF2
***

After studying this some more, I realize that one may have to create quite a few IFx/THENx statements. The (MP15) at lines 40 and 43, requires there to be a another IF3/THEN3 and IF4/THEN4 to be created. Line #46 would then have THEN1 THEN3 THEN4

To me, this started looking like an array of addresses. I then came up with this to simplify things:

: ARRAY <BUILDS 2 * ALLOT DOES> 2 * + ;
6 ARRAY BRANCHES ( reserves 6 cells ) \ Branch #'s are 0-5 and this number can be easily adjusted to handle more cells
: IFBR ( n --- ) BRANCHES HERE 1- SWAP ! ; \ store address in array
: THENBR ( n --- ) BRANCHES @ DUP HERE SWAP - SWAP ! ; \ restore address, calculate branch offset and store offset

now the code becomes:

Code:
[code]
25    BEGIN,
26       Y DIRECT ,        LDA,    \ Get move direction and increment pointer
27       RC                STA,    \ Save it as parameter for PATH
28       M1                LDA,    \ Get "from" position (M1+1 ?????)
29       M2                STA,    \ Initialize "to" position (M1+2 ?????)
30       BEGIN,
31          PATH           JSR,    \ Calculate next position
32          #2             CMPA,   \ Ready for new direction?
***
HERE EQU MP15   \ calculates a backward branch just to reserve the BCC opcode
***
33          MP15           BCC,    \ Branch if yes
***
             1 IFBR         \ IF1 backs up the DP one byte so THEN1 overwrites the branch value after BCC
***
34          RC             STA,    \ Check for empty square and save results
35          T1             LDA,    \ Get moved piece
36          PAWN+1 #       CMPA,   \ Is it a Pawn? ( THIS ISN'T RIGHT)
***
HERE EQU MP20
***
37          MP20           BCS,    \ reserve the BCS opcode
***
              2 IFBR       \ IF2 backs up the DP one byte so THEN2 overwrites the branch value after BCS
***
38          ADMOVE         JSR,    \ Add move to list
39          RC             LDA,    \ Restore previous test results
40          MP15           BNE,    \ Branch if "to" square not empty
***
             3 IFBR
***           
41          T1+1           LDA,    \ Get piece type
42          #KING          CMPA,   \ Is it a King?
43          MP15           BEQ,    \ Branch if yes
***
              4 IFBR
***
44          #BISHOP        CMPA,   \ Is it a Bishop, Rook, or Queen?
45       LO UNTIL,                 \ Branch if any of the above (BHS Branch if Higher or Same)
***
46 ( MP15 ) 1 THENBR       \ stores forward offset at IFBR #1
              3 THENBR           \ stores forward offset at IFBR #3
              4 THENBR           \ stores forward offset at IFBR #4
***
             DECB,   \ Decrement direction counter
...
***
60 ( MP20 ) 2 THENBR    \ stores the forward offset at IFBR #2
***


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 07, 2021 9:45 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
pjeaton wrote:
Thanks for your thoughts, guys.

I read the other threads mentioned and though Brad's assembler documentation and it's sparse, with nothing on forward references. In fact, the only reference I had seen was actually in the Camel Forth primitives declarations, where he uses HERE EQU <LABEL> to create backward references in few circumstances where structured programming might have been a bit verbose.

But I did come across this text below, regarding the Forth assembler, in one of Brad's papers:

Quote:
Code:
4. Labels

    Even in the era of structured programming, some programmers
    will insist on labels in their assembler code.

    The principal problem with named labels in a Forth assembler
    definition is that the labels themselves are Forth words.
    They are compiled into the dictionary -- usually at an
    inconvenient point, such as inside the machine code.  For
    example:

              CODE TEST  ...  machine code  ...
                   HERE CONSTANT LABEL1
                   ...  machine code  ...
                   LABEL1 NZ JP,

    will cause the dictionary header for LABEL1 -- text, links,
    and all -- to be inserted in the middle of CODE.  Several
    solutions have been proposed:

      a) define labels only "outside" machine code.
         Occasionally useful, but very restricted.

      b) use some predefined storage locations (variables) to
         provide "temporary," or local, labels.

      c) use a separate dictionary space for the labels, e.g.,
         as provided by the TRANSIENT scheme [3].

      d) use a separate dictionary space for the machine code.
         This is common practice for meta-compilation; most
         Forth meta- compilers support labels with little
         difficulty.

So clearly, he wasn't a fan of labels and from what I can see of the source code, there's no specific functionality to accommodate them, but this does provide food for thought.

Regarding c) above, see my posts here and here, a little past the middle of each post, regarding compiling address constants in software buffers at the end of memory, which you can delete when you're done with them and they don't take any space in the final memory space.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 07, 2021 11:09 pm 
Offline
User avatar

Joined: Wed Feb 23, 2005 9:20 am
Posts: 23
Location: Zurich, Switzerland
Quote:
To me, this started looking like an array of addresses. I then came up with this to simplify things:

: ARRAY <BUILDS 2 * ALLOT DOES> 2 * + ;

Thanks - I will consider this also!

_________________
P*h*i*l*l*i*p EEaattoon in real life


Top
 Profile  
Reply with quote  
PostPosted: Thu Jan 07, 2021 11:57 pm 
Offline
User avatar

Joined: Wed Feb 23, 2005 9:20 am
Posts: 23
Location: Zurich, Switzerland
I've done an experiment and, roughly, I have a working proof of concept.

The following code (lots of commented out lines, as they don't assemble yet):
Code:
      RC                STA,    \ Save it as parameter for PATH
      M1                LDA,    \ Get "from" position (M1+1 ?????)
      M2                STA,    \ Initialize "to" position (M1+2 ?????)
      BEGIN,
         PATH           JSR,    \ Calculate next position
         2 #            CMPA,   \ Ready for new direction?
\        MP15           BCC,    \ Branch if yes
         here           BCC,
here 1 - equ MP15
         RC             STA,    \ Check for empty square and save results
         T1             LDA,    \ Get moved piece
         PAWN+1 #       CMPA,   \ Is it a Pawn? ( THIS ISN'T RIGHT)
\        MP20           BCS,    \ Branch if yes
\        ADMOVE         JSR,    \ Add move to list
         RC             LDA,    \ Restore previous test results
\        MP15           BNE,    \ Branch if "to" square not empty
\        T1+1           LDA,    \ Get piece type
\        #KING          CMPA,   \ Is it a King?
\        MP15           BEQ,    \ Branch if yes
\        #BISHOP        CMPA,   \ Is it a Bishop, Rook, or Queen?
      LO UNTIL,                 \ Branch if any of the above (BHS Branch if Higher or Same)
here MP15 - 1 - MP15 c!
                        DECB,   \ Decrement direction counter

assembles to: (copied from the Vectrex "VIDE" emulator debugger, <<< lines added manually)
Code:
Address Label   Content    Mnemon  Operand ~   ->Address
--------------------------------------------------------
$4C57           B7 4B 39   sta     >_4B39  5   $4B39
$4C5A           B6 4B 27   lda     >_4B27  5   $4B27
$4C5D           B7 4B 29   sta     >_4B29  5   $4B29
<<<< BEGIN,
$4C60   _4C60:  BD 4B F3   jsr     >_4BF3  8   $4BF3 
$4C63           81 02      cmpa    #$02    2         
$4C65           24 0D      bcc     _4C74   3   $0D    <<<< BCC Patched OK
$4C67           B7 4B 39   sta     >_4B39  5   $4B39
$4C6A           B6 4B 2F   lda     >_4B2F  5   $4B2F
$4C6D           81 F4      cmpa    #$F4    2         
$4C6F           B6 4B 39   lda     >_4B39  5   $4B39
$4C72           24 EC      bcc     _4C60   3   -$14   <<<< UNTIL,
<<<< BCC Target
$4C74   _4C74:  5A         decb            2         


I've also just read through Garth's links and it looks like he's already done this almost exactly, with his clean label version!

However, just doing this PoC has brought to my attention that the CamelForth assembler doesn't produce a list file, so the only way to look at the code is via the debugger and that's a bit clunky and there are still no labels brought across. (I actually have a fix for that, but it's more work.)

Given the code I have is actually disassembled from a mostly working programme, I'm leaning towards a relative simple reassembly with a standalone assembler and call the binary code subroutines from Forth for debugging. I have other improvements to make in CamelForth, it doesn't have a CASE or ?DO words for starters, which is already fiddly. The whole point of this exercise is to make working Vectrex programs, improving Forth for Forth's sake is a secondary priority. (Though a lot of fun and Garth's clean labels solution is tempting :) ).

Also, converting between postfix and prefix and changing all branches to structures is bound to introduce bugs that will need extra testing and will still be messy because the code wasn't originally written with structure in mind.

Nonetheless, whichever way I go, this has been a super learning exercise, I really appreciate your input to the conversation.

_________________
P*h*i*l*l*i*p EEaattoon in real life


Top
 Profile  
Reply with quote  
PostPosted: Fri Jan 08, 2021 10:03 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
pjeaton wrote:
I guess it would be something like the existing structured conditionals I found, but not using the stack for storage:
Code:
: IF,     \ br.opcode -- adr.next.instr  | reserve space
   TC, 0 TC, THERE ;
: ENDIF,  \ adr.instr.after.br -- | patch the forward ref.
   THERE OVER -  DUP 8BIT? 0= ?ADRERR  SWAP 1- TC! ;
: ELSE,   \ adr.after.br -- adr.after.this.br
   NVR IF,  SWAP ENDIF, ;
: BEGIN,  \ -- dest.adr
   THERE ;
: UNTIL,  \ dest.adr br.opcode --
   TC,  THERE 1+ -  DUP 8BIT? 0= ?ADRERR  TC, ;
: WHILE,  \ dest.adr br.opcode -- adr.after.this dest.adr
   IF, SWAP ;
: REPEAT, \ adr.after.while dest.adr.of.begin --
   NVR UNTIL,  ENDIF, ;
: THEN,  ENDIF, ;   : END,  UNTIL, ;


Now I need to do some more experiments - thanks again!


That looks like source for a metacompiler's assembler.


Top
 Profile  
Reply with quote  
PostPosted: Fri Jan 08, 2021 10:45 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 895
pjeaton wrote:
So clearly, he wasn't a fan of labels and from what I can see of the source code, there's no specific functionality to accommodate them, but this does provide food for thought.


I don't see a bias against labels, just a statement of the difficulty with using them in Forth followed by four possible solutions.
My Forth is built with a metacompiler and the metacompiler's assembler is similar to the Forth assembler.
Although I don't use labels when writing CODE words in Forth, I do use labels in the source for some of the primitives in my Forth's kernel.


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

All times are UTC


Who is online

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