1 # NasmJF - a NASM port of JONESFORTH
     
2 
     3 This is a fully-functioning Forth interpreter faithfully ported from the original
     
4 by Richard W.M. Jones:
     
5 
     6 <a href="https://rwmj.wordpress.com/2010/08/07/jonesforth-git-repository/">https://rwmj.wordpress.com/2010/08/07/jonesforth-git-repository/"></a>
     
7 
     8 You can see the full original source in the `jonesforth/` directory in this repo.
     
9 
    10 Assemble and run `nasmjf` like so:
    
11 
    12     $ ./build.sh
    
13     $ ./nasmjf
    
14     JONESFORTH VERSION 1
    
15     20643 CELLS REMAINING
    
16     OK
    
17     : hello ." Hello world!" CR ;
    
18     hello
    
19     Hello world!
    
20     BYE
    
21     $
    
22 
    23 This repo is a port from the original GNU Assembler (GAS) implementation to
    
24 the Netwide Assembler (NASM). The biggest difference between the two assemblers
    
25 is AT&T-style GAS syntax vs. Intel-style NASM syntax. But I have made a couple
    
26 changes. The biggest one is that `nasmjf` loads the `jonesforth.f` source file
    
27 (containing the second half of the interpreter written in Forth) upon startup.
    
28 
    29 See "Loads Jones's FORTH source on start" below.
    
30 
    31 
    32 ## Current status
    
33 
    34 It's done! It passes the original JONESFORTH tests. See
    
35 `test.sh` in the root of this repo.
    
36 
    37 
    38 ## Why does this exist?
    
39 
    40 Check out the `devlog/log*.txt` text files. They're my rambling learning-in-public and
    
41 thinking "out loud" way of describing what I'm up to. The latest log will probably
    
42 give an idea of what I'm currently doing or what I've most recently completed.
    
43 
    44 I also wrote an article about my delightful process with this project:
    
45 <a href="http://ratfactor.com/assembly-nights">http://ratfactor.com/assembly-nights</a>
    
46 
    47 After completing this project, here's my conclusions:
    
48 <a href="http://ratfactor.com/nasmjf/done">http://ratfactor.com/nasmjf/done</a>
    
49 
    50 
    51 ## Compiling and running
    
52 
    53 You'll need the NASM assembler, a linker such as `ld`, and a Linux computer
    
54 (JF relies on raw syscalls). And a sense of adventure.
    
55 
    56 To build the `nasmjf` executabe, run `build.sh`. (Or see what it does.)
    
57 
    58 Manually assemble and link like so:
    
59 
    60     $ nasm -f elf32 -g -o nasmjf.o nasmjf.asm
    
61     $ ld nasmjf.o -o nasmjf
    
62     $ rm nasmjf.o
    
63 
    64 Run by calling the executable you just compiled:
    
65 
    66 
    67     $ ./nasmjf
    
68     'A' EMIT
    
69     A
    
70 
    71 
    72 If you're going to use JONESFORTH for anything longer than a simple line or
    
73 two, I _highly_ recommend wrapping it in `readline` with the excellent `rlwrap`
    
74 (https://github.com/hanslub42/rlwrap) like so:
    
75 
    76     $ rlwrap ./nasmjf
    
77 
    78 Then you'll have line editing, history (up arrow lets you re-enter and edit the
    
79 last line), and even persistent history between Forth sessions!
    
80 
    81 ## Loads Jones's FORTH source on start
    
82 
    83 The implementation of JONESFORTH is in two parts: an assembly language
    
84 "bootstrap" and additional essential word definitions written in FORTH.
    
85 
    86 This NASM contains a hard-coded path to the `jonesforth.f` FORTH source file
    
87 and reads it automatically when the interpreter starts. This is to make
    
88 starting and debugging the system easier and more convenient.
    
89 
    90 If you wish to disable or simply examine this change, search for lines with
    
91 comments containing the string `LOADJF`. You can comment out most of these
    
92 lines. A few will need to remain. Figuring out which is "left as an exercise
    
93 for the reader", as they say.
    
94 
    95 
    96 ## GNU Debugger
    
97 
    98 I've made heavy use of the GNU Debugger to fix mistakes, understand what
    
99 my program is doing, and in these early stages, it's nearly the only way
   
100 to tell what's happening in the program at all.
   
101 
   102 I'm assembling with DWARF2 debugging info. See the `r` script for params.
   
103 
   104 See `gdb.script` for current defaults I'm using.
   
105 
   106 Show stuff:
   
107 
   108     maint info sections     # memory sections
   
109     info addr word_buffer   # address of symbol (label/var/func)
   
110     info sym 0x804c608      # reverse of info addr, symbol at addr
   
111     info var buff           # list (with addr!) of symbol names w/ "buff"
   
112     info var                # list ALL symbols
   
113     info var var_           # list all symbols that start with "var_"
   
114 
   115 Print values (register,  label, literal numbers (handy as base converter)
   
116 
   117     p 0x50                  # prints 80
   
118     p/x 80                  # prints 0x50
   
119     p/x (int)some_label     # show 4 bytes (32b) of data at some_label in hex
   
120     p/x &some_label         # ADDRESS of some_label
   
121 
   122 Print value at memory location
   
123 
   124     x/x &some_label         # show a byte of data at some_label in hex
   
125     x/s &some_label         # show a string at some_label
   
126     x/4x &some_label        # show four consecutive bytes
   
127 
   128 Set temporary break and jump to location (by label)
   
129 
   130     tbreak docol
   
131     jump docol
   
132 
   133 Create GDB commands
   
134 
   135     define foo
   
136         p $arg0
   
137         p $arg1
   
138     end
   
139 
   140 
   141 ## GNU Screen
   
142 
   143 See the file `screenrc` in this repo to see the current convenience setup.
   
144 In short, I've got a GDB session and Vim session open in separate windows
   
145 so I can quickly toggle between them. Anything outside of those two
   
146 applications is best done in a new window to keep from accidentally closing
   
147 one of the two main windows.
   
148 
   149 * `C-j C-j` toggle between main windows
   
150 * `C-j c` create a new window with a shell
   
151 * `C-j H` start (or stop) logging window (not actually what I want)
   
152 * `C-j h` save hardcopy of scrollback buffer (actually what I want)
   
153 * `C-j ?` help (show other shortcuts)
   
154 
   155 I'm using the hardcopy feature to help me record running each milestone of
   
156 progress in GDB sessions to test and document (and celebrate!) the work.
   
157 
   158 An alias called `jf` starts my two-windowe session like so:
   
159 
   160     alias jf='screen -c nasmjf/screenrc'
   
161 
   162 
   163 ## .vimrc
   
164 
   165 My whole setup on this machine is dedicated to this project.
   
166 Here's the entirety of my current `.vimrc`:
   
167 
   168     set tabstop=8 softtabstop=0 expandtab shiftwidth=4 smarttab
   
169     colorscheme elflord
   
170     " simple buffer switching mappings for a handful of files
   
171     nnoremap <right> :bn<cr>
   
172     nnoremap <left> :bp<cr>
   
173     " my eeepc chugs when trying to apply highlighting to this large asm file
   
174     au BufRead jonesforth.S set syntax=text nowrap
   
175     au BufRead nasmjf.listing set nowrap
   
176     let mapleader = ","
   
177 
   178 
   179 ## PUBLIC DOMAIN
   
180 
   181 Because Richard Jones released his work as public domain, it's only right
   
182 that I should release my port also as public domain. So here's the license:
   
183 
   184 I, the copyright holder of this work, hereby release it into the public domain.
   
185 This applies worldwide.
   
186 
   187 In case this is not legally possible, I grant any entity the right to use this
   
188 work for any purpose, without any conditions, unless such conditions are
   
189 required by law.