--- gforth/asm/generic.fs 2007/12/31 18:40:25 1.6 +++ gforth/asm/generic.fs 2010/12/31 18:09:02 1.11 @@ -1,6 +1,6 @@ \ generic.fs implements generic assembler definitions 13aug97jaw -\ Copyright (C) 1998,2000,2003 Free Software Foundation, Inc. +\ Copyright (C) 1998,2000,2003,2007,2010 Free Software Foundation, Inc. \ This file is part of Gforth. @@ -24,11 +24,12 @@ \ \ 13aug97jaw-14aug97 Initial Version -> V0.5 \ ToDo: operand count checking -\ +\ +\ 24apr10dk Added documentation \ general definitions -: clearstack depth 0 ?DO drop LOOP ; +: clearstack ( k*x -- ) depth 0 ?DO drop LOOP ; \ redefinitions to avoid conflicts @@ -56,30 +57,41 @@ Create modes modes# cells allot \ Modes Variable Start-Depth Variable Mode# -: reset +: reset ( -- ) + \G End an opcode / star a new opcode. modes modes# cells erase 1 Mode# ! depth Start-Depth ! ; -: Mode! ( n -- ) +: Mode! ( x -- ) + \G Set current operand's mode to X Modes Mode# @ cells + ! ; -: +Mode! ( n -- ) +: +Mode! ( x -- ) + \G Logically OR X to current operand's mode Modes Mode# @ cells + tuck @ or swap ! ; -: 0Mode! ( n -- ) +: 0Mode! ( x -- ) + \G Set mode of operand #0. Use operand #0 for an (optional) operands that + \G can be placed anywhere, e.g. condition codes or operand lengths .B .W .L + \G etc. Modes ! ; -: , +: , ( -- ) + \G Advance to next operand 1 Mode# +! ; -: Mode +: Mode ( x "name" -- ) + \G Define a new mode that logically ors X to current mode when executed Create dic, DOES> @ +Mode! ; -: 0Mode +: 0Mode ( x "name" -- ) + \G Define a new mode that sets operand #0 when executed Create dic, DOES> @ 0Mode! ; -: Reg +: Reg ( xt x "name" -- ) + \G Define a parametrized mode, that executes mode XT, then puts X onto the + \G stack Create dic, dic, DOES> dup perform cell+ @ ; \ --------- Instruction Latch @@ -88,11 +100,14 @@ Create I-Latch 10 chars allot Variable I-Len : opc! ( adr len -- ) + \G Logically OR string of bytes into instruction latch dup I-Len @ max I-Len ! - I-Latch -rot bounds DO I c@ over c@ or over c! char+ LOOP drop ; + I-Latch -rot bounds ?DO I c@ over c@ or over c! char+ LOOP drop ; -: I-Init 0 I-Len ! I-Latch 10 erase ; -: I-Flush I-Latch I-len @ bounds DO i c@ X c, LOOP reset ; +: I-Init ( -- ) 0 I-Len ! I-Latch 10 erase ; +: I-Flush ( -- ) + \G Append contents of instruction latch to dictionary + I-Latch I-len @ bounds DO i c@ X c, LOOP reset ; : (g!) ( val addr n -1/1 -- ) dup 0< IF rot 2 pick + 1- -rot THEN @@ -108,8 +123,12 @@ Variable I-Len Variable ByteDirection \ -1 = big endian; 1 = little endian -: g@ ByteDirection @ (g@) ; -: g! ByteDirection @ (g!) ; +: g@ ( addr n -- val ) + \G read n-byte integer from addr using current endianess + ByteDirection @ (g@) ; +: g! ( val addr n -- ) + \G write n-byte integer to addr using current endianess + ByteDirection @ (g!) ; \ ---------------- Tables @@ -125,7 +144,9 @@ Variable ByteDirection \ -1 = big endian Describ 4 cells + perform \ to flush the instruction ; -: 1st-mc ( addr -- flag ) +: 1st-mc ( addr -- flag ) + \G mnemonic check? check for matching operands. if matching, execute code + \G to encode mode and operands and return true, else return false dup >modes modes Mode-Compare IF Table-Exec true @@ -133,25 +154,39 @@ Variable ByteDirection \ -1 = big endian THEN ; : 1st-always ( addr -- flag ) + \G Undconditionally encode operands and/or instruction used for instructions + \G that do not have any operands. Return true i.e. make the assembler stop + \G looking for more instruction variants Table-Exec true ; : 1st-thru + \G Unconditionally encode, but return false to make assembler execute next + \G table rows also. dup Table-Exec false ; -: 2nd-opc! +: 2nd-opc! ( -- ) + \G encode opcode by ORing data column of current instruction row into + \G instruction latch Describ >data count opc! ; -: opcode, +: opcode, ( " ..." -- ) + \G Append a counted string to dictionary, reading in every character as + \G space-terminated numbers form the parser until the end of line is + \G reached. here 0 c, BEGIN bl word count dup WHILE s>number drop c, REPEAT 2drop here over - 1- swap c! ; -: modes, +: modes, ( -- ) + \G append contents of MODES to dictionary modes# 0 DO I cells modes + @ dic, LOOP ; 0 Value Table-Link -: Table +: Table ( "name" -- ) + \G create table that lists allowed operand/mode combinations for opcode + \G "name". Note that during assembling, table will be scanned in reverse + \G order! Reset Create here to Table-Link 0 dic, DOES> I-Init @@ -161,22 +196,30 @@ Variable ByteDirection \ -1 = big endian ?EXIT REPEAT -1 ABORT" no valid mode!" ; - -: Follows + +: Follows ( "name" -- ) + \G Link current instruction's table to execute all rows of table "name" + \G (after executing all rows already defined). Do not add any more rows to + \G current table, after executing Follows. Else you're going to modify + \G "name"'s table! ' >body @ Table-Link @ ! ; -: opc, +: opc, ( k*x " ..." -- ) + \G Append current modes and opcode given byte-wise on current input line to + \G dictionary. Clear forth stack to remove any data provided by the + \G otherwise unused operands that wer used to set up the modes array. modes, opcode, clearstack reset ; -: (Opc() -\ Opcode with Operands +: (Opc() ( k*x xt " ..." -- ) + \G Fill table row for opcode with Operands. XT will be executed by the + \G assembler for encoding the operands using data from the stack. ['] 1st-mc dic, ['] 2nd-opc! dic, dic, ['] I-Flush dic, opc, ; -: (Opc) +: (Opc) ( k*x xt " ..." -- ) \ Opcode without Operands ['] 1st-always dic, ['] 2nd-opc! dic, @@ -184,18 +227,34 @@ Variable ByteDirection \ -1 = big endian ['] I-Flush dic, opc, ; -: Opc( -\ Opcode with Operands +: Opc( ( k*x xt " ..." -- ) + \G Append a new table row for an opcode with Operands. Use your assembler + \G operands to fill the MODES array with data showing how the opcode is + \G used. Only the types of operands are recorded, any operand parameters + \G passed on the stack are dropped. The opcode's instruction code is read + \G as 8-bit numbers from the current input line and stored as counted string + \G in the table's opcode column + \G + \G When assembling an instruction, the assembler checks for matching + \G operands. If this row matches, first XT is called to consume operands + \G parameters from the stack and encode them into the instruction latch. + \G Then the opcode column is ORed to the instruction latch and the assembler + \G quits assembly of the current instruction. Table-Link linked (Opc() ; -: Opc -\ Opcode without Operands +: Opc ( k*x " ..." -- ) + \G Append a new table row for an opcode without operand parameters. + \G + \G When assembling an instruction, and the assembler reaches this row, it + \G will assume the opcode is fully assembled and quits assembly of the + \G instruction, after endcoding the opcode. Table-Link linked (Opc) ; -: Opc+ -\ Additional Opcode +: Opc+ ( k*x " ..." -- ) + \G Append a new table row that encodes part of an opcode, but falls through + \G to following lines. Table-Link linked ['] 1st-thru dic, ['] 2nd-opc! dic, @@ -203,8 +262,8 @@ Variable ByteDirection \ -1 = big endian ['] Noop dic, opc, ; -: Opc(+ -\ Additional Opcode with Operands +: Opc(+ ( k*x xt " ..." -- ) + \G Like OPC+ but for a table row that has operands Table-Link linked ['] 1st-thru dic, ['] 2nd-opc! dic, @@ -214,10 +273,23 @@ Variable ByteDirection \ -1 = big endian : End-Table ; -: alone +: alone ( k*x " ..." -- ) + \G Create a single-row instruction table for an instruction without operands. Create 0 dic, ( Dummy Linkfield ) (opc) DOES> dup cell+ perform 0= ABORT" must work always!" ; - -: alone( + +: alone( ( k*x xt " ..." -- ) + \G Create a single-row instruction table for an instruction with operands. Create 0 dic, ( Dummy Linkfield ) (opc() DOES> dup cell+ perform 0= ABORT" must work always!" ; + + +\ Configure Emacs forth-mode to keep this file's formatting +0 [IF] + Local Variables: + forth-indent-level: 2 + forth-local-indent-words: + (((";") (0 . -2) (0 . -2)) + (("does>") (0 . 0) (0 . 0))) + End: +[THEN]