OpenCores
URL https://opencores.org/ocsvn/ssbcc/ssbcc/trunk

Subversion Repositories ssbcc

[/] [ssbcc/] [trunk/] [README] - Diff between revs 7 and 9

Go to most recent revision | Only display areas with differences | Details | Blame | View Log

Rev 7 Rev 9
SSBCC.9x8 is a free Small Stack-Based Computer Compiler with a 9-bit opcode,
SSBCC.9x8 is a free Small Stack-Based Computer Compiler with a 9-bit opcode,
8-bit data core designed to facilitate FPGA HDL development.
8-bit data core designed to facilitate FPGA HDL development.
The primary design criteria are:
The primary design criteria are:
- high speed (to avoid timing issues)
- high speed (to avoid timing issues)
- low fabric utilization
- low fabric utilization
- vendor independent
- vendor independent
- development tools available for all operating systems
- development tools available for all operating systems
It has been used in Spartan-3A, Spartan-6, Virtex-6, and Artix-7 FPGAs and has
It has been used in Spartan-3A, Spartan-6, Virtex-6, and Artix-7 FPGAs and has
been built for Altera, Lattice, and other Xilinx devices.  It is faster and
been built for Altera, Lattice, and other Xilinx devices.  It is faster and
usually smaller than vendor provided processors.
usually smaller than vendor provided processors.
The compiler takes an architecture file that describes the micro controller
The compiler takes an architecture file that describes the micro controller
memory spaces, inputs and outputs, and peripherals and which specifies the HDL
memory spaces, inputs and outputs, and peripherals and which specifies the HDL
language and source assembly.  It generates a single HDL module implementing
language and source assembly.  It generates a single HDL module implementing
the entire micro controller.  No user-written HDL is required to instantiate
the entire micro controller.  No user-written HDL is required to instantiate
I/Os, program memory, etc.
I/Os, program memory, etc.
The features are:
The features are:
- high speed, low fabric utilization
- high speed, low fabric utilization
- vendor-independent Verilog output with a VHDL package file
- vendor-independent Verilog output with a VHDL package file
- simple Forth-like assembly language (43 instructions)
- simple Forth-like assembly language (43 instructions)
- single cycle instruction execution
- single cycle instruction execution
- automatic generation of I/O ports
- automatic generation of I/O ports
- configurable instruction, data stack, return stack, and memory utilization
- configurable instruction, data stack, return stack, and memory utilization
- extensible set of peripherals (I2C busses, UARTs, AXI4-Lite busses, etc.)
- extensible set of peripherals (I2C busses, UARTs, AXI4-Lite busses, etc.)
- extensible set of macros
- extensible set of macros
- memory initialization file to facilitate code development without rebuilds
- memory initialization file to facilitate code development without rebuilds
- simulation diagnostics to facilitate identifying code errors
- simulation diagnostics to facilitate identifying code errors
- conditionally included I/Os and peripherals, functions, and assembly code
- conditionally included I/Os and peripherals, functions, and assembly code
SSBCC has been used for the following projects:
SSBCC has been used for the following projects:
- operate a media translator from a parallel camera interface to an OMAP GPMC
- operate a media translator from a parallel camera interface to an OMAP GPMC
  interface, detect and report bus errors and hardware errors, and act as an
  interface, detect and report bus errors and hardware errors, and act as an
  SPI slave to the OMAP
  SPI slave to the OMAP
- operate two UART interfaces and multiple PWM controlled 2-lead bi-color LEDs
- operate two UART interfaces and multiple PWM controlled 2-lead bi-color LEDs
- operate and monitor the Artix-7 fabric in a Zynq system using AXI4-Lite
- operate and monitor the Artix-7 fabric in a Zynq system using AXI4-Lite
  master and slave buses, I2C buses for timing-critical voltage measurements
  master and slave buses, I2C buses for timing-critical voltage measurements
The only external tool required is Python 2.7.
The only external tool required is Python 2.7.
DESCRIPTION
DESCRIPTION
================================================================================
================================================================================
The computer compiler uses an architectural description of the processor stating
The computer compiler uses an architectural description of the processor stating
the sizes of the instruction memory, data stack, and return stack; the input and
the sizes of the instruction memory, data stack, and return stack; the input and
output ports; RAM and ROM types and sizes; and peripherals.
output ports; RAM and ROM types and sizes; and peripherals.
 
 
The instructions are all single-cycle.  The instructions include
The instructions are all single-cycle.  The instructions are:
- 4 arithmetic instructions:  addition, subtraction, increment, and decrement
- 4 arithmetic instructions:  addition, subtraction, increment, and decrement
- 2 carry bit instructions:  +c and -c for addition and subtraction respectively
- 2 carry bit instructions:  +c and -c for addition and subtraction respectively
- 3 bit-wise logical instructions:  and, or, and exclusive or
- 3 bit-wise logical instructions:  and, or, and exclusive or
- 7 shift and rotation instructions: <<0, <<1, 0>>, 1>>, <>msb, and >>lsb
- 7 shift and rotation instructions: <<0, <<1, 0>>, 1>>, <>, and lsb>>
- 4 logical instructions:  0=, 0<>, -1=, -1<>
- 4 logical instructions:  0=, 0<>, -1=, -1<>
- 6 Forth-like data stack instructions:  drop, dup, nip, over, push, swap
- 6 Forth-like data stack instructions:  drop, dup, nip, over, push, swap
- 3 Forth-like return stack instructions:  >r, r>, r@
- 3 Forth-like return stack instructions:  >r, r>, r@
- 2 input and output
- 2 I/O: inport, outport
- 6 memory read and write with optional address post increment and post decrement
- 6 memory read and write with optional address post increment and post decrement
- 2 jump and conditional jump
- 2 jump and conditional jump
- 2 call and conditional call
- 2 call and conditional call
- 1 function return
- 1 function return
- 1 nop
- 1 nop
The 9x8 address space is up to 8K.  This is achieved by pushing the 8 lsb of the
The 9x8 address space is up to 8K.  This is achieved by pushing the 8 lsb of the
target address onto the data stack immediately before the jump or call
target address onto the data stack immediately before the jump or call
instruction and by encoding the 5 msb of the address within the jump or call
instruction and by encoding the 5 msb of the address within the jump or call
instruction.  The instruction immediately following a jump, call, or return is
instruction.  The instruction immediately following a jump, call, or return is
executed before the instruction sequence at the destination address is executed
executed before the instruction sequence at the destination address is executed
(this is illustrated later).
(this is illustrated later).
Up to four banks of memory, either RAM or ROM, are available.  Each of these can
Up to four banks of memory, either RAM or ROM, are available.  Each of these can
be up to 256 bytes long, providing a total of up to 1 kB of memory.
be up to 256 bytes long, providing a total of up to 1 kB of memory.
The assembly language is Forth-like.  Built-in macros are used to encode the
The assembly language is Forth-like.  Built-in macros are used to encode the
jump and call instructions and to encode the 2-bit memory bank index in memory
jump and call instructions and to encode the 2-bit memory bank index in memory
store and fetch instructions.
store and fetch instructions.
The computer compiler and assembler are written in Python 2.7.  Peripherals are
The computer compiler and assembler are written in Python 2.7.  Peripherals are
implemented by Python modules which generate the I/O ports and the peripheral
implemented by Python modules which generate the I/O ports and the peripheral
HDL.
HDL.
The computer compiler is documented in the doc directory.  The 9x8 core is
The computer compiler is documented in the doc directory.  The 9x8 core is
documented in the core/9x8/doc directory.  Several examples are provided.
documented in the core/9x8/doc directory.  Several examples are provided.
The computer compiler and assembler are fully functional and there are no known
The computer compiler and assembler are fully functional and there are no known
bugs.
bugs.
SPEED AND RESOURCE UTILIZATION
SPEED AND RESOURCE UTILIZATION
================================================================================
================================================================================
 
 
These device speed and resource utilization results are copied from the build
These device speed and resource utilization results are copied from the build
tests.  The full results are listed in the core/9x8/build directories.  The
tests.  The full results are listed in the core/9x8/build directories.  The
tests use a minimal processor implementation (clock, reset, and one output).
tests use a minimal processor implementation (clock, reset, and one output).
Device-specific scripts state how these performance numbers were obtained.
Device-specific scripts state how these performance numbers were obtained.
VENDOR          DEVICE          BEST SPEED      SMALLEST RESOURCE UTILIZATION
VENDOR          DEVICE          BEST SPEED      SMALLEST RESOURCE UTILIZATION
------          ------          ----------      -------------------------------
------          ------          ----------      -------------------------------
Altera          Cyclone-III     190.6 MHz       282 LEs           (preliminary)
Altera          Cyclone-III     190.6 MHz       282 LEs           (preliminary)
Altera          Cyclone-IV      192.1 MHz       281 LEs           (preliminary)
Altera          Cyclone-IV      192.1 MHz       281 LEs           (preliminary)
Altera          Stratix-V       372.9 MHz       198 ALUTs         (preliminary)
Altera          Stratix-V       372.9 MHz       198 ALUTs         (preliminary)
Lattice         LCMXO2-640ZE-3   98.4 MHz       206 LUTs          (preliminary)
Lattice         LCMXO2-640ZE-3   98.4 MHz       206 LUTs          (preliminary)
Lattice         LFE2-6E-7       157.9 MHz       203 LUTs          (preliminary)
Lattice         LFE2-6E-7       157.9 MHz       203 LUTs          (preliminary)
Xilinx          Artix-7         TBD             163 slice LUTs (48 slices)
Xilinx          Artix-7         TBD             163 slice LUTs (48 slices)
Xilinx          Kintex-7        TBD             158 slice LUTs (44 slices)
Xilinx          Kintex-7        TBD             158 slice LUTs (44 slices)
Xilinx          Spartan-3A      149.4 MHz       232 4-input LUTs (129 slices)
Xilinx          Spartan-3A      149.4 MHz       232 4-input LUTs (129 slices)
Xilinx          Spartan-6       193.7 MHz       124 Slice LUTs (34 slices)
Xilinx          Spartan-6       193.7 MHz       124 Slice LUTs (34 slices)
Xilinx          Virtex-6        275.7 MHz       122 Slice LUTs (38 slices) (p.)
Xilinx          Virtex-6        275.7 MHz       122 Slice LUTs (38 slices) (p.)
Disclaimer:  Like other embedded processors, these are the maximum performance
Disclaimer:  Like other embedded processors, these are the maximum performance
claims.  Realistic implementations will produce slower maximum clock rates,
claims.  Realistic implementations will produce slower maximum clock rates,
particularly with lots of I/O ports and peripherals and with the constraint of
particularly with lots of I/O ports and peripherals and with the constraint of
existing with other subsystems in the FPGA fabric.  What these performance
existing with other subsystems in the FPGA fabric.  What these performance
numbers do provide is an estimate of the amount of slack available.  For
numbers do provide is an estimate of the amount of slack available.  For
example, you can't realistically expect to get 110 MHz from a processor that,
example, you can't realistically expect to get 110 MHz from a processor that,
under ideal conditions, places and routes at 125 MHz, but you can with a
under ideal conditions, places and routes at 125 MHz, but you can with a
processor that is demonstrated to place and route at 150 MHz.
processor that is demonstrated to place and route at 150 MHz.
EXAMPLE:
EXAMPLE:
================================================================================
================================================================================
The LED flasher example demonstrates the simplicity of the architectural
The LED flasher example demonstrates the simplicity of the architectural
specification and the Forth-like assembly language.
specification and the Forth-like assembly language.
The architecture file, named "led.9x8", with the comments and user header
The architecture file, named "led.9x8", with the comments and user header
removed, is as follows:
removed, is as follows:
  ARCHITECTURE    core/9x8 Verilog
  ARCHITECTURE    core/9x8 Verilog
  INSTRUCTION     2048
  INSTRUCTION     2048
  RETURN_STACK    32
  RETURN_STACK    32
  DATA_STACK      32
  DATA_STACK      32
  PORTCOMMENT LED on/off signal
  PORTCOMMENT LED on/off signal
  OUTPORT 1-bit o_led O_LED
  OUTPORT 1-bit o_led O_LED
  ASSEMBLY led.s
  ASSEMBLY led.s
The ARCHITECTURE configuration command specifies the 9x8 core and the Verilog
The ARCHITECTURE configuration command specifies the 9x8 core and the Verilog
language.  The INSTRUCTION, RETURN_STACK, and DATA_STACK configuration commands
language.  The INSTRUCTION, RETURN_STACK, and DATA_STACK configuration commands
specify the sizes of the instruction space, return stack, and data stack.  The
specify the sizes of the instruction space, return stack, and data stack.  The
content of the PORTCOMMENT configuration command is inserted in the module
content of the PORTCOMMENT configuration command is inserted in the module
declaration -- this facilitates identifying signals in micro controllers with a
declaration -- this facilitates identifying signals in micro controllers with a
lot of inputs and outputs.  The single OUTPORT statement specifies a 1-bit
lot of inputs and outputs.  The single OUTPORT statement specifies a 1-bit
signal named "o_led".  This signal is accessed in the assembly code through the
signal named "o_led".  This signal is accessed in the assembly code through the
symbol "O_LED".  The ASSEMBLY command specifies the single input file "led.s,"
symbol "O_LED".  The ASSEMBLY command specifies the single input file "led.s,"
which is listed below.  The output module will be "led.v"
which is listed below.  The output module will be "led.v"
The "led.s" assembly file is as follows:
The "led.s" assembly file is as follows:
  ; Consume 256*5+4 clock cycles.
  ; Consume 256*5+4 clock cycles.
  ; ( - )
  ; ( - )
  .function pause
  .function pause
    0 :inner 1- dup .jumpc(inner) drop
    0 :inner 1- dup .jumpc(inner) drop
  .return
  .return
  ; Repeat "pause" 256 times.
  ; Repeat "pause" 256 times.
  ; ( - )
  ; ( - )
  .function repause
  .function repause
    0 :inner .call(pause) 1- dup .jumpc(inner) drop
    0 :inner .call(pause) 1- dup .jumpc(inner) drop
  .return
  .return
  ; main program (as an infinite loop)
  ; main program (as an infinite loop)
  .main
  .main
    0 :inner 1 ^ dup .outport(O_LED) .call(repause) .jump(inner)
    0 :inner 1 ^ dup .outport(O_LED) .call(repause) .jump(inner)
This example is coded in a traditional Forth structure with the conditional
This example is coded in a traditional Forth structure with the conditional
jumps consuming the top of the data stack.  Examining the "pause" function, the
jumps consuming the top of the data stack.  Examining the "pause" function, the
".function" directive specifies the start of a function and the function name.
".function" directive specifies the start of a function and the function name.
The "0" instruction pushes the value "0" onto the top of the data stack.
The "0" instruction pushes the value "0" onto the top of the data stack.
":inner" is a label for a jump instruction.  The "1-" instruction decrements the
":inner" is a label for a jump instruction.  The "1-" instruction decrements the
top of the data stack.  "dup" is the Forth instruction to push a duplicate of
top of the data stack.  "dup" is the Forth instruction to push a duplicate of
the top of the data stack onto the data stack.  The ".jumpc(inner)" macro
the top of the data stack onto the data stack.  The ".jumpc(inner)" macro
expands to three instructions as follows:  (1) push the 8 lsb of the address at
expands to three instructions as follows:  (1) push the 8 lsb of the address at
"inner" onto the data stack, (2) the conditional jump instruction with the 5 msb
"inner" onto the data stack, (2) the conditional jump instruction with the 5 msb
of the address of "inner" (the jumpc instruction also drops the top of the data
of the address of "inner" (the jumpc instruction also drops the top of the data
stack with its partial address), and (3) a "drop" instruction to drop the
stack with its partial address), and (3) a "drop" instruction to drop the
duplicated loop count from the top of the data stack.  Finally, the "drop"
duplicated loop count from the top of the data stack.  Finally, the "drop"
instruction drops the loop count from the top of the data stack and the
instruction drops the loop count from the top of the data stack and the
".return" macro generates the "return" instruction and a "nop" instruction.
".return" macro generates the "return" instruction and a "nop" instruction.
The function "repause" calls the "pause" function 256 times.  The main program
The function "repause" calls the "pause" function 256 times.  The main program
body is identified by the directive ".main"  This function runs an infinite loop
body is identified by the directive ".main"  This function runs an infinite loop
that toggles the lsb of the LED output, outputs the LED setting, and calls the
that toggles the lsb of the LED output, outputs the LED setting, and calls the
"repause" function.
"repause" function.
A tighter version of the loop in the "pause" function can be written as
A tighter version of the loop in the "pause" function can be written as
  ; Consume 256*3+3 clock cycles.
  ; Consume 256*3+3 clock cycles.
  ; ( - )
  ; ( - )
  .function pause
  .function pause
    0xFF :inner .jumpc(inner,1-) .return(drop)
    0xFF :inner .jumpc(inner,1-) .return(drop)
which is 3 cycles long for each iteration, the "drop" that is normally part
which is 3 cycles long for each iteration, the "drop" that is normally part
of the ".jumpc" macro has been replaced by the decrement instruction, and the
of the ".jumpc" macro has been replaced by the decrement instruction, and the
final "drop" instruction has replaced the default "nop" instruction that is
final "drop" instruction has replaced the default "nop" instruction that is
normally part of the ".return" macro.  Note that the decrement is performed
normally part of the ".return" macro.  Note that the decrement is performed
after the non-zero comparison in the "jumpc" instruction.
after the non-zero comparison in the "jumpc" instruction.
A version of the "pause" function that consumes exactly 1000 clock cycles is:
A version of the "pause" function that consumes exactly 1000 clock cycles is:
  .function pause
  .function pause
    ${(1000-4)/4-1} :inner nop .jumpc(inner,1-) drop .return
    ${(1000-4)/4-1} :inner nop .jumpc(inner,1-) drop .return
The instruction memory initialization for the processor module includes the
The instruction memory initialization for the processor module includes the
instruction mnemonics being performed at each address and replaces the "list"
instruction mnemonics being performed at each address and replaces the "list"
file output from traditional assemblers.  The following is the memory
file output from traditional assemblers.  The following is the memory
initialization for this LED flasher example.  The main program always starts at
initialization for this LED flasher example.  The main program always starts at
address zero and functions are included in the order encountered.  Unused
address zero and functions are included in the order encountered.  Unused
library functions are not included in the generated instruction list.
library functions are not included in the generated instruction list.
  reg [8:0] s_opcodeMemory[2047:0];
  reg [8:0] s_opcodeMemory[2047:0];
  initial begin
  initial begin
    // .main
    // .main
    s_opcodeMemory['h000] = 9'h100; // 0x00
    s_opcodeMemory['h000] = 9'h100; // 0x00
    s_opcodeMemory['h001] = 9'h101; // :inner 0x01
    s_opcodeMemory['h001] = 9'h101; // :inner 0x01
    s_opcodeMemory['h002] = 9'h052; // ^
    s_opcodeMemory['h002] = 9'h052; // ^
    s_opcodeMemory['h003] = 9'h008; // dup
    s_opcodeMemory['h003] = 9'h008; // dup
    s_opcodeMemory['h004] = 9'h100; // O_LED
    s_opcodeMemory['h004] = 9'h100; // O_LED
    s_opcodeMemory['h005] = 9'h038; // outport
    s_opcodeMemory['h005] = 9'h038; // outport
    s_opcodeMemory['h006] = 9'h054; // drop
    s_opcodeMemory['h006] = 9'h054; // drop
    s_opcodeMemory['h007] = 9'h10D; //
    s_opcodeMemory['h007] = 9'h10D; //
    s_opcodeMemory['h008] = 9'h0C0; // call repause
    s_opcodeMemory['h008] = 9'h0C0; // call repause
    s_opcodeMemory['h009] = 9'h000; // nop
    s_opcodeMemory['h009] = 9'h000; // nop
    s_opcodeMemory['h00A] = 9'h101; //
    s_opcodeMemory['h00A] = 9'h101; //
    s_opcodeMemory['h00B] = 9'h080; // jump inner
    s_opcodeMemory['h00B] = 9'h080; // jump inner
    s_opcodeMemory['h00C] = 9'h000; // nop
    s_opcodeMemory['h00C] = 9'h000; // nop
    // repause
    // repause
    s_opcodeMemory['h00D] = 9'h100; // 0x00
    s_opcodeMemory['h00D] = 9'h100; // 0x00
    s_opcodeMemory['h00E] = 9'h119; // :inner
    s_opcodeMemory['h00E] = 9'h119; // :inner
    s_opcodeMemory['h00F] = 9'h0C0; // call pause
    s_opcodeMemory['h00F] = 9'h0C0; // call pause
    s_opcodeMemory['h010] = 9'h000; // nop
    s_opcodeMemory['h010] = 9'h000; // nop
    s_opcodeMemory['h011] = 9'h05C; // 1-
    s_opcodeMemory['h011] = 9'h05C; // 1-
    s_opcodeMemory['h012] = 9'h008; // dup
    s_opcodeMemory['h012] = 9'h008; // dup
    s_opcodeMemory['h013] = 9'h10E; //
    s_opcodeMemory['h013] = 9'h10E; //
    s_opcodeMemory['h014] = 9'h0A0; // jumpc inner
    s_opcodeMemory['h014] = 9'h0A0; // jumpc inner
    s_opcodeMemory['h015] = 9'h054; // drop
    s_opcodeMemory['h015] = 9'h054; // drop
    s_opcodeMemory['h016] = 9'h054; // drop
    s_opcodeMemory['h016] = 9'h054; // drop
    s_opcodeMemory['h017] = 9'h028; // return
    s_opcodeMemory['h017] = 9'h028; // return
    s_opcodeMemory['h018] = 9'h000; // nop
    s_opcodeMemory['h018] = 9'h000; // nop
    // pause
    // pause
    s_opcodeMemory['h019] = 9'h100; // 0x00
    s_opcodeMemory['h019] = 9'h100; // 0x00
    s_opcodeMemory['h01A] = 9'h05C; // :inner 1-
    s_opcodeMemory['h01A] = 9'h05C; // :inner 1-
    s_opcodeMemory['h01B] = 9'h008; // dup
    s_opcodeMemory['h01B] = 9'h008; // dup
    s_opcodeMemory['h01C] = 9'h11A; //
    s_opcodeMemory['h01C] = 9'h11A; //
    s_opcodeMemory['h01D] = 9'h0A0; // jumpc inner
    s_opcodeMemory['h01D] = 9'h0A0; // jumpc inner
    s_opcodeMemory['h01E] = 9'h054; // drop
    s_opcodeMemory['h01E] = 9'h054; // drop
    s_opcodeMemory['h01F] = 9'h054; // drop
    s_opcodeMemory['h01F] = 9'h054; // drop
    s_opcodeMemory['h020] = 9'h028; // return
    s_opcodeMemory['h020] = 9'h028; // return
    s_opcodeMemory['h021] = 9'h000; // nop
    s_opcodeMemory['h021] = 9'h000; // nop
    s_opcodeMemory['h022] = 9'h000;
    s_opcodeMemory['h022] = 9'h000;
    s_opcodeMemory['h023] = 9'h000;
    s_opcodeMemory['h023] = 9'h000;
    s_opcodeMemory['h024] = 9'h000;
    s_opcodeMemory['h024] = 9'h000;
    ...
    ...
    s_opcodeMemory['h7FF] = 9'h000;
    s_opcodeMemory['h7FF] = 9'h000;
  end
  end
DATA and STRINGS
DATA and STRINGS
================================================================================
================================================================================
Values are pushed onto the data stack by stating the value.  For example,
Values are pushed onto the data stack by stating the value.  For example,
  0x10 0x20 'x'
  0x10 0x20 'x'
will successively push the values 0x10, 0x20, and the character 'x' onto the
will successively push the values 0x10, 0x20, and the character 'x' onto the
data stack.  The character 'x' will be at the top of the data stack after these
data stack.  The character 'x' will be at the top of the data stack after these
3 instructions.
3 instructions.
Numeric values can be represented in binary, octal, decimal, and hex.  Binary
Numeric values can be represented in binary, octal, decimal, and hex.  Binary
values start with the two characters "0b" followed by a sequence of binary
values start with the two characters "0b" followed by a sequence of binary
digits; octal numbers start with a "0" followed by a sequence of octal digits;
digits; octal numbers start with a "0" followed by a sequence of octal digits;
decimal values can start with a "+" or "-" have a non-zero first digit and have
decimal values can start with a "+" or "-" have a non-zero first digit and have
zero or more decimal digits; and hex values start with the two characters "0X"
zero or more decimal digits; and hex values start with the two characters "0X"
followed by a sequence of hex digits.
followed by a sequence of hex digits.
Examples of equivalent numeric values are:
Examples of equivalent numeric values are:
  binary:   0b01  0b10010
  binary:   0b01  0b10010
  octal:    01    022
  octal:    01    022
  decimal:  1     18
  decimal:  1     18
  hex:      0x1   0x12
  hex:      0x1   0x12
See the COMPUTED VALUES section for using computed values in the assembler.
See the COMPUTED VALUES section for using computed values in the assembler.
There are four ways to specify strings in the assembler.  Simply stating the
There are four ways to specify strings in the assembler.  Simply stating the
string
string
  "Hello World!"
  "Hello World!"
puts the characters in the string onto the data stack with the letter 'H' at the
puts the characters in the string onto the data stack with the letter 'H' at the
top of the data stack.  I.e., the individual push operations are
top of the data stack.  I.e., the individual push operations are
  '!' 'd' 'l' ... 'e' 'H'
  '!' 'd' 'l' ... 'e' 'H'
Prepending a 'N' before the double quote, like
Prepending a 'N' before the double quote, like
  N"Hello World!"
  N"Hello World!"
puts a null-terminated string onto the data stack.  I.e., the value under the
puts a null-terminated string onto the data stack.  I.e., the value under the
'!' will be a 0x00 and the instruction sequence would be
'!' will be a 0x00 and the instruction sequence would be
  0x0 '!' 'd' 'l' ... 'e' 'H'
  0x0 '!' 'd' 'l' ... 'e' 'H'
Forth uses counted strings, which are specified here as
Forth uses counted strings, which are specified here as
  C"Hello World!"
  C"Hello World!"
In this case the number of characters, 12, in the string is pushed onto the data
In this case the number of characters, 12, in the string is pushed onto the data
stack after the 'H', i.e., the instruction sequence would be
stack after the 'H', i.e., the instruction sequence would be
  '!' 'd' 'l' ... 'e' 'H' 12
  '!' 'd' 'l' ... 'e' 'H' 12
Finally, a lesser-counted string specified like
Finally, a lesser-counted string specified like
  c"Hello World!"
  c"Hello World!"
is similar to the Forth-like counted string except that the value pushed onto
is similar to the Forth-like counted string except that the value pushed onto
the data stack is one less than the number of characters in the string.  Here
the data stack is one less than the number of characters in the string.  Here
the value pushed onto the data stack after the 'H' would be 11 instead of 12.
the value pushed onto the data stack after the 'H' would be 11 instead of 12.
Simple strings are useful for constructing more complex strings in conjunction
Simple strings are useful for constructing more complex strings in conjunction
with other string functions.   For example, to transmit the hex values of the
with other string functions.   For example, to transmit the hex values of the
top 2 values in the data stack, do something like:
top 2 values in the data stack, do something like:
  ; move the top 2 values to the return stack
  ; move the top 2 values to the return stack
  >r >r
  >r >r
  ; push the tail of the message onto the data stack
  ; push the tail of the message onto the data stack
  N"\n\r"
  N"\n\r"
  ; convert the 2 values to 2-digit hex values, LSB deepest in the stack
  ; convert the 2 values to 2-digit hex values, LSB deepest in the stack
  r> .call(string_byte_to_hex)
  r> .call(string_byte_to_hex)
  r> .call(string_byte_to_hex)
  r> .call(string_byte_to_hex)
  ; pre-pend the identification message
  ; pre-pend the identification message
  "Message:  "
  "Message:  "
  ; transmit the string, using the null terminator to terminate the loop
  ; transmit the string, using the null terminator to terminate the loop
  :loop_transmit .outport(O_UART_TX) .jumpc(loop_transmit,nop) drop
  :loop_transmit .outport(O_UART_TX) .jumpc(loop_transmit,nop) drop
A lesser-counted string would be used like:
A lesser-counted string would be used like:
  c"Status Message\r\n"
  c"Status Message\r\n"
  :loop_msg swap .outport(O_UART_TX) .jumpc(loop_msg,1-) drop
  :loop_msg swap .outport(O_UART_TX) .jumpc(loop_msg,1-) drop
These four string formats can also be used for variable definitions.  For
These four string formats can also be used for variable definitions.  For
example 3 variables could be allocated and initialized as follows:
example 3 variables could be allocated and initialized as follows:
  .memory ROM myrom
  .memory ROM myrom
  .variable fred N"fred"
  .variable fred N"fred"
  .variable joe  c"joe"
  .variable joe  c"joe"
  .variable moe  "moe"
  .variable moe  "moe"
These are equivalent to
These are equivalent to
  .variable fred 'f' 'r' 'e' 'd'  0
  .variable fred 'f' 'r' 'e' 'd'  0
  .variable joe   2  'j' 'o' 'e'
  .variable joe   2  'j' 'o' 'e'
  .variable moe  'm' 'o' 'e'
  .variable moe  'm' 'o' 'e'
with 5 bytes allocated for the variable fred, 4 bytes for joe, and 3 bytes for
with 5 bytes allocated for the variable fred, 4 bytes for joe, and 3 bytes for
moe.
moe.
The following escaped characters are recognized:
The following escaped characters are recognized:
  '\0'     null character
  '\0'     null character
  '\a'     bell
  '\a'     bell
  '\b'     backspace
  '\b'     backspace
  '\f'     form feed
  '\f'     form feed
  '\n'     line feed
  '\n'     line feed
  '\r'     carriage return
  '\r'     carriage return
  '\t'     horizontal tab
  '\t'     horizontal tab
  "\0ooo"  3-digit octal value
  "\0ooo"  3-digit octal value
  "\xXX"   2-digit hex value where X is one of 0-9, a-f, or A-F
  "\xXX"   2-digit hex value where X is one of 0-9, a-f, or A-F
  "\Xxx"   alternate form for 2-digit hex value
  "\Xxx"   alternate form for 2-digit hex value
  "\\"     backslash character
  "\\"     backslash character
Unrecognized escaped characters are simple treated as that character.  For
Unrecognized escaped characters are simple treated as that character.  For
example, '\m' is treated as the single character 'm' and '\'' is treated as the
example, '\m' is treated as the single character 'm' and '\'' is treated as the
single quote character.
single quote character.
INSTRUCTIONS
INSTRUCTIONS
================================================================================
================================================================================
The 43 instructions are as follows (see core/9x8/doc/opcodes.html for detailed
The 43 instructions are as follows (see core/9x8/doc/opcodes.html for detailed
descriptions).  Here, T is the top of the data stack, N is the next-to-top of
descriptions).  Here, T is the top of the data stack, N is the next-to-top of
the data stack, and R is the top of the return stack.  All of these are the
the data stack, and R is the top of the return stack.  All of these are the
values at the start of the instruction.
values at the start of the instruction.
The nop instruction does nothing:
The nop instruction does nothing:
  nop           no operation
  nop           no operation
Mathematical operations drop one value from the data stack and replace the new
Mathematical operations drop one value from the data stack and replace the new
top with the state value:
top with the state value:
  &             bitwise and of N and T
  &             bitwise and of N and T
  +             N + T
  +             N + T
  -             N - T
  -             N - T
  ^             bitwise exclusive or of N and T
  ^             bitwise exclusive or of N and T
  or            bitwise or of N and T
  or            bitwise or of N and T
Push the carry bit for addition or subtraction onto the data stack (see
Push the carry bit for addition or subtraction onto the data stack (see
lib/9x8/math.s for examples on using +c and -c for multi-byte arithmetic):
lib/9x8/math.s for examples on using +c and -c for multi-byte arithmetic):
  +c            carry bit for N+T
  +c            carry bit for N+T
  -c            carry bit for N-T
  -c            carry bit for N-T
Increment and decrement replace the top of the data stack with the stated
Increment and decrement replace the top of the data stack with the stated
result.
result.
  1+            replace T with T+1
  1+            replace T with T+1
  1-            replace T with T-1
  1-            replace T with T-1
Comparison operations replace the top of the data stack with the results of the
Comparison operations replace the top of the data stack with the results of the
comparison:
comparison:
  -1<>          replace T with -1 if T != -1, otherwise set T to 0
  -1<>          replace T with -1 if T != -1, otherwise set T to 0
  -1=           replace T with 0 if T != -1, otherwise leave T as -1
  -1=           replace T with 0 if T != -1, otherwise leave T as -1
  0<>           replace T with -1 if T != 0, otherwise leave T as 0
  0<>           replace T with -1 if T != 0, otherwise leave T as 0
  0=            replace T with -1 if T == 0, otherwise set T to 0
  0=            replace T with -1 if T == 0, otherwise set T to 0
Shift/rotate operations replace the top of the data with with the result of the
Shift/rotate operations replace the top of the data with with the result of the
specified shift/rotate.
specified shift/rotate.
  0>>           shift T right one bit and set the msb to 0
  0>>           shift T right one bit and set the msb to 0
  1>>           shift T right 1 bit and set the msb to 1
  1>>           shift T right 1 bit and set the msb to 1
  <<0           shift T left 1 bit and set the lsb to 0
  <<0           shift T left 1 bit and set the lsb to 0
  <<1           shift T left 1 bit and set the lsb to 1
  <<1           shift T left 1 bit and set the lsb to 1
  <
  <
  lsb>>         rotate T right 1 bit
  lsb>>         rotate T right 1 bit
  msb>>         shift T right 1 bit and set the msb to the old msb
  msb>>         shift T right 1 bit and set the msb to the old msb
Note:  There is no "<
Note:  There is no "<
Stack manipulation instructions are as follows:
Stack manipulation instructions are as follows:
  >r            pushd T onto the return stack and drop T from the data stack
  >r            pushd T onto the return stack and drop T from the data stack
  drop          drop T from the data stack
  drop          drop T from the data stack
  dup           push T onto the data stack
  dup           push T onto the data stack
  nip           drop N from the data stack
  nip           drop N from the data stack
  over          push N onto the data stack
  over          push N onto the data stack
  push          push a single byte onto the data stack, see the preceding DATA
  push          push a single byte onto the data stack, see the preceding DATA
                and STRINGS section
                and STRINGS section
  r>            push R onto the data stack and drop R from the return stack
  r>            push R onto the data stack and drop R from the return stack
  r@            push R onto the data stack
  r@            push R onto the data stack
  swap          swap N and T
  swap          swap N and T
Jump and call and their conditional variants are as follows and must use the
Jump and call and their conditional variants are as follows and must use the
associated macro:
associated macro:
  call          call instruction -- use the .call macro
  call          call instruction -- use the .call macro
  callc         conditional call instruction -- use the .callc macro
  callc         conditional call instruction -- use the .callc macro
  jump          jump instruction -- use the .jump macro
  jump          jump instruction -- use the .jump macro
  jumpc         conditional jump instruction -- use the .jumpc macro
  jumpc         conditional jump instruction -- use the .jumpc macro
  return        return instruction -- use the .return macro
  return        return instruction -- use the .return macro
See the MEMORY section for details for these memory operations.  T is the
See the MEMORY section for details for these memory operations.  T is the
address for the instructions, N is the value stored.  Chained fetches insert the
address for the instructions, N is the value stored.  Chained fetches insert the
value below T.  Chained stores drop N.
value below T.  Chained stores drop N.
  fetch         memory fetch, replace T with the value fetched
  fetch         memory fetch, replace T with the value fetched
  fetch+        chained memory fetch, retain and increment the address
  fetch+        chained memory fetch, retain and increment the address
  fetch-        chained memory fetch, retain and decrement the address
  fetch-        chained memory fetch, retain and decrement the address
  store         memory store, drop T (N is the next value of T)
  store         memory store, drop T (N is the next value of T)
  store+        chained memory store, retain and increment the address
  store+        chained memory store, retain and increment the address
  store-        chained memory store, retain and decrement the address
  store-        chained memory store, retain and decrement the address
See the INPORT and OUTPORT section for details for the input and output port
See the INPORT and OUTPORT section for details for the input and output port
operations:
operations:
  inport        input port operation
  inport        input port operation
  outport       output port operation
  outport       output port operation
The .call, .callc, .jump, and .jumpc macros encode the 3 instructions required
The .call, .callc, .jump, and .jumpc macros encode the 3 instructions required
to perform a call or jump along with the subsequent instructions.  The default
to perform a call or jump along with the subsequent instructions.  The default
third instructions is "nop" for .call and .jump and it is "drop" for .callc and
third instructions is "nop" for .call and .jump and it is "drop" for .callc and
.jumpc.  The default can be changed by specifying the optional second argument.
.jumpc.  The default can be changed by specifying the optional second argument.
The .call and .callc macros must specify a function identified by the .function
The .call and .callc macros must specify a function identified by the .function
directive and the .jump and .jumpc macros must specify a label.
directive and the .jump and .jumpc macros must specify a label.
The .function directive takes the name of the function and the function body.
The .function directive takes the name of the function and the function body.
Function bodies must end with a .return or a .jump macro.  The .main directive
Function bodies must end with a .return or a .jump macro.  The .main directive
defines the body of the main function, i.e., the function at which the processor
defines the body of the main function, i.e., the function at which the processor
starts.
starts.
The .include directive is used to read additional assembly code.  You can, for
The .include directive is used to read additional assembly code.  You can, for
example, put the main function in uc.s, define constants and such in consts.s,
example, put the main function in uc.s, define constants and such in consts.s,
define the memories and variables in ram.s, and include UART utilities in
define the memories and variables in ram.s, and include UART utilities in
uart.s.  These files could be included in uc.s through the following lines:
uart.s.  These files could be included in uc.s through the following lines:
  .include consts.s
  .include consts.s
  .include myram.s
  .include myram.s
  .include uart.s
  .include uart.s
The assembler only includes functions that can be reached from the main
The assembler only includes functions that can be reached from the main
function.  Unused functions will not consume instruction space.
function.  Unused functions will not consume instruction space.
INPORT and OUTPORT
INPORT and OUTPORT
================================================================================
================================================================================
The INPORT and OUTPORT configuration commands are used to specify 2-state inputs
The INPORT and OUTPORT configuration commands are used to specify 2-state inputs
and outputs.  For example
and outputs.  For example
  INPORT 8-bit i_value I_VALUE
  INPORT 8-bit i_value I_VALUE
specifies a single 8-bit input signal named "i_value" for the module.  The port
specifies a single 8-bit input signal named "i_value" for the module.  The port
is accessed in assembly by ".inport(I_VALUE)" which is equivalent to the
is accessed in assembly by ".inport(I_VALUE)" which is equivalent to the
two-instruction sequence "I_VALUE inport".  To input an 8-bit value from a FIFO
two-instruction sequence "I_VALUE inport".  To input an 8-bit value from a FIFO
and send a single-clock-cycle wide acknowledgment strobe, use
and send a single-clock-cycle wide acknowledgment strobe, use
  INPORT 8-bit,strobe i_fifo,o_fifo_ack I_FIFO
  INPORT 8-bit,strobe i_fifo,o_fifo_ack I_FIFO
The assembly ".inport(I_FIFO)" will automatically send an acknowledgment strobe
The assembly ".inport(I_FIFO)" will automatically send an acknowledgment strobe
to the FIFO through "o_fifo_ack".
to the FIFO through "o_fifo_ack".
A write port to an 8-bit FIFO is similarly specified by
A write port to an 8-bit FIFO is similarly specified by
  OUTPORT 8-bit,strobe o_fifo,o_fifo_wr O_FIFO
  OUTPORT 8-bit,strobe o_fifo,o_fifo_wr O_FIFO
The assembly ".outport(O_FIFO)" which is equivalent to "O_FIFO outport drop"
The assembly ".outport(O_FIFO)" which is equivalent to "O_FIFO outport drop"
will automatically send a write strobe to the FIFO through "o_fifo_wr".
will automatically send a write strobe to the FIFO through "o_fifo_wr".
Multiple signals can be packed into a single input or output port by defining
Multiple signals can be packed into a single input or output port by defining
them in comma separated lists.  The associated bit masks can be defined
them in comma separated lists.  The associated bit masks can be defined
coincident with the port definition as follows:
coincident with the port definition as follows:
  INPUT 1-bit,1-bit i_fifo_full,i_fifo_empty I_FIFO_STATUS
  INPUT 1-bit,1-bit i_fifo_full,i_fifo_empty I_FIFO_STATUS
  CONSTANT C_FIFO_STATUS__FULL  0x02
  CONSTANT C_FIFO_STATUS__FULL  0x02
  CONSTANT C_FIFO_STATUS__EMPTY 0x01
  CONSTANT C_FIFO_STATUS__EMPTY 0x01
Checking the "full" status of the FIFO can be done by the following assembly
Checking the "full" status of the FIFO can be done by the following assembly
sequence:
sequence:
  .inport(I_FIFO_STATUS) C_FIFO_STATUS__FULL &
  .inport(I_FIFO_STATUS) C_FIFO_STATUS__FULL &
Multiple bits can be masked using a computed value as follows (see below for
Multiple bits can be masked using a computed value as follows (see below for
more details):
more details):
  .inport(I_FIFO_STATUS) ${C_FIFO_STATUS__FULL|C_FIFO_STATUS__EMPTY} &
  .inport(I_FIFO_STATUS) ${C_FIFO_STATUS__FULL|C_FIFO_STATUS__EMPTY} &
The "${...}" creates an instruction to push the 8-bit value in the braces onto
The "${...}" creates an instruction to push the 8-bit value in the braces onto
the data stack.  The computation is performed using the Python "eval" function
the data stack.  The computation is performed using the Python "eval" function
in the context of the program constants, memory addresses, and memory sizes.
in the context of the program constants, memory addresses, and memory sizes.
Preceding all of these by
Preceding all of these by
  PORTCOMMENT external FIFO
  PORTCOMMENT external FIFO
produces the following in the Verilog module statement.  The I/O ports are
produces the following in the Verilog module statement.  The I/O ports are
listed in the order in which they are declared.
listed in the order in which they are declared.
  // external FIFO
  // external FIFO
  input  wire       [7:0] i_fifo,
  input  wire       [7:0] i_fifo,
  output reg              o_fifo_ack,
  output reg              o_fifo_ack,
  output reg        [7:0] o_fifo,
  output reg        [7:0] o_fifo,
  output reg              o_fifo_wr,
  output reg              o_fifo_wr,
  input  wire             i_fifo_full,
  input  wire             i_fifo_full,
  input  wire             i_fifo_empty
  input  wire             i_fifo_empty
The HDL to implement the inputs and outputs is computer generated.  Identifying
The HDL to implement the inputs and outputs is computer generated.  Identifying
the port name in the architecture file eliminates the possibility of
the port name in the architecture file eliminates the possibility of
inconsistent port numbers between the HDL and the assembly.  Specifying the bit
inconsistent port numbers between the HDL and the assembly.  Specifying the bit
mapping for the assembly code immediately after the port definition helps
mapping for the assembly code immediately after the port definition helps
prevent inconsistencies between the port definition and the bit mapping in the
prevent inconsistencies between the port definition and the bit mapping in the
assembly code.
assembly code.
The normal initial value for an outport is zero.  This can be changed by
The normal initial value for an outport is zero.  This can be changed by
including an optional initial value as follows.  This initial value will be
including an optional initial value as follows.  This initial value will be
applied on system startup and when the micro controller is reset.
applied on system startup and when the micro controller is reset.
  OUTPORT 4-bit=4'hA o_signal O_SIGNAL
  OUTPORT 4-bit=4'hA o_signal O_SIGNAL
An isolated output strobe can also be created using:
An isolated output strobe can also be created using:
  OUTPORT strobe o_strobe O_STROBE
  OUTPORT strobe o_strobe O_STROBE
The assembly ".outstrobe(O_STROBE)" which is equivalent to "O_STROBE outport"
The assembly ".outstrobe(O_STROBE)" which is equivalent to "O_STROBE outport"
is used to generate the strobe.  Since "O_STROBE" is a strobe-only outport, the
is used to generate the strobe.  Since "O_STROBE" is a strobe-only outport, the
".outport" macro cannot be used with it.  Similarly, attempting to use the
".outport" macro cannot be used with it.  Similarly, attempting to use the
".outstrobe" macro will generate an error if it is invoked with an outport
".outstrobe" macro will generate an error if it is invoked with an outport
that does have data.
that does have data.
A single-bit "set-reset" input port type is also included.  This sets a register
A single-bit "set-reset" input port type is also included.  This sets a register
when an external strobe is received and clears the register when the port is
when an external strobe is received and clears the register when the port is
read.  For example, to capture an external timer for a polled-loop, include the
read.  For example, to capture an external timer for a polled-loop, include the
following in the architecture file:
following in the architecture file:
  PORTCOMMENT external timer
  PORTCOMMENT external timer
  INPORT set-reset i_timer I_TIMER
  INPORT set-reset i_timer I_TIMER
The following is the assembly code to conditionally call two functions when the
The following is the assembly code to conditionally call two functions when the
timer event is encountered:
timer event is encountered:
  .inport(I_TIMER)
  .inport(I_TIMER)
    .callc(timer_event_1,nop)
    .callc(timer_event_1,nop)
    .callc(timer_event_2)
    .callc(timer_event_2)
The "nop" in the first conditional call prevents the conditional from being
The "nop" in the first conditional call prevents the conditional from being
dropped from the data stack so that it can be used by the subsequent conditional
dropped from the data stack so that it can be used by the subsequent conditional
function call.
function call.
 
 
 
The input from a set-reset INPORT is a pure flag.  I.e., either all of the bits
 
are zero or all of the bits are one.  This can be used as part of executing a
 
loop a fixed number of times.  For example, the inperiod argument of the
 
servo_motor peripheral can be used to receive a strobe every time the PWM goes
 
high.  The following loop will wait for 10 occurrences of the rising edge of the
 
servo_motor PWM before proceeding to the next block of code:
 
 
 
  10 :loop .inport(I_INPERIOD) + .jumpc(loop,nop) drop
 
 
 
 
PERIPHERAL
PERIPHERAL
================================================================================
================================================================================
Peripherals are implemented via Python modules.  For example, an open drain I/O
Peripherals are implemented via Python modules.  For example, an open drain I/O
signal, such as is required for an I2C bus, does not fit the INPORT and OUTPORT
signal, such as is required for an I2C bus, does not fit the INPORT and OUTPORT
functionality.  Instead, an "open_drain" peripheral is provided by the Python
functionality.  Instead, an "open_drain" peripheral is provided by the Python
script in "core/9x8/peripherals/open_drain.py".  This puts a tri-state I/O in
script in "core/9x8/peripherals/open_drain.py".  This puts a tri-state I/O in
the module statement, allows it to be read through an "inport" instruction, and
the module statement, allows it to be read through an "inport" instruction, and
allows it to be set low or released through an "outport" instruction.  An I2C
allows it to be set low or released through an "outport" instruction.  An I2C
bus with separate SCL and SDA ports can then be incorporated into the processor
bus with separate SCL and SDA ports can then be incorporated into the processor
as follows:
as follows:
  PORTCOMMENT     I2C bus
  PORTCOMMENT     I2C bus
  PERIPHERAL      open_drain      inport=I_SCL \
  PERIPHERAL      open_drain      inport=I_SCL \
                                  outport=O_SCL \
                                  outport=O_SCL \
                                  iosignal=io_scl
                                  iosignal=io_scl
  PERIPHERAL      open_drain      inport=I_SDA \
  PERIPHERAL      open_drain      inport=I_SDA \
                                  outport=O_SDA \
                                  outport=O_SDA \
                                  iosignal=io_sda
                                  iosignal=io_sda
The default width for this peripheral is 1 bit.  The module statement will then
The default width for this peripheral is 1 bit.  The module statement will then
include the lines
include the lines
  // I2C bus
  // I2C bus
  inout  wire     io_scl,
  inout  wire     io_scl,
  inout  wire     io_sda
  inout  wire     io_sda
The assembly code to set the io_scl signal low is "0 .outport(O_SCL)" and to
The assembly code to set the io_scl signal low is "0 .outport(O_SCL)" and to
release it is "1 .outport(O_SCL)".  These instruction sequences are actually
release it is "1 .outport(O_SCL)".  These instruction sequences are actually
"0 O_SCL outport drop" and "1 O_SCL outport drop" respectively.  The "outport"
"0 O_SCL outport drop" and "1 O_SCL outport drop" respectively.  The "outport"
instruction drops the top of the data stack (which contained the port number)
instruction drops the top of the data stack (which contained the port number)
and sends the next-to-the-top of the data stack to the designated output port.
and sends the next-to-the-top of the data stack to the designated output port.
Two examples of I2C device operation are included in the examples directory.
Two examples of I2C device operation are included in the examples directory.
The following peripherals are provided:
The following peripherals are provided:
  adder_16bit   16-bit adder/subtractor
  adder_16bit   16-bit adder/subtractor
  AXI4_Lite_Master
  AXI4_Lite_Master
                32-bit read/write AXI4-Lite Master
                32-bit read/write AXI4-Lite Master
                Note:  The synchronous version has been tested on hardware.
                Note:  The synchronous version has been tested on hardware.
  AXI4_Lite_Slave_DualPortRAM
  AXI4_Lite_Slave_DualPortRAM
                dual-port-RAM interface for the micro controller to act as an
                dual-port-RAM interface for the micro controller to act as an
                AXI4-Lite slave
                AXI4-Lite slave
  big_inport    shift reads from a single INPORT to construct a wide input
  big_inport    shift reads from a single INPORT to construct a wide input
  big_outport   shift writes to a single OUTPORT to construct a wide output
  big_outport   shift writes to a single OUTPORT to construct a wide output
  counter       counter for number of received high cycles from signal
  counter       counter for number of received high cycles from signal
  inFIFO_async  input FIFO with an asynchronous write clock
  inFIFO_async  input FIFO with an asynchronous write clock
  latch         latch wide inputs for sampling
  latch         latch wide inputs for sampling
  monitor_stack simulation diagnostic (see below)
  monitor_stack simulation diagnostic (see below)
  open_drain    for software-implemented I2C buses or similar
  open_drain    for software-implemented I2C buses or similar
  outFIFO_async output FIFO with an asynchronous read clock
  outFIFO_async output FIFO with an asynchronous read clock
  PWM_8bit      PWM generator with an 8-bit control
  PWM_8bit      PWM generator with an 8-bit control
 
  servo_motor   PWM modulation suitable for servo motor or similar control
 
  stepper_motor stepper motor controller with acceleration
  timer         timing for polled loops or similar
  timer         timing for polled loops or similar
  trace         simulation diagnostic (see below)
  trace         simulation diagnostic (see below)
  UART          bidirectional UART
  UART          bidirectional UART
  UART_Rx       receive UART
  UART_Rx       receive UART
  UART_Tx       transmit UART
  UART_Tx       transmit UART
  wide_strobe   1 to 8 bit strobe generator
  wide_strobe   1 to 8 bit strobe generator
The following command illustrates how to display the help message for
The following command illustrates how to display the help message for
peripherals:
peripherals:
  echo "ARCHITECTURE core/9x8 Verilog" | ssbcc -P "big_inport help" - | less
  echo "ARCHITECTURE core/9x8 Verilog" | ssbcc -P "big_inport help" - | less
User defined peripherals can be in the same directory as the architecture file
User defined peripherals can be in the same directory as the architecture file
or a subdirectory named "peripherals".
or a subdirectory named "peripherals".
PARAMETER and LOCALPARAM
PARAMETER and LOCALPARAM
================================================================================
================================================================================
Parameters are incorporated through the PARAMETER and LOCALPARAM configuration
Parameters are incorporated through the PARAMETER and LOCALPARAM configuration
commands.  For example, the clock frequency in hertz is needed for UARTs for
commands.  For example, the clock frequency in hertz is needed for UARTs for
their baud rate generator.  The configuration command
their baud rate generator.  The configuration command
  PARAMETER G_CLK_FREQ_HZ 97_000_000
  PARAMETER G_CLK_FREQ_HZ 97_000_000
specifies the clock frequency as 97 MHz.  The HDL instantiating the processor
specifies the clock frequency as 97 MHz.  The HDL instantiating the processor
can change this specification.  The frequency can also be changed through the
can change this specification.  The frequency can also be changed through the
command-line invocation of the computer compiler.  For example,
command-line invocation of the computer compiler.  For example,
  ssbcc -G "G_CLK_FREQ_HZ=100_000_000" myprogram.9x8
  ssbcc -G "G_CLK_FREQ_HZ=100_000_000" myprogram.9x8
specifies that a frequency of 100 MHz be used instead of the default frequency
specifies that a frequency of 100 MHz be used instead of the default frequency
of 97 MHz.
of 97 MHz.
The LOCALPARAM configuration command can be used to specify parameters that
The LOCALPARAM configuration command can be used to specify parameters that
should not be changed by the surrounding HDL.  For example,
should not be changed by the surrounding HDL.  For example,
  LOCALPARAM L_VERSION 24'h00_00_00
  LOCALPARAM L_VERSION 24'h00_00_00
specifies a 24-bit parameter named "L_VERSION".  The 8-bit major, minor, and
specifies a 24-bit parameter named "L_VERSION".  The 8-bit major, minor, and
build sections of the parameter can be accessed in an assembly program using
build sections of the parameter can be accessed in an assembly program using
"L_VERSION[16+:8]", "L_VERSION[8+:8]", and "L_VERSION[0+:8]".
"L_VERSION[16+:8]", "L_VERSION[8+:8]", and "L_VERSION[0+:8]".
For both parameters and localparams, the default range is "[0+:8]".  The
For both parameters and localparams, the default range is "[0+:8]".  The
instruction memory is initialized using the parameter value during synthesis,
instruction memory is initialized using the parameter value during synthesis,
not the value used to initialize the parameter.  That is, the instruction memory
not the value used to initialize the parameter.  That is, the instruction memory
initialization will be:
initialization will be:
  s_opcodeMemory[...] = { 1'b1, L_VERSION[16+:8] };
  s_opcodeMemory[...] = { 1'b1, L_VERSION[16+:8] };
The value of the localparam can be set when the computer compiler is run using
The value of the localparam can be set when the computer compiler is run using
the "-G" option.  For example,
the "-G" option.  For example,
  ssbcc -G "L_VERSION=24'h01_04_03" myprogram.9x8
  ssbcc -G "L_VERSION=24'h01_04_03" myprogram.9x8
can be used in a makefile to set the version number for a release without
can be used in a makefile to set the version number for a release without
modifying the micro controller architecture file.
modifying the micro controller architecture file.
DIAGNOSTICS AND DEBUGGING
DIAGNOSTICS AND DEBUGGING
================================================================================
================================================================================
A 3-character, human readable version of the opcode can be included in
A 3-character, human readable version of the opcode can be included in
simulation waveform outputs by adding "--display-opcode" to the ssbcc command.
simulation waveform outputs by adding "--display-opcode" to the ssbcc command.
The stack health can be monitored during simulation by including the
The stack health can be monitored during simulation by including the
"monitor_stack" peripheral through the command line.  For example, the LED
"monitor_stack" peripheral through the command line.  For example, the LED
flasher example can be generated using
flasher example can be generated using
  ssbcc -P monitor_stack led.9x8
  ssbcc -P monitor_stack led.9x8
This allows the architecture file to be unchanged between simulation and an FPGA
This allows the architecture file to be unchanged between simulation and an FPGA
build.
build.
Stack errors include underflow and overflow, malformed data validity, and
Stack errors include underflow and overflow, malformed data validity, and
incorrect use of the values on the return stack (returns to data values and data
incorrect use of the values on the return stack (returns to data values and data
operations on return addresses).  Other errors include out-of-range for memory,
operations on return addresses).  Other errors include out-of-range for memory,
inport, and outport operations.
inport, and outport operations.
When stack errors are detected the last 50 instructions are dumped to the
When stack errors are detected the last 50 instructions are dumped to the
console and the simulation terminates.  The dump includes the PC, numeric
console and the simulation terminates.  The dump includes the PC, numeric
opcode, textual representation of the opcode, data stack pointer, next-to-top of
opcode, textual representation of the opcode, data stack pointer, next-to-top of
the data stack, top of the data stack, top of the return stack, and the return
the data stack, top of the data stack, top of the return stack, and the return
stack pointer.  Invalid stack values are displayed as "XX".  The length of the
stack pointer.  Invalid stack values are displayed as "XX".  The length of the
history dumped is configurable.
history dumped is configurable.
Out-of-range PC checks are also performed if the instruction space is not a
Out-of-range PC checks are also performed if the instruction space is not a
power of 2.
power of 2.
A "trace" peripheral is also provided that dumps the entire execution history.
A "trace" peripheral is also provided that dumps the entire execution history.
This was used to validate the processor core.
This was used to validate the processor core.
MEMORY ARCHITECTURE
MEMORY ARCHITECTURE
================================================================================
================================================================================
The DATA_STACK, RETURN_STACK, INSTRUCTION, and MEMORY configuration commands
The DATA_STACK, RETURN_STACK, INSTRUCTION, and MEMORY configuration commands
allocate memory for the data stack, return stack, instruction ROM, and memory
allocate memory for the data stack, return stack, instruction ROM, and memory
RAM and ROM respectively.  The data stack, return stack, and memories are
RAM and ROM respectively.  The data stack, return stack, and memories are
normally instantiated as dual-port LUT-based memories with asynchronous reads
normally instantiated as dual-port LUT-based memories with asynchronous reads
while the instruction memory is always instantiated with a synchronous read
while the instruction memory is always instantiated with a synchronous read
architecture.
architecture.
The COMBINE configuration command is used to coalesce memories and to convert
The COMBINE configuration command is used to coalesce memories and to convert
LUT-based memories to synchronous SRAM-based memories.  For example, the large
LUT-based memories to synchronous SRAM-based memories.  For example, the large
SRAMs in modern FPGAs are ideal for storing the instruction opcodes and their
SRAMs in modern FPGAs are ideal for storing the instruction opcodes and their
dual-ported access allows either the data stack or the return stack to be
dual-ported access allows either the data stack or the return stack to be
stored in a relatively small region at the end of the large instruction memory.
stored in a relatively small region at the end of the large instruction memory.
Memories, which required dual-ported operation, can also be instantiated in
Memories, which required dual-ported operation, can also be instantiated in
large RAMs either individually or in combination with each other.  Conversion
large RAMs either individually or in combination with each other.  Conversion
to SRAM-based memories is also useful for FPGA architectures that do not have
to SRAM-based memories is also useful for FPGA architectures that do not have
efficient LUT-based memories.
efficient LUT-based memories.
The INSTRUCTION configuration allocates memory for the processor instruction
The INSTRUCTION configuration allocates memory for the processor instruction
space.  It has the form "INSTRUCTION N" or "INSTRUCTION N*M" where N must be a
space.  It has the form "INSTRUCTION N" or "INSTRUCTION N*M" where N must be a
power of 2.  The first form is used if the desired instruction memory size is a
power of 2.  The first form is used if the desired instruction memory size is a
power of 2.  The second form is used to allocate M memory blocks of size N
power of 2.  The second form is used to allocate M memory blocks of size N
where M is not a power of 2.  For example, on an Altera Cyclone III, the
where M is not a power of 2.  For example, on an Altera Cyclone III, the
configuration command "INSTRUCTION 1024*3" allocates three M9Ks for the
configuration command "INSTRUCTION 1024*3" allocates three M9Ks for the
instruction space, saving one M9K as compared to the configuration command
instruction space, saving one M9K as compared to the configuration command
"INSTRUCTION 4096".
"INSTRUCTION 4096".
The DATA_STACK configuration command allocates memory for the data stack.  It
The DATA_STACK configuration command allocates memory for the data stack.  It
has the form "DATA_STACK N" where N is the commanded size of the data stack.
has the form "DATA_STACK N" where N is the commanded size of the data stack.
N must be a power of 2.
N must be a power of 2.
The RETURN_STACK configuration command allocates memory for the return stack and
The RETURN_STACK configuration command allocates memory for the return stack and
has the same format as the DATA_STACK configuration command.
has the same format as the DATA_STACK configuration command.
The MEMORY configuration command is used to define one to four memories, either
The MEMORY configuration command is used to define one to four memories, either
RAM or ROM, with up to 256 bytes each.  If no MEMORY configuration command is
RAM or ROM, with up to 256 bytes each.  If no MEMORY configuration command is
issued, then no memories are allocated for the processor.  The MEMORY
issued, then no memories are allocated for the processor.  The MEMORY
configuration command has the format "MEMORY {RAM|ROM} name N" where
configuration command has the format "MEMORY {RAM|ROM} name N" where
"{RAM|ROM}" specifies either a RAM or a ROM, name is the name of the memory and
"{RAM|ROM}" specifies either a RAM or a ROM, name is the name of the memory and
must start with an alphabetic character, and the size of the memory, N, must be
must start with an alphabetic character, and the size of the memory, N, must be
a power of 2.  For example, "MEMORY RAM myram 64" allocates 64 bytes of memory
a power of 2.  For example, "MEMORY RAM myram 64" allocates 64 bytes of memory
to form a RAM named myram.  Similarly, "MEMORY ROM lut 256" defines a 256 byte
to form a RAM named myram.  Similarly, "MEMORY ROM lut 256" defines a 256 byte
ROM named lut.  More details on using memories is provided in the next section.
ROM named lut.  More details on using memories is provided in the next section.
The COMBINE configuration command can be used to combine the various memories
The COMBINE configuration command can be used to combine the various memories
for more efficient processor implementation as follows:
for more efficient processor implementation as follows:
  COMBINE INSTRUCTION,
  COMBINE INSTRUCTION,
  COMBINE 
  COMBINE 
  COMBINE ,
  COMBINE ,
  COMBINE 
  COMBINE 
where  is one of DATA_STACK, RETURN_STACK, or a list of one
where  is one of DATA_STACK, RETURN_STACK, or a list of one
or more ROMs and  is a list of one or more RAMs and/or ROMs.  The first
or more ROMs and  is a list of one or more RAMs and/or ROMs.  The first
configuration command reserves space at the end of the instruction memory for
configuration command reserves space at the end of the instruction memory for
the DATA_STACK, RETURN_STACK, or listed ROMs.
the DATA_STACK, RETURN_STACK, or listed ROMs.
The SRAM_WIDTH configuration command is used to make the memory allocations more
The SRAM_WIDTH configuration command is used to make the memory allocations more
efficient when the SRAM block width is more than 9 bits.  For example,
efficient when the SRAM block width is more than 9 bits.  For example,
Altera's Cyclone V family has 10-bit wide memory blocks and the configuration
Altera's Cyclone V family has 10-bit wide memory blocks and the configuration
command "SRAM_WIDTH 10" is appropriate.  The configuration command
command "SRAM_WIDTH 10" is appropriate.  The configuration command
sequence
sequence
  INSTRUCTION     1024
  INSTRUCTION     1024
  RETURN_STACK    32
  RETURN_STACK    32
  SRAM_WIDTH      10
  SRAM_WIDTH      10
  COMBINE         INSTRUCTION,RETURN_STACK
  COMBINE         INSTRUCTION,RETURN_STACK
will use a single 10-bit memory entry for each element of the return stack
will use a single 10-bit memory entry for each element of the return stack
instead of packing the 10-bit values into two memory entries of a 9-bit wide
instead of packing the 10-bit values into two memory entries of a 9-bit wide
memory.
memory.
The following illustrates a possible configuration for a Spartan-6 with a
The following illustrates a possible configuration for a Spartan-6 with a
2048-long SRAM and relatively large 64-deep data stack.  The data stack will be
2048-long SRAM and relatively large 64-deep data stack.  The data stack will be
in the last 64 elements of the instruction memory and the instruction space will
in the last 64 elements of the instruction memory and the instruction space will
be reduced to 1984 words.
be reduced to 1984 words.
  INSTRUCTION   2048
  INSTRUCTION   2048
  DATA_STACK    64
  DATA_STACK    64
  COMBINE       INSTRUCTION,DATA_STACK
  COMBINE       INSTRUCTION,DATA_STACK
The following illustrates a possible configuration for a Cyclone-III with three
The following illustrates a possible configuration for a Cyclone-III with three
M9Ks for the instruction ROM and the data stack.
M9Ks for the instruction ROM and the data stack.
  INSTRUCTION   1024*3
  INSTRUCTION   1024*3
  DATA_STACK    64
  DATA_STACK    64
  COMBINE       INSTRUCTION,DATA_STACK
  COMBINE       INSTRUCTION,DATA_STACK
WARNING:  Some devices, such as Xilinx' Spartan-3A devices, do not support
WARNING:  Some devices, such as Xilinx' Spartan-3A devices, do not support
asynchronous reads, so the COMBINE configuration command does not work for them.
asynchronous reads, so the COMBINE configuration command does not work for them.
WARNING:  Xilinx XST does not correctly infer a Block RAM when the
WARNING:  Xilinx XST does not correctly infer a Block RAM when the
"COMBINE INSTRUCTION,RETURN_STACK" configuration command is used and the
"COMBINE INSTRUCTION,RETURN_STACK" configuration command is used and the
instruction space is 1024 instructions or larger.  Xilinx is supposed to fix
instruction space is 1024 instructions or larger.  Xilinx is supposed to fix
this in a future release of Vivado so the fix will only apply to 7-series or
this in a future release of Vivado so the fix will only apply to 7-series or
later FPGAs.
later FPGAs.
MEMORY
MEMORY
================================================================================
================================================================================
The MEMORY configuration command is used as follows to allocate a 128-byte RAM
The MEMORY configuration command is used as follows to allocate a 128-byte RAM
named "myram" and to allocate a 32-byte ROM named "myrom".  Zero to four
named "myram" and to allocate a 32-byte ROM named "myrom".  Zero to four
memories can be allocated, each with up to 256 bytes.
memories can be allocated, each with up to 256 bytes.
  MEMORY RAM myram 128
  MEMORY RAM myram 128
  MEMORY ROM myrom  32
  MEMORY ROM myrom  32
The assembly code to lay out the memory uses the ".memory" directive to identify
The assembly code to lay out the memory uses the ".memory" directive to identify
the memory and the ".variable" directive to identify the symbol and its content.
the memory and the ".variable" directive to identify the symbol and its content.
Single or multiple values can be listed and "*N" can be used to identify a
Single or multiple values can be listed and "*N" can be used to identify a
repeat count.
repeat count.
  .memory RAM myram
  .memory RAM myram
  .variable a 0
  .variable a 0
  .variable b 0
  .variable b 0
  .variable c 0 0 0 0
  .variable c 0 0 0 0
  .variable d 0*4
  .variable d 0*4
  .memory ROM myrom
  .memory ROM myrom
  .variable coeff_table 0x04
  .variable coeff_table 0x04
                        0x08
                        0x08
                        0x10
                        0x10
                        0x20
                        0x20
  .variable hello_world N"Hello World!\r\n"
  .variable hello_world N"Hello World!\r\n"
Single values are fetched from or stored to memory using the following assembly:
Single values are fetched from or stored to memory using the following assembly:
  .fetchvalue(a)
  .fetchvalue(a)
  0x12 .storevalue(b)
  0x12 .storevalue(b)
Multi-byte values are fetched or stored as follows.  This copies the four values
Multi-byte values are fetched or stored as follows.  This copies the four values
from coeff_table, which is stored in a ROM, to d.
from coeff_table, which is stored in a ROM, to d.
  .fetchvector(coeff_table,4) .storevector(d,4)
  .fetchvector(coeff_table,4) .storevector(d,4)
The memory size is available using computed values (see below) and can be used
The memory size is available using computed values (see below) and can be used
to clear the entire memory, etc.
to clear the entire memory, etc.
The available single-cycle memory operation macros are:
The available single-cycle memory operation macros are:
  .fetch(mem_name)      replaces T with the value at the address T in the memory
  .fetch(mem_name)      replaces T with the value at the address T in the memory
                        mem_name
                        mem_name
                        Note:  .fetchram(var_name) is safer.
                        Note:  .fetchram(var_name) is safer.
  .fetch+(mem_name)     pushes the value at address T in the memory mem_name
  .fetch+(mem_name)     pushes the value at address T in the memory mem_name
                        into the data stack below T and increments T
                        into the data stack below T and increments T
                        Note:  This is useful for fetching successive values
                        Note:  This is useful for fetching successive values
                               from memory into the data stack.
                               from memory into the data stack.
                        Note:  .fetchram+(var_name) is safer.
                        Note:  .fetchram+(var_name) is safer.
  .fetch-(mem_name)     similar to .fetch+ but decrements T
  .fetch-(mem_name)     similar to .fetch+ but decrements T
                        Note:  .fetchram-(var_name) is safer.
                        Note:  .fetchram-(var_name) is safer.
  .store(ram_name)      stores N at address T in the RAM ram_name, also drops
  .store(ram_name)      stores N at address T in the RAM ram_name, also drops
                        the top of the data stack
                        the top of the data stack
                        Note:  .storeram(var_name) is safer.
                        Note:  .storeram(var_name) is safer.
  .store+(ram_name)     stores N at address T in the RAM ram_name, also drops N
  .store+(ram_name)     stores N at address T in the RAM ram_name, also drops N
                        from the data stack and increments T
                        from the data stack and increments T
                        Note:  .storeram+(var_name) is safer.
                        Note:  .storeram+(var_name) is safer.
  .store-(ram_name)     similar to .store+ but decrements T
  .store-(ram_name)     similar to .store+ but decrements T
                        Note:  .storeram-(var_name) is safer.
                        Note:  .storeram-(var_name) is safer.
The following multi-cycle macros provide more generalized access to the
The following multi-cycle macros provide more generalized access to the
memories:
memories:
  .fetchindexed(var_name)
  .fetchindexed(var_name)
                        uses the top of the data stack as an index into var_name
                        uses the top of the data stack as an index into var_name
                        Note:  This is equivalent to the 3 instruction sequence
                        Note:  This is equivalent to the 3 instruction sequence
                               "var_name + .fetch(mem_name)"
                               "var_name + .fetch(mem_name)"
  .fetchoffset(var_name,offset)
  .fetchoffset(var_name,offset)
                        fetches the single-byte value of var_name offset by
                        fetches the single-byte value of var_name offset by
                        "offset" bytes
                        "offset" bytes
                        Note:  This is equivalent to
                        Note:  This is equivalent to
                               "${var_name+offset} .fetch(mem_name)"
                               "${var_name+offset} .fetch(mem_name)"
  .fetchram(var_name)   is similar to the .fetch(mem_name) macro except that the
  .fetchram(var_name)   is similar to the .fetch(mem_name) macro except that the
                        variable name is used to identify the memory instead of
                        variable name is used to identify the memory instead of
                        the name of the memory
                        the name of the memory
  .fetchram+(var_name)  is similar to the .fetch+(mem_name) macro except that
  .fetchram+(var_name)  is similar to the .fetch+(mem_name) macro except that
                        the variable name is used to identify the memory instead
                        the variable name is used to identify the memory instead
                        of the name of the memory
                        of the name of the memory
  .fetchram-(var_name)  is similar to the .fetch-(mem_name) macro except that the
  .fetchram-(var_name)  is similar to the .fetch-(mem_name) macro except that the
                        the variable name is used to identify the memory instead
                        the variable name is used to identify the memory instead
                        of the name of the memory
                        of the name of the memory
  .fetchvalue(var_name) fetches the single-byte value of var_name
  .fetchvalue(var_name) fetches the single-byte value of var_name
                        Note:  This is equivalent to "var_name .fetch(mem_name)"
                        Note:  This is equivalent to "var_name .fetch(mem_name)"
                               where mem_name is the memory in which var_name is
                               where mem_name is the memory in which var_name is
                               stored.
                               stored.
  .fetchvalueoffset(var_name,offset)
  .fetchvalueoffset(var_name,offset)
                        fetches the single-byte value stored at var_name+offset
                        fetches the single-byte value stored at var_name+offset
                        Note:  This is equivalent to
                        Note:  This is equivalent to
                               "${var_name+offset}" .fetch(mem_name)
                               "${var_name+offset}" .fetch(mem_name)
                               where mem_name is the memory in which var_name is
                               where mem_name is the memory in which var_name is
                               stored.
                               stored.
  .fetchvector(var_name,N)
  .fetchvector(var_name,N)
                        fetches N values starting at var_name into the data
                        fetches N values starting at var_name into the data
                        stack with the value at var_name at the top and the
                        stack with the value at var_name at the top and the
                        value at var_name+N-1 deep in the stack.
                        value at var_name+N-1 deep in the stack.
                        Note:  This is equivalent N+1 operation sequence
                        Note:  This is equivalent N+1 operation sequence
                               "${var_name+N-1} .fetch-(mem_name) ...
                               "${var_name+N-1} .fetch-(mem_name) ...
                               .fetch-(mem_name) .fetch(mem_name)"
                               .fetch-(mem_name) .fetch(mem_name)"
                               where ".fetch-(mem_name)" is repeated N-1 times.
                               where ".fetch-(mem_name)" is repeated N-1 times.
  .storeindexed(var_name)
  .storeindexed(var_name)
                        uses the top of the data stack as an index into var_name
                        uses the top of the data stack as an index into var_name
                        into which to store the next-to-top of the data stack.
                        into which to store the next-to-top of the data stack.
                        Note:  This is equivalent to the 4 instruction sequence
                        Note:  This is equivalent to the 4 instruction sequence
                               "var_name + .store(mem_name) drop".
                               "var_name + .store(mem_name) drop".
                        Note:  The default "drop" instruction can be overriden
                        Note:  The default "drop" instruction can be overriden
                               by providing the optional second argument
                               by providing the optional second argument
                               similarly to the .storevalue macro.
                               similarly to the .storevalue macro.
  .storeoffset(var_name,offset)
  .storeoffset(var_name,offset)
                        stores the single-byte value at the top of the data
                        stores the single-byte value at the top of the data
                        stack at var_name offset by "offset" bytes
                        stack at var_name offset by "offset" bytes
                        Note:  This is equivalent to
                        Note:  This is equivalent to
                               "${var_name+offset} .store(mem_name) drop"
                               "${var_name+offset} .store(mem_name) drop"
                        Note:  The optional third argument is as per the
                        Note:  The optional third argument is as per the
                               optional second argument of .storevalue
                               optional second argument of .storevalue
  .storeram(var_name)   is similar to the .store(mem_name) macro except that the
  .storeram(var_name)   is similar to the .store(mem_name) macro except that the
                        variable name is used to identify the RAM instead of the
                        variable name is used to identify the RAM instead of the
                        name of the RAM
                        name of the RAM
  .storeram+(var_name)  is similar to the .store+(mem_name) macro except that
  .storeram+(var_name)  is similar to the .store+(mem_name) macro except that
                        the variable name is used to identify the RAM instead of
                        the variable name is used to identify the RAM instead of
                        the name of the RAM
                        the name of the RAM
  .storeram-(var_name)  is similar to the .store-(mem_name) macro except that
  .storeram-(var_name)  is similar to the .store-(mem_name) macro except that
                        the variable name is used to identify the RAM instead of
                        the variable name is used to identify the RAM instead of
                        the name of the RAM
                        the name of the RAM
  .storevalue(var_name) stores the single-byte value at the top of the data
  .storevalue(var_name) stores the single-byte value at the top of the data
                        stack at var_name
                        stack at var_name
                        Note:  This is equivalent to
                        Note:  This is equivalent to
                               "var_name .store(mem_name) drop"
                               "var_name .store(mem_name) drop"
                        Note:  The default "drop" instruction can be replaced by
                        Note:  The default "drop" instruction can be replaced by
                               providing the optional second argument.  For
                               providing the optional second argument.  For
                               example, the following instruction will store and
                               example, the following instruction will store and
                               then decrement the value at the top of the data
                               then decrement the value at the top of the data
                               stack:
                               stack:
                                 .storevalue(var_name,1-)
                                 .storevalue(var_name,1-)
  .storevector(var_name,N)
  .storevector(var_name,N)
                        Does the reverse of the .fetchvector macro.
                        Does the reverse of the .fetchvector macro.
                        Note:  This is equivalent to the N+2 operation sequence
                        Note:  This is equivalent to the N+2 operation sequence
                               "var_name .store+(mem_name) ... .store+(mem_name)
                               "var_name .store+(mem_name) ... .store+(mem_name)
                               .store(mem_name) drop"
                               .store(mem_name) drop"
                               where ".store+(mem_name)" is repeated N-1 times.
                               where ".store+(mem_name)" is repeated N-1 times.
The .fetchvector and .storevector macros are intended to work with values stored
The .fetchvector and .storevector macros are intended to work with values stored
MSB first in memory and with the MSB toward the top of the data stack,
MSB first in memory and with the MSB toward the top of the data stack,
similarly to the Forth language with multi-word values.  To demonstrate how
similarly to the Forth language with multi-word values.  To demonstrate how
this data structure works, consider the examples of decrementing and
this data structure works, consider the examples of decrementing and
incrementing a two-byte value on the data stack:
incrementing a two-byte value on the data stack:
  ; Decrement a 2-byte value
  ; Decrement a 2-byte value
  ;   swap 1- swap      - decrement the LSB
  ;   swap 1- swap      - decrement the LSB
  ;   over -1=          - puts -1 on the top of the data stack if the LSB rolled
  ;   over -1=          - puts -1 on the top of the data stack if the LSB rolled
  ;                       over from 0 to -1, puts 0 on the top otherwise
  ;                       over from 0 to -1, puts 0 on the top otherwise
  ;   +                 - decrements the MSB if the LSB rolled over
  ;   +                 - decrements the MSB if the LSB rolled over
  ; ( u_LSB u_MSB - u_LSB' u_MSB' )
  ; ( u_LSB u_MSB - u_LSB' u_MSB' )
  .function decrement_2byte
  .function decrement_2byte
  swap 1- swap over -1= .return(+)
  swap 1- swap over -1= .return(+)
  ; Increment a 2-byte value
  ; Increment a 2-byte value
  ;   swap 1+ swap      - increment the LSB
  ;   swap 1+ swap      - increment the LSB
  ;   over 0=           - puts -1 on the top of the data stack if the LSB rolled
  ;   over 0=           - puts -1 on the top of the data stack if the LSB rolled
  ;                       over from 0xFF to 0, puts 0 on the top otherwise
  ;                       over from 0xFF to 0, puts 0 on the top otherwise
  ;   -                 - increments the MSB if the LSB rolled over (by
  ;   -                 - increments the MSB if the LSB rolled over (by
  ;                       subtracting -1)
  ;                       subtracting -1)
  ; ( u_LSB u_MSB - u_LSB' u_MSB' )
  ; ( u_LSB u_MSB - u_LSB' u_MSB' )
  .function increment_2byte
  .function increment_2byte
  swap 1+ swap over 0= .return(-)
  swap 1+ swap over 0= .return(-)
COMPUTED VALUES
COMPUTED VALUES
================================================================================
================================================================================
Computed values can be pushed on the stack using a "${...}" where the "..." is
Computed values can be pushed on the stack using a "${...}" where the "..." is
evaluated in Python and cannot have any spaces.
evaluated in Python and cannot have any spaces.
For example, a loop that should be run 5 times can be coded as:
For example, a loop that should be run 5 times can be coded as:
  ${5-1} :loop ... .jumpc(loop,1-) drop
  ${5-1} :loop ... .jumpc(loop,1-) drop
which is a clearer indication that the loop is to be run 5 times than is the
which is a clearer indication that the loop is to be run 5 times than is the
instruction sequence
instruction sequence
  4 :loop ...
  4 :loop ...
Constants can be accessed in the computation.  For example, a block of memory
Constants can be accessed in the computation.  For example, a block of memory
can be allocated as follows:
can be allocated as follows:
  .constant C_RESERVE
  .constant C_RESERVE
  .memory RAM myram
  .memory RAM myram
  ...
  ...
  .variable reserved 0*${C_RESERVE}
  .variable reserved 0*${C_RESERVE}
and the block of reserved memory can be cleared using the following loop:
and the block of reserved memory can be cleared using the following loop:
  ${C_RESERVE-1} :loop 0 over .storeindexed(reserved) .jumpc(loop,1-) drop
  ${C_RESERVE-1} :loop 0 over .storeindexed(reserved) .jumpc(loop,1-) drop
The offsets of variables in their memory can also be accessed through a computed
The offsets of variables in their memory can also be accessed through a computed
value.  The value of reserved could also be cleared as follows:
value.  The value of reserved could also be cleared as follows:
  ${reserved-1} ${C_RESERVE-1} :loop >r
  ${reserved-1} ${C_RESERVE-1} :loop >r
    0 swap .store-(myram)
    0 swap .store-(myram)
  r> .jumpc(loop,-1) drop drop
  r> .jumpc(loop,-1) drop drop
This body of this version of the loop is the same length as the first version.
This body of this version of the loop is the same length as the first version.
In general, it is better to use the memory macros to access variables as they
In general, it is better to use the memory macros to access variables as they
ensure the correct memory is accessed.
ensure the correct memory is accessed.
The sizes of memories can also be accessed using computed values.  If "myram" is
The sizes of memories can also be accessed using computed values.  If "myram" is
a RAM, then "${size['myram']}" will push the size of "myram" on the stack.  As
a RAM, then "${size['myram']}" will push the size of "myram" on the stack.  As
an example, the following code will clear the entire RAM:
an example, the following code will clear the entire RAM:
  ${size['myram']-1} :loop 0 swap .jumpc(loop,.store-(myram)) drop
  ${size['myram']-1} :loop 0 swap .jumpc(loop,.store-(myram)) drop
The lengths of I/O signals can also be accessed using computed values.  If
The lengths of I/O signals can also be accessed using computed values.  If
"o_mask" is a mask, then "${size['o_mask']}" will push the size of the mask on
"o_mask" is a mask, then "${size['o_mask']}" will push the size of the mask on
the stack and "${2**size['o_mask']-1}" will push a value that sets all the bits
the stack and "${2**size['o_mask']-1}" will push a value that sets all the bits
of the mask.  The I/O signals include I/O signals instantiated by peripherals.
of the mask.  The I/O signals include I/O signals instantiated by peripherals.
For example, for the configuration command
For example, for the configuration command
  PERIPHERAL big_outport outport=O_BIG outsignal=o_big width=47
  PERIPHERAL big_outport outport=O_BIG outsignal=o_big width=47
the width of the output signal is accessible using "${size['o_big']}".  You can
the width of the output signal is accessible using "${size['o_big']}".  You can
set the wide signal to all zeroes using:
set the wide signal to all zeroes using:
  ${(size['o_big']+7)/8-1} :loop 0 .outport(O_BIG) .jumpc(loop,1-) drop
  ${(size['o_big']+7)/8-1} :loop 0 .outport(O_BIG) .jumpc(loop,1-) drop
MACROS
MACROS
================================================================================
================================================================================
 
 
There are 3 types of macros used by the assembler.
There are 3 types of macros used by the assembler.
The first kind of macros are built in to the assembler and are required to
The first kind of macros are built in to the assembler and are required to
encode instructions that have embedded values or have mandatory subsequent
encode instructions that have embedded values or have mandatory subsequent
instructions.  These include function calls, jump instructions, function return,
instructions.  These include function calls, jump instructions, function return,
and memory accesses as follows:
and memory accesses as follows:
  .call(function,[op])
  .call(function,[op])
  .callc(function,[op])
  .callc(function,[op])
  .fetch(ramName)
  .fetch(ramName)
  .fetch+(ramName)
  .fetch+(ramName)
  .fetch-(ramName)
  .fetch-(ramName)
  .jump(label,[op])
  .jump(label,[op])
  .jumpc(label,[op])
  .jumpc(label,[op])
  .return([op])
  .return([op])
  .store(ramName)
  .store(ramName)
  .store+(ramName)
  .store+(ramName)
  .store-(ramName)
  .store-(ramName)
The second kind of macros are designed to ease access to input and output
The second kind of macros are designed to ease access to input and output
operations and for memory accesses and to help ensure these operations are
operations and for memory accesses and to help ensure these operations are
correctly constructed.  These are defined as python scripts in the
correctly constructed.  These are defined as python scripts in the
core/9x8/macros directory and are automatically loaded into the assembler.
core/9x8/macros directory and are automatically loaded into the assembler.
These macros are:
These macros are:
  .fetchindexed(variable)
  .fetchindexed(variable)
  .fetchoffset(variable,ix)
  .fetchoffset(variable,ix)
  .fetchvalue(variableName)
  .fetchvalue(variableName)
  .fetchvector(variableName,N)
  .fetchvector(variableName,N)
  .inport(I_name)
  .inport(I_name)
  .outport(O_name[,op])
  .outport(O_name[,op])
  .outstrobe(O_name)
  .outstrobe(O_name)
  .storeindexed(variableName[,op])
  .storeindexed(variableName[,op])
  .storeoffset(variableName,ix[,op])
  .storeoffset(variableName,ix[,op])
  .storevalue(variableName[,op])
  .storevalue(variableName[,op])
  .storevector(variableName,N)
  .storevector(variableName,N)
The third kind of macro is user-defined macros.  These macros must be registered
The third kind of macro is user-defined macros.  These macros must be registered
with the assembler using the ".macro" directive.
with the assembler using the ".macro" directive.
For example, the ".push32" macro is defined by macros/9x8/push32.py and can be
For example, the ".push32" macro is defined by macros/9x8/push32.py and can be
used to push 32-bit (4-byte) values onto the data stack as follows:
used to push 32-bit (4-byte) values onto the data stack as follows:
  .macro push32
  .macro push32
  .constant C_X 0x87654321
  .constant C_X 0x87654321
  .main
  .main
    ...
    ...
    .push32(0x12345678)
    .push32(0x12345678)
    .push32(C_X)
    .push32(C_X)
    .push32(${0x12345678^C_X})
    .push32(${0x12345678^C_X})
    ...
    ...
The following macros are provided in macros/9x8:
The following macros are provided in macros/9x8:
  .push16(v)    push the 16-bit (2-byte) value "v" onto the data stack with the
  .push16(v)    push the 16-bit (2-byte) value "v" onto the data stack with the
                MSB at the top of the data stack
                MSB at the top of the data stack
  .push24(v)    push the 24-bit (3-byte) value "v" onto the data stack with the
  .push24(v)    push the 24-bit (3-byte) value "v" onto the data stack with the
                MSB at the top of the data stack
                MSB at the top of the data stack
  .push32(v)    push the 32-bit (4-byte) value "v" onto the data stack with the
  .push32(v)    push the 32-bit (4-byte) value "v" onto the data stack with the
                MSB at the top of the data stack
                MSB at the top of the data stack
  .pushByte(v,ix)
  .pushByte(v,ix)
                push the ix'th byte of v onto the data stack
                push the ix'th byte of v onto the data stack
                Note:  ix=0 designates the LSB
                Note:  ix=0 designates the LSB
Directories are searched in the following order for macros:
Directories are searched in the following order for macros:
  .
  .
  ./macros
  ./macros
  include paths specified by the '-M' command line option.
  include paths specified by the '-M' command line option.
  macros/9x8
  macros/9x8
The python scripts in core/9x8/macros and macros/9x8 can be used as design
The python scripts in core/9x8/macros and macros/9x8 can be used as design
examples for user-defined macros.  The assembler does some type checking based
examples for user-defined macros.  The assembler does some type checking based
on the list provided when the macro is registered by the "AddMacro" method, but
on the list provided when the macro is registered by the "AddMacro" method, but
additional type checking is often warranted by the macro "emitFunction" which
additional type checking is often warranted by the macro "emitFunction" which
emits the actual assembly code.  The ".fetchvector" and ".storevector" macros
emits the actual assembly code.  The ".fetchvector" and ".storevector" macros
demonstrates how to design variable-length macros.  Several macros in
demonstrates how to design variable-length macros.  Several macros in
core/9x8/macros illustrate designing macros with optional arguments.
core/9x8/macros illustrate designing macros with optional arguments.
It is not an error to repeat the ".macro MACRO_NAME" directive for user-defined
It is not an error to repeat the ".macro MACRO_NAME" directive for user-defined
macros.  The assembler will issue a fatal error if a user-defined macro
macros.  The assembler will issue a fatal error if a user-defined macro
conflicts with a built-in macro.
conflicts with a built-in macro.
CONDITIONAL COMPILATION
CONDITIONAL COMPILATION
================================================================================
================================================================================
The computer compiler and assembler recognize conditional compilation as
 
follows:  .IFDEF, .IFNDEF, .ELSE, and .ENDIF can be used in the architecture
 
file and they can be used to conditionally include functions, files, etc within
 
the assembly code; .ifdef, .ifndef, .else, and .endif can be used in function
 
bodies, variable bodies, etc. to conditionally include assembly code, symbols,
 
or data.  Conditionals cannot cross file boundaries.
 
 
 
The computer compiler examines the list of defined symbols such as I/O ports,
 
I/O signals, etc. to evaluate the true/false condition associated with the
 
.IFDEF and .IFNDEF commands.  The "-D" option to the computer compiler is
 
provided to define symbols for enabling conditionally compiled configuration
 
commands.  Similarly, the assembler examines the list of I/O ports, I/O signals,
 
parameters, constants, etc. to evaluate the .IFDEF, .IFNDEF, .ifdef, and .ifndef
 
conditionals.
 
 
 
For example, a diagnostic UART can be conditionally included using the
Conditional compilation is accepted in the architecture file and in the assembly
configuration commands:
source files and is based on whether or not the referenced symbol is defined.
 
 
 
In the architecture file, symbols are defined by CONSTANT, INPORT, OUTPORT, and
 
PERIPHERAL statements, or by the "-D D_name" argument to ssbcc.  The line
 
 
 
  .IFDEF name
 
  
 
  .ENDIF
 
 
 
will then include the lines "" if the symbol "name" is defined.
 
The ".IFNDEF" command is similar except that the statements included if the
 
symbol is not defined.  A ".ELSE" is also provided.
 
 
 
In an assembly file directives are conditionally included using the .IFDEF and
 
.IFNDEF directives, an optional .ELSE directive, and the terminating .ENDIF
 
directive.  Note that this is done at the directive level, i.e. function
 
declarations, memory declarations, and so forth.  Within a function code is
 
conditionally included starting with a ".ifdef(name)" or a ".ifndef(name)", an
 
optional ".else" and a terminating ".endif".
 
 
 
For example, a diagnostic UART can be conditionally included in a program by
 
including the following lines in the architecture file:
 
 
  .IFDEF ENABLE_UART
  .IFDEF D_ENABLE_UART
  PORTCOMMENT Diagnostic UART
  PORTCOMMENT Diagnostic UART
  PERIPHERAL UART_Tx outport=O_UART_TX ...
  PERIPHERAL UART_Tx outport=O_UART_TX ...
  .ENDIF
  .ENDIF
 
 
And the assembly code can include conditional code fragments such the following,
A "uart_tx" function can be optionally created using code similar to the
where the existence of the output port is used to determine whether or not to
following.  Note that the symbol for the .outport macro is used to determine
send a character to that output port:
whether or not the function is defined since that is more closely related to
 
whether or not the function can be defined.  The function definition must
  .ifdef(O_UART_TX) 'A' .outport(O_UART_TX) .endif
preceed any ".ifdef(uart_tx)" conditionals used to output diagnostics.
 
 
Invoking the computer compiler with "-D ENABLE_UART" will generate a module with
  .IFDEF O_UART_TX
the UART peripheral and will enable the conditional code sending the 'A'
  .function uart_tx
character to the UART port.
    :loop .outport(O_UART_TX) .jumpc(loop,nop) .return(drop)
 
  .ENDIF
 
 
 
Diagnostics in the assembly code can be included using either
 
 
 
  .ifdef(D_ENABLE_UART) N"Msg\r\n" .call(uart_tx) .endif
 
 
 
or
 
 
 
  .ifdef(uart_tx) N"Msg\r\n" .call(uart_tx) .endif
 
 
 
Conditional compilation cannot cross file boundaries.
 
 
 
The assembler also recognizes the ".define" directive.  For example, specific
 
diagnostics could be enabled if the UART is instantiated as follows:
 
 
 
  .IFDEF O_UART_TX
 
  .define D_DEBUG_FUNCTION_A
 
  .ENDIF
 
 
 
  ...
 
 
 
  .ifdef(D_DEBUG_FUNCTION_A) N"Debug Msg\r\n" .call(uart_tx) .endif
 
 
The following code can be used to preclude multiple attempted inclusions of an
The following code illustrates how to preclude multiple attempted inclusions of
assembly library file.
an assembly library file.
 
 
  ; put these two lines near the top of the file
  ; put these two lines near the top of the file
  .IFNDEF C_FILENAME_INCLUDED
  .IFNDEF D_FILENAME_INCLUDED
  .constant C_FILENAME_INCLUDED 1
  .define D_FILENAME_INCLUDED
  ; put the library body here
  ; put the library body here
  ...
  ...
  ; put this line at the bottom of the file
  ; put this line at the bottom of the file
  .ENDIF ; .IFNDEF C_FILENAME_INCLUDED
  .ENDIF ; .IFNDEF D_FILENAME_INCLUDED
 
 
The ".INCLUDE" configuration command can be used to read configuration commands
The ".INCLUDE" configuration command can be used to read configuration commands
from additional sources.
from additional sources.  For example, the following code will conditionally
 
include a general UART library if the outport O_UART_TX is defined:
 
 
 
  .IFDEF O_UART_TX
 
  .INCLUDE uart.s
 
  .ENDIF
 
 
SIMULATIONS
SIMULATIONS
================================================================================
================================================================================
Simulations have been performed with Icarus Verilog, Verilator, and Xilinx'
Simulations have been performed with Icarus Verilog, Verilator, and Xilinx'
ISIM.  Icarus Verilog is good for short, simple simulations and is used for the
ISIM.  Icarus Verilog is good for short, simple simulations and is used for the
core and peripheral test benches; Verilator for long simulations of large,
core and peripheral test benches; Verilator for long simulations of large,
complex systems; and ISIM when Xilinx-specific cores are used.  Verilator is
complex systems; and ISIM when Xilinx-specific cores are used.  Verilator is
the fastest simulators I've encountered.  Verilator is also used for lint
the fastest simulators I've encountered.  Verilator is also used for lint
checking in the core test benches.
checking in the core test benches.
MEM INITIALIZATION FILE
MEM INITIALIZATION FILE
================================================================================
================================================================================
A memory initialization file is produced during compilation.  This file can be
A memory initialization file is produced during compilation.  This file can be
used with tools such as Xilinx' data2mem to modify the SRAM contents without
used with tools such as Xilinx' data2mem to modify the SRAM contents without
having to rebuild the entire system.  It is restricted to the opcode memory
having to rebuild the entire system.  It is restricted to the opcode memory
initialization.  The file must be processed before it can be used by specific
initialization.  The file must be processed before it can be used by specific
tools, see doc/MemoryInitialization.html.
tools, see doc/MemoryInitialization.html.
WARNING:  The values of parameters used in the assembly code must match the
WARNING:  The values of parameters used in the assembly code must match the
instantiated design.
instantiated design.
THEORY OF OPERATION
THEORY OF OPERATION
================================================================================
================================================================================
Registers are used for the top of data stack, "T", and the next-to-top of the
Registers are used for the top of data stack, "T", and the next-to-top of the
data stack, "N".  The data stack is a separate memory.  This means that the
data stack, "N".  The data stack is a separate memory.  This means that the
"DATA_STACK N" configuration command actually allows N+2 values in the data
"DATA_STACK N" configuration command actually allows N+2 values in the data
stack since T and N are not stored in the N-element deep data stack.
stack since T and N are not stored in the N-element deep data stack.
The return stack is similar in that "R" is the top of the return stack and the
The return stack is similar in that "R" is the top of the return stack and the
"RETURN_STACK N" allocates an additional N words of memory.  The return stack is
"RETURN_STACK N" allocates an additional N words of memory.  The return stack is
the wider of the 8-bit data width and the program counter width.
the wider of the 8-bit data width and the program counter width.
The program counter is always either incremented by 1 or is set to an address
The program counter is always either incremented by 1 or is set to an address
as controlled by jump, jumpc, call, callc, and return instructions.  The
as controlled by jump, jumpc, call, callc, and return instructions.  The
registered program counter is used to read the next opcode from the instruction
registered program counter is used to read the next opcode from the instruction
memory and this opcode is also registered in the memory.  This means that there
memory and this opcode is also registered in the memory.  This means that there
is a 1 clock cycle delay between the address changing and the associated
is a 1 clock cycle delay between the address changing and the associated
instruction being performed.  This is also part of the architecture required to
instruction being performed.  This is also part of the architecture required to
have the processor operate at one instruction per clock cycle.
have the processor operate at one instruction per clock cycle.
Separate ALUs are used for the program counter, adders, logical operations, etc.
Separate ALUs are used for the program counter, adders, logical operations, etc.
and MUXes are used to select the values desired for the destination registers.
and MUXes are used to select the values desired for the destination registers.
The instruction execution consists of translating the upper 6 msb of the opcode
The instruction execution consists of translating the upper 6 msb of the opcode
into MUX settings and performing opcode-dependent ALU operations as controlled
into MUX settings and performing opcode-dependent ALU operations as controlled
by the 3 lsb of the opcode (during the first half of the clock cycle) and then
by the 3 lsb of the opcode (during the first half of the clock cycle) and then
setting the T, N, R, memories, etc. as controlled by the computed MUX settings.
setting the T, N, R, memories, etc. as controlled by the computed MUX settings.
The "core.v" file is the code for these operations.  Within this file there are
The "core.v" file is the code for these operations.  Within this file there are
several "@xxx@" strings that specify where the computer compiler is to insert
several "@xxx@" strings that specify where the computer compiler is to insert
code such as I/O declarations, memories, inport interpretation, outport
code such as I/O declarations, memories, inport interpretation, outport
generation, peripherals, etc.
generation, peripherals, etc.
The file structure, i.e., putting the core and the assembler in "core/9x8"
The file structure, i.e., putting the core and the assembler in "core/9x8"
should facilitate application-specific modification of processor.  For example,
should facilitate application-specific modification of processor.  For example,
the store+, store-, fetch+, and fetch- instructions could be replaced with
the store+, store-, fetch+, and fetch- instructions could be replaced with
additional stack manipulation operations, arithmetic operations with 2 byte
additional stack manipulation operations, arithmetic operations with 2 byte
results, etc.  Simply copy the "9x8" directory to something like "9x8_XXX" and
results, etc.  Simply copy the "9x8" directory to something like "9x8_XXX" and
make your modifications in that directory.  The 8-bit peripherals should still
make your modifications in that directory.  The 8-bit peripherals should still
work, but the 9x8 library functions may need rework to accommodate the
work, but the 9x8 library functions may need rework to accommodate the
modifications.
modifications.
MISCELLANEOUS
MISCELLANEOUS
================================================================================
================================================================================
Features and peripherals are still being added and the documentation is
Features and peripherals are still being added and the documentation is
incomplete.  The output HDL is currently restricted to Verilog although a VHDL
incomplete.  The output HDL is currently restricted to Verilog although a VHDL
package file is automatically generated by the computer compiler.
package file is automatically generated by the computer compiler.
The "INVERT_RESET" configuration command is used to indicate an active-low reset
The "INVERT_RESET" configuration command is used to indicate an active-low reset
is input to the micro controller rather than an active-high reset.
is input to the micro controller rather than an active-high reset.
 
 
A VHDL package file is automatically generated by the computer compiler.
 
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.