1 |
2 |
sinclairrf |
<!-- Copyright 2012, Sinclair R.F., Inc. -->
|
2 |
|
|
<html>
|
3 |
|
|
<title>
|
4 |
|
|
SSBCC -- Small Stack-Based Computer Compiler
|
5 |
|
|
</title>
|
6 |
|
|
<body>
|
7 |
|
|
This document describes the purpose and design methodology of the Small
|
8 |
|
|
Stack-Based Computer Compiler (SSBCC).<br/><br/>
|
9 |
|
|
The system is designed to run a Forth-like assembly.<br/><br/>
|
10 |
|
|
<h1>Introduction</h1>
|
11 |
|
|
The purpose of the SSBCC is to generate small microcontrollers for use in
|
12 |
|
|
FPGAs. This computer compiler is designed to generate FPGA-vendor
|
13 |
|
|
independent systems in either Verilog or VHDL. The resulting micro
|
14 |
|
|
controller is described by a single HDL file containing the processor core,
|
15 |
|
|
the program, data stack, return stack, and variable memory.<br/><br/>
|
16 |
|
|
The archive consists of the computer compiler, micro computer cores and
|
17 |
|
|
assemblers, and libraries.<br/><br/>
|
18 |
|
|
<h1>Processor Architecture</h1>
|
19 |
|
|
TODO -- RFS: describe the general architecture<br/><br/>
|
20 |
|
|
<h1>8-bit Processor Example</h1>
|
21 |
|
|
This section demonstrates how to generate a 8-bit processor with 9-bit wide
|
22 |
|
|
instructions. The 8-bit data width was chosen because it is characteristic
|
23 |
|
|
of embedded systems controlling other processes and generating ascii output.
|
24 |
|
|
The 9-bit data width was chosen because the FPGAs produced by the three
|
25 |
|
|
major FPGA vendors produce memories with 8-bit data widths.<br/><br/>
|
26 |
|
|
The processor is described by a regular text file with the following contents:
|
27 |
|
|
<ul>
|
28 |
|
|
<li>A description of the program memory, the stack memory, the return
|
29 |
|
|
stack memory, the variable memory, and the I/O ports.<br/><br/>
|
30 |
|
|
This part of the processor may be FPGA-dependent. For example, Altera's
|
31 |
|
|
Cyclone III FPGAs do not have distributed memory, so short memories in
|
32 |
|
|
those FPGAs are either extremely inefficient or are converted into an
|
33 |
|
|
M9K, in which case you ought to state that an M9K is going to be used
|
34 |
|
|
anyway. As another example, Xilinx' Spartan 6 has 6-input
|
35 |
|
|
LUTs that can be used as distributed memory, so a 128-word program can
|
36 |
|
|
be efficiently stored in 18 LUTs instead of occupying a precious
|
37 |
|
|
Block RAM. Additionally, if the program is between 129 and 192 words,
|
38 |
|
|
i.e., it would fit in 3 64x9 LUTs, then the program ROM can be
|
39 |
|
|
described as such, saving 9 LUT in this case.<br/><br/>
|
40 |
|
|
</li>
|
41 |
|
|
<li>An instruction to load the processor core and its intrinsics.<br/><br/>
|
42 |
|
|
This instruction loads the HDL instantiating processor core, i.e., its
|
43 |
|
|
opcode interpretation, ALU, stack manipulation, etc.<br/><br/>
|
44 |
|
|
This instruction also loads the list of Forth operations supported
|
45 |
|
|
natively by the processor core and the instructions on how to construct
|
46 |
|
|
the machine opcodes from those instructions.<br/><br/>
|
47 |
|
|
For example, the '<tt>+</tt>' instruction is translated directly to the
|
48 |
|
|
opcode <tt>0_XXXX_XXXX</tt>.<br/><br/>
|
49 |
|
|
TODO -- RFS: fill in the "X"s above.<br/><br/>
|
50 |
|
|
As another example, the 9-bit opcodes for this particular machine use
|
51 |
|
|
a leading bit of '<tt>0</tt>' to indicate that an 8-bit value is to be
|
52 |
|
|
pushed onto the stack. An 8-bit opcode cannot put the full range
|
53 |
|
|
of 8-bit values onto the stack in a single instruction. Instead, a
|
54 |
|
|
7-bit, positive value is pushed onto the stack and then, if this is
|
55 |
|
|
not the desired value, an "<tt>invert</tt>" instruction immediately
|
56 |
|
|
follows and is used to invert the leading bit of the of the top of the
|
57 |
|
|
stack.<br/><br/>
|
58 |
|
|
</li>
|
59 |
|
|
<li>An optional instruction to load definitions of the remaining Forth
|
60 |
|
|
instructions.<br/><br/>
|
61 |
|
|
For example, a processor core could implement the Forth instructions
|
62 |
|
|
"<tt>0<</tt>" and "<tt>0=</tt>" and none of the remaining
|
63 |
|
|
comparison operators "<tt>0<=</tt>", "<tt>0></tt>",
|
64 |
|
|
"<tt>0>=</tt>", and "<tt>0<></tt>". The optional instructions
|
65 |
|
|
would include statements like:<br/><br/>
|
66 |
|
|
<tt> : 0
|
67 |
|
|
</li>
|
68 |
|
|
</ul>
|
69 |
|
|
<h1>Processor Description Syntax</h1>
|
70 |
|
|
<h2>Memory Description</h2>
|
71 |
|
|
<h2>
|
72 |
|
|
<h1>Core Description Syntax</h1>
|
73 |
|
|
<h2>Opcode List</h2>
|
74 |
|
|
This section lists the opcodes and describes how the compiler is to
|
75 |
|
|
implement them.<br/><br/>
|
76 |
|
|
TODO -- RFS: Determine this syntax<br/><br/>
|
77 |
|
|
<h2>HDL Section(s)</h2>
|
78 |
|
|
Each of these sections lists the processor core implementation in the
|
79 |
|
|
specified language.<br/><br/>
|
80 |
|
|
The languages currently supported by the compiler are Verilog and
|
81 |
|
|
VHDL.<br/><br/>
|
82 |
|
|
<b>Syntax:</b> <tt>HDL {Verilog|VHDL} ... ENDHDL</tt><br/><br/>
|
83 |
|
|
<b>Example:</b><br/>
|
84 |
|
|
<pre>HDL Verilog
|
85 |
|
|
always @ (posedge i_clk) begin
|
86 |
|
|
s_stack_addr <= s_stack_addr;
|
87 |
|
|
if (s_opcode[C_NBITS_OPCODE-1] = 1'b0) begin
|
88 |
|
|
s_stack[s_stack_addr] <= s_opcode[C_NBITS_OPCODE-2:0];
|
89 |
|
|
s_stack_addr <= s_stack_addr + 1;
|
90 |
|
|
else
|
91 |
|
|
end
|
92 |
|
|
end
|
93 |
|
|
ENDHDL
|
94 |
|
|
</pre><br/>
|
95 |
|
|
</body>
|
96 |
|
|
</html>
|