Shift838 Posted September 19, 2020 Share Posted September 19, 2020 So I thought I would try my hand at TurboForth and I am getting the concepts down. My question, is can the source code of my program be compiled into Assembly so that the program can be ran without the TurboForth cartridge, like EA option 3 or EA option 5 ? If so, how? 1 Quote Link to comment Share on other sites More sharing options...
GDMike Posted September 19, 2020 Share Posted September 19, 2020 (edited) I do know that fbforth and turboforth both have the ability to let you code in assembly as they have most of the 9900 assembler code as words that allows for assembler execution. Example, in TF registers are set as "R1," instead of "R1" and use words such as "SOC," instead of "SOC". Note the"," comma it may actually be at the beginning of the word instead of the end. I can't remember off hand, and the manual explains this, but no labels exist since forth handles the code. I've never heard of what you are asking for though. Also, I think if it were converted it would have timing Problems as do other programs that get converted. Edited September 19, 2020 by GDMike Quote Link to comment Share on other sites More sharing options...
+Lee Stewart Posted September 19, 2020 Share Posted September 19, 2020 1 hour ago, Shift838 said: So I thought I would try my hand at TurboForth and I am getting the concepts down. My question, is can the source code of my program be compiled into Assembly so that the program can be ran without the TurboForth cartridge, like EA option 3 or EA option 5? If so, how? The simple answer is no. Without a compiler written for that purpose, the best you can do is to compile/interpret your source code with Turboforth and BSAVE it for a later BLOAD that loads into memory the binary saved with BSAVE , which, of course, still requires the cartridge. The Forth code is compiled to a list of executable address that require the Forth Inner Interpreter to run. The cartridge contains all of the executable code those execution addresses reference. In order to actually do what you ask, a compiler such as Harry Wilhem (@senior_falcon) wrote for Basic would need to be developed for Turboforth. ...lee 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted September 20, 2020 Share Posted September 20, 2020 5 hours ago, Lee Stewart said: The simple answer is no. Without a compiler written for that purpose, the best you can do is to compile/interpret your source code with Turboforth and BSAVE it for a later BLOAD that loads into memory the binary saved with BSAVE , which, of course, still requires the cartridge. The Forth code is compiled to a list of executable address that require the Forth Inner Interpreter to run. The cartridge contains all of the executable code those execution addresses reference. In order to actually do what you ask, a compiler such as Harry Wilhem (@senior_falcon) wrote for Basic would need to be developed for Turboforth. ...lee Or one could use a Forth Cross-compiler. @shift838 This is a Forth compiler that generates code in separate memory space or even to disk if that's all there is. That memory image becomes a binary program when saved to disk. Forth cross-compilers are really cool from the intellectual standpoint , once you get them going but not for the faint of heart to create. It took me quite a while to get mine running. I have a Forth Cross-Assembler now. If you understand Forth's internals a now, you might (or not) want to study how it works. In theory, with the cross assembler you could assembler an entire Forth system with only what you needed and then write a game in that new Forth. The game would exist as a memory image that you could save as EA5 and run. This kind of stuff is probably best described as "black-belt" level Forth but I am happy to help if you are interested. It could be done on Turbo Forth as well. It would not take much of a preamble to make the turbo-forth assembler become a cross-assembler. Note: I have been thinking about improving my cross-compiler so that it more like normal Forth. It can never be exactly like normal Forth but I could remove a few warts here and there for other people to use it. 2 Quote Link to comment Share on other sites More sharing options...
+TheBF Posted September 20, 2020 Share Posted September 20, 2020 By way of example , here is the code for a Hello world program, written in Camel99 Forth Cross-Assembler Spoiler \ Cross compiling program demo NEEDS NEW. FROM DSK1.CROSS99 MARKER /XASMDEMO HEX NEW. A000 ORIGIN. SUB: WMODE R0 4000 ORI, R0 SWPB, 0 LIMI, R0 8C02 @@ MOVB, R0 SWPB, R0 8C02 @@ MOVB, RET, ;SUB SUB: VWRITE ( CPU-addr VDP-addr cnt -- ) WMODE @@ BL, BEGIN, TOS DEC, OC WHILE, R1 *+ 8C00 @@ MOVB, REPEAT, 2 LIMI, TOS POP, RET, ;SUB L: A$ S" Hello World!" TEXT, \ compiles a byte counted string \ main program......... PROG: XASMTEST 8300 LWPI, \ Forth workspace SP FF00 LI, \ set data stack RP FE00 LI, \ set return stack \ set up to write string A$ @@ TOS MOVB, \ get count byte to TOS TOS SWPB, \ swap byte to other side R1 A$ 1+ LI, \ start of text to R1 R0 CLR, \ VDP screen address to R0 VWRITE @@ BL, \ delay TOS FFFF LI, BEGIN, R1 16 SRL, R1 16 SLA, TOS DEC, EQ UNTIL, \ return to main menu 83E0 LWPI, R0 CLR, R0 837C @@ MOV, RT, END. CR .( Saving file ) S" DSK3.HELLO" 2DUP TYPE SAVE-EA5 CR .( Program size = ) BYTESUSED DECIMAL . .( bytes) And here is the source for the entire cross-assembler including Assembler directives. Spoiler CR .( CROSS ASSEMBLER for Camel99 Forth ) ( *NOTE: ) ( compare instruction has been changed to CMP, ) ( to remove name conflict with C, ) ( change A, and S, to ADD, SUB, ) NEEDS CASE FROM DSK1.CASE : XASM99 ; VARIABLE TDP \ "target dictionary point" \ set where the Cross-assembler puts its code : ORG ( addr -- ) TDP ! ; \ Target versions of HERE and ALLOT : THERE ( -- addr) TDP @ ; : TALLOT ( n -- ) TDP +! ; \ integer and byte "Target" compilers : T, ( n -- ) THERE ! 2 TALLOT ; : TC, ( c -- ) THERE C! 1 TALLOT ; \ =================================================== CR .( TI-99 Cross Assembler V 0.1 ...) CR .( Loading at) DP @ HEX U. DECIMAL 0 CONSTANT R0 1 CONSTANT R1 2 CONSTANT R2 3 CONSTANT R3 4 CONSTANT R4 5 CONSTANT R5 6 CONSTANT R6 7 CONSTANT R7 8 CONSTANT R8 9 CONSTANT R9 10 CONSTANT R10 11 CONSTANT R11 12 CONSTANT R12 13 CONSTANT R13 14 CONSTANT R14 15 CONSTANT R15 HEX : ADDRESS? ( n -- ?) DUP 1F > SWAP 30 < AND ; : GOP' OVER ADDRESS? \ address or register? IF + T, T, \ compile instruction & address ELSE + T, \ compile register THEN ; : GOP CREATE , DOES> @ GOP' ; 0440 GOP B, 0680 GOP BL, 0400 GOP BLWP, 04C0 GOP CLR, 0700 GOP SETO, 0540 GOP INV, 0500 GOP NEG, 0740 GOP ABS, 06C0 GOP SWPB, 0580 GOP INC, 05C0 GOP INCT, 0600 GOP DEC, 0640 GOP DECT, 0480 GOP X, : GROP CREATE , DOES> @ SWAP 40 * + GOP' ; 2000 GROP COC, 2400 GROP CZC, 2800 GROP XOR, 3800 GROP MPY, 3C00 GROP DIV, 2C00 GROP XOP, : GGOP CREATE , DOES> @ SWAP DUP ADDRESS? IF 40 * + SWAP >R GOP' R> T, ELSE 40 * + GOP' THEN ; HEX A000 GGOP ADD, B000 GGOP ADDB, 8000 GGOP CMP, 9000 GGOP CMPB, 6000 GGOP SUB, 7000 GGOP SUBB, E000 GGOP SOC, F000 GGOP SOCB, 4000 GGOP SZC, 5000 GGOP SZCB, C000 GGOP MOV, D000 GGOP MOVB, : 0OP CREATE , DOES> @ T, ; 0340 0OP IDLE, 0360 0OP RSET, 03C0 0OP CKOF, 03A0 0OP CKON, 03E0 0OP LREX, 0380 0OP RTWP, : ROP CREATE , DOES> @ + T, ; 02C0 ROP STST, 02A0 ROP STWP, : IOP CREATE , DOES> @ T, T, ; 02E0 IOP LWPI, 0300 IOP LIMI, : RIOP CREATE , DOES> @ ROT + T, T, ; 0220 RIOP AI, 0240 RIOP ANDI, 0280 RIOP CI, 0200 RIOP LI, 0260 RIOP ORI, : RCOP CREATE , DOES> @ SWAP 10 * + + T, ; 0A00 RCOP SLA, 0800 RCOP SRA, 0B00 RCOP SRC, 0900 RCOP SRL, CR .( jump instructions) : DOP CREATE , DOES> @ SWAP 00FF AND OR T, ; 1300 DOP JEQ, 1500 DOP JGT, 1B00 DOP JH, 1400 DOP JHE, 1A00 DOP JL, 1200 DOP JLE, 1100 DOP JLT, 1000 DOP JMP, 1700 DOP JNC, 1600 DOP JNE, 1900 DOP JNO, 1800 DOP JOC, 1C00 DOP JOP, 1D00 DOP SBO, 1E00 DOP SBZ, 1F00 DOP TB, : GCOP CREATE , DOES> @ SWAP 000F AND 40 * + GOP' ; 3000 GCOP LDCR, 3400 GCOP STCR, HEX \ Wycove assembler register syntax: : @@ 020 ; \ symbolic addressing : ** 010 + ; \ indirect addressing : *+ 030 + ; \ indirect addressing, auto-increment : () 20 + ; \ indexed addressing CR .( Jump tokens) \ for use with CJMP HEX 1 CONSTANT GTE \ GT OR EQUAL 2 CONSTANT HI \ JMP IF HI 3 CONSTANT NE \ NOT equal 4 CONSTANT LO \ jmp if low 5 CONSTANT LTE \ jmp if less than or equal 6 CONSTANT EQ \ jmp if equal 7 CONSTANT OC \ jmp on carry flag set 8 CONSTANT NC \ jmp if no carry flag set 9 CONSTANT OO \ jmp on overflow A CONSTANT HE \ jmp high or equal B CONSTANT LE \ jmp if low or equal C CONSTANT NP \ jmp if no parity ? D CONSTANT LT \ jmp if less than E CONSTANT GT \ jmp if greater than F CONSTANT NO \ jmp if no overflow 10 CONSTANT OP \ jmp if ODD parity : CJMP CASE LT OF 1101 T, 0 ENDOF GT OF 1501 T, 0 ENDOF NO OF 1901 T, 0 ENDOF OP OF 1C01 T, 0 ENDOF DUP 0< OVER 10 > ABORT" IF, BAD jump token" ENDCASE >< 1000 + T, ; CR .( Structured branching and looping ) : IF, ?EXEC ( only useable in immediate mode) CJMP THERE 2- 42 ; IMMEDIATE : ENDIF, ?EXEC 42 ?PAIRS THERE OVER - 2- 2/ SWAP CHAR+ C! ; IMMEDIATE : ELSE, ?EXEC 42 ?PAIRS 0 CJMP THERE 2- SWAP 42 POSTPONE ENDIF, 42 ; IMMEDIATE : BEGIN, ?EXEC THERE 41 ; IMMEDIATE : UNTIL, ?EXEC SWAP 41 ?PAIRS CJMP THERE - 2/ 00FF AND THERE 1- C! ; IMMEDIATE : AGAIN, ?EXEC 0 POSTPONE UNTIL, ; IMMEDIATE : REPEAT, ?EXEC >R >R POSTPONE AGAIN, R> R> 2- POSTPONE ENDIF, ; IMMEDIATE : WHILE, ?EXEC POSTPONE IF, CELL+ ; IMMEDIATE CR .( Pseudo instructions) : RT, ( -- ) R11 ** B, ; : NOP, ( -- ) 0 JMP, ; : NEXT, ( -- ) R10 ** B, ; \ 045A T, ; \ CAMEL99 NEXT: B *R10 CR CR .( Cross Assembler loaded) HEX Edit: Forgot this file which is the directives and stuff for saving the EA5 file. Spoiler CR .( Native code cross compiler B Fox May 2020) \ creates a binary program E/A 5 format NEEDS DUMP FROM DSK1.TOOLS NEEDS THERE FROM DSK1.XASM99 NEEDS MARKER FROM DSK1.MARKER NEEDS MALLOC FROM DSK1.MALLOC NEEDS R/W FROM DSK1.ANSFILES NEEDS SAVE-FILE FROM DSK1.LOADSAVE MARKER CROSS99 HEX 2050 H ! \ reset Forth HEAP in low ram 1000 MALLOC CONSTANT HEADORG HEADORG 3 CELLS + CONSTANT CODEORG : NEW. ( -- ) HEADORG TDP ! THERE 2000 0FF FILL \ erase target memory \ create dummy ti-files header in target memory space 0000 T, \ multi-file flag 0000 T, \ program size 0000 T, \ load address \ *all programs shall have a branch and address as 1st instruction 0460 T, \ branch instruction 0000 T, ; \ address we branch to : ]HEADER ( n ndx -- addr[n]) CELLS HEADORG + ; \ header as cell array : MULTI! ( ? -- ) 0 ]HEADER ! ; : SIZEFIELD ( -- addr) 1 ]HEADER ; \ size field in header : SIZE@ ( -- n ) SIZEFIELD @ DUP 0= ABORT" Program size not set" ; : LOADFIELD ( addr -- ) 2 ]HEADER ; : LOAD@ ( addr -- ) LOADFIELD @ DUP 0= ABORT" LOAD address not set" ; \ cross compiler extensions VARIABLE AORG HEX \ set cross-compiler org variable and store in file header : ORIGIN. ( addr -- ) DUP AORG ! LOADFIELD ! ; : ORG@ ( -- addr ) AORG @ DUP 0= ABORT" Program ORIGIN not set" ; : BOOTFIELD ( -- addr) 4 ]HEADER ; \ boot field in the header : BYTESUSED ( -- n ) TDP @ HEADORG - ; HEX \ save program to file : >VDPBUFF ( addr -- ) 1000 SIZE@ VWRITE ; : SAVE-EA5 ( file$ len -- ) HEADORG >VDPBUFF 1000 SIZE@ 13 SAVE-FILE ; CR .( Forth VM support) DECIMAL 4 CONSTANT TOS : (TOS) TOS () ; : *TOS TOS ** ; : *TOS+ TOS *+ ; 6 CONSTANT SP : (SP) SP () ; : *SP SP ** ; : *SP+ SP *+ ; \ PUSH & POP to data stack : PUSH, ( src -- ) SP DECT, *SP MOV, ; \ 10+18 = 28 cycles : POP, ( dst -- ) *SP+ SWAP MOV, ; \ 22 cycles 7 CONSTANT RP \ R11 is also 9900 LINK register : (RP) RP () ; : *RP RP ** ; : *RP+ RP *+ ; \ PUSH & POP to return ttack : RPUSH, ( src -- ) RP DECT, *RP MOV, ; : RPOP, ( dst -- ) *RP+ SWAP MOV, ; 8 CONSTANT W : (W) W () ; : *W W ** ; : *W+ W *+ ; : *R10 R10 ** ; : *R11 R11 ** ; : RELOCATE ( Taddr -- addr') CODEORG - LOAD@ + ; \ create a label in HOST Forth \ Returns a relocated TARGET address when executed : L: CREATE THERE , DOES> @ RELOCATE ; \ nestable sub-routines ** MUST END WITH RET, ** : SUB: ( -- ) CREATE !CSP THERE , R11 RPUSH, DOES> @ RELOCATE ; : RET, ( -- ) R11 RPOP, RT, ; \ nestable return psuedo-instruction : ;SUB ( -- ) ?CSP ; : EVEN. TDP @ ALIGNED TDP ! ; : TEXT, ( c-addr u -- ) THERE OVER 1+ TALLOT PLACE EVEN. ; : PROG: ( -- <label> ) CREATE !CSP THERE DUP , \ DUP & record code location RELOCATE BOOTFIELD ! \ also put it in program header DOES> @ RELOCATE ; \ Runtime: return relocated address : END. ?CSP BYTESUSED DUP 2000 > ABORT" Prog > 8K" SIZEFIELD ! ; 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.