Joined: Fri Aug 30, 2002 1:09 am Posts: 8543 Location: Southern California
|
IamRob wrote: I don't have a built in assembler in Forth, mostly because I have trouble grasping the RPN of assembly. You don't have to. I had to work with RPN assembly briefly around 1990 at work and absolutely hated it. (Nothing against those who like it though.) Years later, it only took me a couple of hours to write my 6502 Forth assembler in its original form (but I did some improvements later, and still have more in mind). The bulk of it, ie, the main stuff, without going into branching for example, was this kind of thing:
Code: : ADC# 69 C, ; : AND# 29 C, ; : ASL_A 0A C, ; : ADC_ABS 6D C, ; : AND_ABS 2D C, ; : ASL_ABS 0E C, ; : ADC_ZP 65 C, ; : AND_ZP 25 C, ; : ASL_ZP 06 C, ; : ADC(ZP) 72 C, ; : AND(ZP) 32 C, ; : ASL,X 1E C, ; : ADC,X 7D C, ; : AND,X 3D C, ; : ASL_ZP,X 16 C, ; : ADC,Y 79 C, ; : AND,Y 39 C, ; : ADC_ZP,X 75 C, ; : AND_ZP,X 35 C, ; : ADC(ZP,X) 61 C, ; : AND(ZP,X) 21 C, ; : ADC(ZP),Y 71 C, ; : AND(ZP),Y 31 C, ;
<etc.> which shows most of the '02 addressing modes. So you just put the mnemonic down followed by the operand (if any) with a comma (or C-comma, or in the case of the '816, a "3C," also, for the few times you need a three-byte operand). There is no parsing, even though the mnemonic precedes the operand. It is up to you to specify the addressing mode along with the mnemonic, and to use the right word to compile the operand (whether comma or C-comma). So you'll do for example,
Code: LDA_ABS FOOBAR , Later I wrote a word "comp_op", laid down by macro OP_CODE, to shorten the op-code words by five bytes each (this is from the Forth assembly source-code, not high-level Forth):
Code: HEADER "ADC#", NOT_IMMEDIATE OP_CODE $69 so that after the header (formed by the HEADER macro), there are only the two bytes of CFA (pointing to comp_op) laid down in the code field by the OP_CODE macro, followed by the one byte of op code which the macro also lays down, and nothing more, ie, no nest, unnest, or lit, and only one byte (not two) for the op code number itself. comp_op also takes care of the semicolon's job, so it's all there, without adding more bytes.
For the places in the kernel where you'd want to jump to in various primitives you would write, I have constants like this:
Code: 8F34 CONSTANT POP 8F74 CONSTANT SET-TRUE 8F32 CONSTANT POP2 8F86 CONSTANT SET-FALSE 8F7E CONSTANT POP2-FALSE 8F38 CONSTANT CPUSH 8F6C CONSTANT POP2-TRUE 8F3B CONSTANT PUSH 8F30 CONSTANT POP3 8F84 CONSTANT PUSH-FALSE 8F6A CONSTANT POP3-TRUE 8F72 CONSTANT PUSH-TRUE 8F7C CONSTANT POP3-FALSE 8F3D CONSTANT PUT 8F6E CONSTANT POP-TRUE 8F42 CONSTANT NEXT 8F80 CONSTANT POP-FALSE 00FD CONSTANT XSAVE 00F0 CONSTANT N C98D CONSTANT setirq 4 CONSTANT tempA FE CONSTANT irq?\
Note that no separate assembler vocabulary is needed, because for example assembly's AND will not conflict with Forth's AND because assembly's word always comes with the addressing mode, whether #, _ABS, or whatever, as part of the name.
And, not particularly related to this method, not that being Forth, macro capability is built in, with no extra effort on the part of the person writing the assembler!
There's a little more to it, particularly in the matter of branching and labels, but It'll take me more time to describe that, which I'll do later if you're interested. For now, this should give you the ideas to get started. You assembly source code then won't look so different from how it does for a normal assembler.
_________________ 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?
|
|