Upload of completed j1eforth for FOMU in verilog

This commit is contained in:
rob-ng15 2020-09-25 11:01:36 +01:00
parent d7119d0719
commit cccaf76e71
38 changed files with 10780 additions and 0 deletions

BIN
docs/j1eforth-verilog.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

351
docs/j1eforth.rst Normal file
View File

@ -0,0 +1,351 @@
Verilog-Playground
==================
My Verilog Coding Experimental Area
j1eforth-verilog for FOMU
-------------------------
Translation of the j1eforth interactive Forth environment for FOMU
(https://www.crowdsupply.com/sutajio-kosagi/fomu with documentation at
https://workshop.fomu.im/en/latest/) translated from Silice to Verilog.
The original J1 CPU (https://www.excamera.com/sphinx/fpga-j1.html with a
very clear explanatory paper at https://www.excamera.com/files/j1.pdf)
along with the j1eforth interactive Forth environment
(https://github.com/samawati/j1eforth) was written for an FPGA with
access to 16384 x 16bit (256kbit) dual port single cycle block ram,
whereas the FOMU has 120kbit of block ram. It does however have 1024kbit
of single port ram (65536 x 16bit), which is more than sufficient for
j1eforth, but it has 2 cycle latency.
j1eforth for FOMU was originally coded in Silice
(https://github.com/sylefeb/Silice) due to my limited (i.e. NO) FPGA
programming experience. Silice provides a nice introduction to FPGA
programming for those coming from more tradition software coding. Once
this design was working, especially the timings to access the single
port ram, I translated it back to verilog, as an educational experience
for myself.
Ive, in my opinion, tidied up the code, to make the variables more
explanatory, and to aid my coding.
For communicating via a terminal the tinyfpga_bx_usbserial
(https://github.com/stef/nb-fomu-hw) was implemented to provide a 115200
baud UART. A 32 character input and output buffer was added.
Using j1eforth-verilog on the FOMU
----------------------------------
Download the source code from this repository. Ensure that you have the
required toolchain installed. Compile (on Linux) with
``./fomu_hacker_USB_SPRAM.sh`` within the source directory.
Or download the precompiled ``j1eforth-verilog-FOMU.dfu`` file from this repository.
Upload the compiled, or downloaded bitstream to your FOMU with
``dfu-util -D build.dfu`` or ``dfu-util -D j1eforth-verilog-FOMU.dfu`` and connect via your chosen terminal, for
minicom ``minicom -D /dev/ttyACM0`` (ACM0 may need replacing with an
appropriate number on your machine).
Resources on the FOMU
---------------------
Resource usage:
::
Info: Device utilisation:
Info: ICESTORM_LC: 2612/ 5280 49%
Info: ICESTORM_RAM: 19/ 30 63%
Info: SB_IO: 12/ 96 12%
Info: SB_GB: 8/ 8 100%
Info: ICESTORM_PLL: 0/ 1 0%
Info: SB_WARMBOOT: 0/ 1 0%
Info: ICESTORM_DSP: 0/ 8 0%
Info: ICESTORM_HFOSC: 0/ 1 0%
Info: ICESTORM_LFOSC: 0/ 1 0%
Info: SB_I2C: 0/ 2 0%
Info: SB_SPI: 0/ 2 0%
Info: IO_I3C: 0/ 2 0%
Info: SB_LEDDA_IP: 0/ 1 0%
Info: SB_RGBA_DRV: 1/ 1 100%
Info: ICESTORM_SPRAM: 4/ 4 100%
// Timing estimate: 36.89 ns (27.11 MHz)
The original J1 CPU has this instruction encoding:
::
+---------------------------------------------------------------+
| F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---------------------------------------------------------------+
| 1 | LITERAL VALUE |
+---------------------------------------------------------------+
| 0 | 0 | 0 | BRANCH TARGET ADDRESS |
+---------------------------------------------------------------+
| 0 | 0 | 1 | CONDITIONAL BRANCH TARGET ADDRESS |
+---------------------------------------------------------------+
| 0 | 1 | 0 | CALL TARGET ADDRESS |
+---------------------------------------------------------------+
| 0 | 1 | 1 |R2P| ALU OPERATION |T2N|T2R|N2A| | RSTACK| DSTACK|
+---------------------------------------------------------------+
| F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---------------------------------------------------------------+
T : Top of data stack
N : Next on data stack
PC : Program Counter
LITERAL VALUES : push a value onto the data stack
CONDITIONAL : BRANCHS pop and test the T
CALLS : PC+1 onto the return stack
T2N : Move T to N
T2R : Move T to top of return stack
N2A : STORE T to memory location addressed by N
R2P : Move top of return stack to PC
RSTACK and DSTACK are signed values (twos compliment) that are
the stack delta (the amount to increment or decrement the stack
by for their respective stacks: return and data)
The J1+ CPU adds up to 16 new alu operations, by assigning new alu
operations by using ALU bit 4 to determine if J1 or J1+ alu operations,
with the ALU instruction encoding:
::
+---------------------------------------------------------------+
| 0 | 1 | 1 |R2P| ALU OPERATION |T2N|T2R|N2A|J1+| RSTACK| DSTACK|
+---------------------------------------------------------------+
| F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
+---------------------------------------------------------------+
+-----------+-----------+-----------+-----------+-----------+-----------+
| Binary | J1 CPU | J1+ CPU | J1 CPU | J1+ CPU | J1+ |
| ALU | | | Forth | Forth | Im |
| Operation | | | Word | Word | plemented |
| Code | | | (notes) | | in |
| | | | | | j1eforth |
+===========+===========+===========+===========+===========+===========+
| 0000 | T | T==0 | (top of | 0= | X |
| | | | stack) | | |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 0001 | N | T<>0 | (next on | 0<> | X |
| | | | stack) | | |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 0010 | T+N | N<>T | + | <> | X |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 0011 | T&N | T+1 | and | 1+ | X |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 0100 | T|N | T<<1 | or | 2\* | X |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 0101 | T^N | T>>1 | xor | 2/ | (stops |
| | | | | | ROM |
| | | | | | working) |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 0110 | ~T | N>T | invert | > | X |
| | | | | (signed) | |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 0111 | N==T | NU>T | = | > | X |
| | | | | ( | |
| | | | | unsigned) | |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 1000 | N<T | T<0 | < | 0< | X |
| | | | (signed) | | |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 1001 | N>>T | T>0 | rshift | 0> | X |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 1010 | T-1 | ABST | 1- | abs | X |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 1011 | rt | MXNT | (push top | max | X |
| | | | of return | | |
| | | | stack to | | |
| | | | data | | |
| | | | stack) | | |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 1100 | [T] | MNNT | @ (read | min | X |
| | | | from | | |
| | | | memory) | | |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 1101 | N<<T | -T | lshift | negate | X |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 1110 | dsp | N-T | (depth of | - | (stops |
| | | | stacks) | | ROM |
| | | | | | working) |
+-----------+-----------+-----------+-----------+-----------+-----------+
| 1111 | NU<T | N>=T | < | >= | X |
| | | | ( | (signed) | |
| | | | unsigned) | | |
+-----------+-----------+-----------+-----------+-----------+-----------+
*I am presently unable to add the 2/ or - to the j1eforth ROM, as the
compiled ROM is no longer functional. Some assistance to add these
instructions would be appreciated.*
Memory Map
~~~~~~~~~~
+-----------------------------------+-----------------------------------+
| Hexadecimal Address | Usage |
+===================================+===================================+
| 0000 - 3fff | Program code and data |
+-----------------------------------+-----------------------------------+
| 4000 - 7fff | RAM (written to with |
| | ``value addr !``, read by |
| | ``addr @`` |
+-----------------------------------+-----------------------------------+
| f000 | UART input/output (best to leave |
| | to j1eforth to operate via IN/OUT |
| | buffers) |
+-----------------------------------+-----------------------------------+
| f001 | UART Status (bit 1 = TX buffer |
| | full, bit 0 = RX character |
| | available, best to leave to |
| | j1eforth to operate via IN/OUT |
| | buffers) |
+-----------------------------------+-----------------------------------+
| f002 | RGB LED input/output bitfield { |
| | 13b0, red, green, blue } |
+-----------------------------------+-----------------------------------+
| f003 | BUTTONS input bitfield { 12b0, |
| | button 4, button 3, button 2, |
| | button 1 } |
+-----------------------------------+-----------------------------------+
INIT stages
~~~~~~~~~~~
Due to the size of the block ram on the FOMU (120kbit or 7680 x 16bit)
and the J1+ CPU requiring 256kbit (16384 x 16bit) of RAM, the J1+ CPU on
the FOMU copies the j1eforth code from an initialised block ram to
SPRAM, and uses the SPRAM for the J1+ CPU.
+-----------------------------------+-----------------------------------+
| INIT | Action |
+===================================+===================================+
| 0 | 0 the SPRAM. Due to the latency, |
| | this is controlled by CYCLE |
| | (pipeline). |
+-----------------------------------+-----------------------------------+
| 1 | COPY the j1eforth ROM to SPRAM. |
| | Due to latency, this is |
| | controoled by CYCLE (pipeline). |
| | The block ram at address |
| | [copaddress] is read in a |
| | separate always block. This |
| | allows the block ram to inferred |
| | by yosys. |
+-----------------------------------+-----------------------------------+
| 2 | SPARE (not used in the J1+ CPU). |
+-----------------------------------+-----------------------------------+
| 3 | Start the J1+ CPU at pc==0 from |
| | SPRAM. |
+-----------------------------------+-----------------------------------+
Pipeline / CYCLE logic
~~~~~~~~~~~~~~~~~~~~~~
Due to blockram and SPRAM latency, there needs to be a pipeline for the
J1+ CPU on the FOMU, which is set to 0 to 12 stages. These are used as
follows:
+-----------------------------------+-----------------------------------+
| CYCLE | Action |
+===================================+===================================+
| ALL (at entry to INIT==3 loop) | Check for input from the UART, |
| | put into buffer. Check if output |
| | in the UART buffer and send to |
| | UART. **NOTE:** To stop a race |
| | condition, uartOutBufferTop = |
| | newuartOutBufferTop is updated |
| | after output. |
+-----------------------------------+-----------------------------------+
| 0 | blockram: Read data stackNext and |
| | rstackTop, started in CYCLE==9. |
| | SPRAM: Start the read of memory |
| | position [stackTop] by setting |
| | the SPRAM sram_address and |
| | sram_readwrite flag. This is done |
| | speculatively in case the ALU |
| | needs this memory later in the |
| | pipeline. |
+-----------------------------------+-----------------------------------+
| 3 | Complete read of memory position |
| | [stackTop] from SPRAM by reading |
| | sram_data_read. |
+-----------------------------------+-----------------------------------+
| 4 | Start read of the instruction at |
| | memory position [pc] by setting |
| | sram_address and sram_readwrite |
| | flag. |
+-----------------------------------+-----------------------------------+
| 7 | Complete read of the instruction |
| | at memory position [pc] by |
| | reading sram_data_read. *The |
| | instruction is decoded |
| | automatically by the continuos |
| | assigns := block at the top of |
| | the code.* |
+-----------------------------------+-----------------------------------+
| 8 | Instruction Execution Determine |
| | if LITERAL, BRANCH, BRANCH, CALL |
| | or ALU. In the ALU (J1 CPU block) |
| | the UART input buffer, UART |
| | status register, RGB LED status, |
| | input buttons or memory is |
| | selected as appropriate. The UART |
| | buffers and the speculative |
| | memory read of [stackTop] are |
| | used to allow **ALL** ALU |
| | operations to execute in one |
| | cycle. At the end of the ALU if a |
| | write to memory is required, this |
| | is initiated by setting the |
| | sram_address, sram_data_write and |
| | sram_readwrite flag. This will be |
| | completed by CYCLE==12. Output to |
| | UART output buffer or the RGB LED |
| | is performed here if a write to |
| | an I/O address, not memory, is |
| | requested. |
+-----------------------------------+-----------------------------------+
| 9 | Start the writing to the block |
| | ram for the data and return |
| | stacks. This will be completed by |
| | CYCLE==10. |
+-----------------------------------+-----------------------------------+
| 10 | Update all of the J1+ CPU |
| | pointers for the data and return |
| | stacks, the program counter, and |
| | stackTop. Start the reading of |
| | the data and return stacks. This |
| | will be completed by CYCLE==11, |
| | but not actually read until the |
| | return to CYCLE==0. |
+-----------------------------------+-----------------------------------+
| 12 | Reset the sram_readwrite flag, to |
| | complete any memory write started |
| | in CYCLE==8 in the ALU. |
+-----------------------------------+-----------------------------------+
| ALL (at end of INIT==3 loop) | Reset the UART output if any |
| | character was transmitted. Move |
| | to the next CYCLE. |
+-----------------------------------+-----------------------------------+
Forth Words to try
~~~~~~~~~~~~~~~~~~
- ``cold`` reset
- ``words`` list known Forth words
- ``cr`` output a carriage return
- ``2a emit`` output a \* (character 2a (hex) 42 (decimal)
- ``decimal`` use decimal notation
- ``hex`` use hexadecimal notation
.. figure:: j1eforth-verilog.png
:alt: j1eforth on FOMU
j1eforth on FOMU

View File

@ -0,0 +1,26 @@
#!/bin/bash
rm build*
yosys -D HACKER=1 -p 'synth_ice40 -top top -json build.json' \
tinyfpga_bx_usbserial/usb/edge_detect.v \
tinyfpga_bx_usbserial/usb/serial.v \
tinyfpga_bx_usbserial/usb/usb_fs_in_arb.v \
tinyfpga_bx_usbserial/usb/usb_fs_in_pe.v \
tinyfpga_bx_usbserial/usb/usb_fs_out_arb.v \
tinyfpga_bx_usbserial/usb/usb_fs_out_pe.v \
tinyfpga_bx_usbserial/usb/usb_fs_pe.v \
tinyfpga_bx_usbserial/usb/usb_fs_rx.v \
tinyfpga_bx_usbserial/usb/usb_fs_tx_mux.v \
tinyfpga_bx_usbserial/usb/usb_fs_tx.v\
tinyfpga_bx_usbserial/usb/usb_reset_det.v \
tinyfpga_bx_usbserial/usb/usb_serial_ctrl_ep.v \
tinyfpga_bx_usbserial/usb/usb_uart_bridge_ep.v \
tinyfpga_bx_usbserial/usb/usb_uart_core.v \
tinyfpga_bx_usbserial/usb/usb_uart_i40.v \
j1eforth.v
nextpnr-ice40 --up5k --freq 12 --opt-timing --package uwg30 --pcf pcf/fomu-hacker.pcf --json build.json --asc build.asc
icepack build.asc build.bit
icetime -d up5k -mtr build.rpt build.asc
cp build.bit build.dfu
dfu-suffix -v 1209 -p 70b1 -a build.dfu

View File

@ -0,0 +1,13 @@
all: j1 j1.bin j1.hex
j1: j1.c
gcc -o j1 j1.c -lwpcap
strip -s j1
j1.bin j1.hex: j1.4th
gforth ./j1.4th
run: all
./j1
core: all
./j1 core.4th
clean:
rm -rf j1 j1.bin j1.hex

View File

@ -0,0 +1,99 @@
eForth for the J1 Simulator and actual J1 FPGAs
-------------
J1 eForth is an interactive work-in-progress Forth designed to run on the [James Bowman's J1 FPGA soft core][j1]
(see also [J1 on Github][J1github]). There is a Forth cross compiler written in Forth to
generate the interactice J1 eForth system, and a J1 simulator written in C to run J1 eForth simulated
on a PC.
J1 eForth also runs on actual J1 FPGAs. It has been ported to the [Papilio Pro][pappro] FPGA board,
where it executes Forth program at 66 MHz. It communicates with a host system using a serial line at a
default speed of 115200 Bits/s.
### Prerequisites
- [GNU make][gmake] (optional) for job control
- [gforth][gforth] for cross compiling / generating the J1 eForth image
- [WpdPack][pcap] for network simulation
If you want to run J1 eForth simulated on a PC:
- [gcc][gcc] to compile the J1 simulator
If you want to run J1 eForth on a J1 in an FPGA:
- [Xilinx ISE][xilinxise] to generate the FPGA bit stream (ISE 14.7)
- [Papilio-Loader][paploader] to download the bitstream to the FPGA
### Directry Structure
j1eforth
├── README.MD
├── j1.4th cross compiler with J1 eForth
├── j1.c J1 simulator
└── fpga
├── src Verilog projects for J1 and UART (miniuart2) for Papilio Pro
└── test testbenches
### Building and running the j1 Simulator
#### Compiling using gcc Mingw (Windows)
gcc j1.c -o -lwpcap j1.exe
#### Creating flash image j1.bin (and j1.hex)
gforth j1.4th
#### Running the Simulator
j1.exe [optional argument]
The argument to the simulator is an optional forth file that can be used to extend the dictionary
and is passed to the simulator as the first argument during startup
Words to test in the simulator :
[ see , ' , compile , [compile] , ?branch , branch , call, .. and many more ]
Have fun , modify and pass on
### Running on Real Hardware
J1 eForth can run on an actual j1 FPGA. It has been ported to the [Papilio Pro][pappro] FPGA board.
#### Create the J1 bit stream:
Start Xilinx ise on project `vhdl/papiolo-pro-j1.xise`
choose `Generate Programming File` on the `papilio_pro_j1` component. This generates `papilio_pro_j1.bit`
including the Forth image (`j1.hex`) as initial memory (built before when generating the flash image).
#### Load the complete bit stream (J1 and memory) into the FPGA:
sudo papilio-prog -v -f papilio_pro_j1.bit
You might want to use the pre-built `pipilio_pro_j1.bit` for a quick start.
#### Connect to J1 eForth:
screen /dev/tty.usbserial 115200
or similar. J1 eForth should show the prompt
eForth j1 v1.04
ok
If you only see the **`ok`** prompts issue a **`cold`** and press the enter key to reboot the system.
### May the Forth be with you.
[pappro]: http://papilio.cc/index.php?n=Papilio.PapilioPro
[paploader]: http://papilio.cc/index.php?n=Papilio.PapilioLoaderV2
[pcap]: http://www.winpcap.org/archive/4.1.1-WpdPack.zip
[j1]: http://www.excamera.com/sphinx/fpga-j1.html
[j1github]: https://github.com/jamesbowman/j1
[gmake]: https://www.gnu.org/software/make/
[gcc]: https://gcc.gnu.org/
[gforth]: https://www.gnu.org/software/gforth/
[xilinxise]: http://www.xilinx.com/products/design-tools/ise-design-suite/ise-webpack.html

View File

@ -0,0 +1,422 @@
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<project xmlns="http://www.xilinx.com/XMLSchema" xmlns:xil_pn="http://www.xilinx.com/XMLSchema">
<header>
<!-- ISE source project file created by Project Navigator. -->
<!-- -->
<!-- This file contains project source information including a list of -->
<!-- project source files, project and process properties. This file, -->
<!-- along with the project source files, is sufficient to open and -->
<!-- implement in ISE Project Navigator. -->
<!-- -->
<!-- Copyright (c) 1995-2013 Xilinx, Inc. All rights reserved. -->
</header>
<version xil_pn:ise_version="14.7" xil_pn:schema_version="2"/>
<files>
<file xil_pn:name="src/papilio-pro.ucf" xil_pn:type="FILE_UCF">
<association xil_pn:name="Implementation" xil_pn:seqID="0"/>
</file>
<file xil_pn:name="src/miniuart.vhd" xil_pn:type="FILE_VHDL">
<association xil_pn:name="BehavioralSimulation" xil_pn:seqID="4"/>
<association xil_pn:name="Implementation" xil_pn:seqID="4"/>
</file>
<file xil_pn:name="src/Rxunit.vhd" xil_pn:type="FILE_VHDL">
<association xil_pn:name="BehavioralSimulation" xil_pn:seqID="3"/>
<association xil_pn:name="Implementation" xil_pn:seqID="3"/>
</file>
<file xil_pn:name="src/Txunit.vhd" xil_pn:type="FILE_VHDL">
<association xil_pn:name="BehavioralSimulation" xil_pn:seqID="2"/>
<association xil_pn:name="Implementation" xil_pn:seqID="2"/>
</file>
<file xil_pn:name="src/utils.vhd" xil_pn:type="FILE_VHDL">
<association xil_pn:name="BehavioralSimulation" xil_pn:seqID="1"/>
<association xil_pn:name="Implementation" xil_pn:seqID="1"/>
</file>
<file xil_pn:name="test/miniuart2_tb.vhd" xil_pn:type="FILE_VHDL">
<association xil_pn:name="BehavioralSimulation" xil_pn:seqID="5"/>
<association xil_pn:name="PostMapSimulation" xil_pn:seqID="231"/>
<association xil_pn:name="PostRouteSimulation" xil_pn:seqID="231"/>
<association xil_pn:name="PostTranslateSimulation" xil_pn:seqID="231"/>
</file>
<file xil_pn:name="test/papilio_pro_j1_tb.vhd" xil_pn:type="FILE_VHDL">
<association xil_pn:name="BehavioralSimulation" xil_pn:seqID="0"/>
<association xil_pn:name="PostMapSimulation" xil_pn:seqID="15"/>
<association xil_pn:name="PostRouteSimulation" xil_pn:seqID="15"/>
<association xil_pn:name="PostTranslateSimulation" xil_pn:seqID="15"/>
</file>
<file xil_pn:name="src/papilio-pro-j1.vhd" xil_pn:type="FILE_VHDL">
<association xil_pn:name="BehavioralSimulation" xil_pn:seqID="0"/>
<association xil_pn:name="Implementation" xil_pn:seqID="7"/>
</file>
<file xil_pn:name="src/j1.v" xil_pn:type="FILE_VERILOG">
<association xil_pn:name="BehavioralSimulation" xil_pn:seqID="0"/>
<association xil_pn:name="Implementation" xil_pn:seqID="5"/>
</file>
<file xil_pn:name="src/clock.vhd" xil_pn:type="FILE_VHDL">
<association xil_pn:name="BehavioralSimulation" xil_pn:seqID="0"/>
<association xil_pn:name="Implementation" xil_pn:seqID="6"/>
</file>
</files>
<properties>
<property xil_pn:name="AES Initial Vector spartan6" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="AES Key (Hex String) spartan6" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Add I/O Buffers" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Allow Logic Optimization Across Hierarchy" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Allow SelectMAP Pins to Persist" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Allow Unexpanded Blocks" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Allow Unmatched LOC Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Allow Unmatched Timing Group Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Analysis Effort Level" xil_pn:value="Standard" xil_pn:valueState="default"/>
<property xil_pn:name="Asynchronous To Synchronous" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Auto Implementation Compile Order" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Auto Implementation Top" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Automatic BRAM Packing" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Automatically Insert glbl Module in the Netlist" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Automatically Run Generate Target PROM/ACE File" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="BRAM Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
<property xil_pn:name="Bring Out Global Set/Reset Net as a Port" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Bring Out Global Tristate Net as a Port" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Bus Delimiter" xil_pn:value="&lt;>" xil_pn:valueState="default"/>
<property xil_pn:name="CLB Pack Factor Percentage" xil_pn:value="100" xil_pn:valueState="default"/>
<property xil_pn:name="Case" xil_pn:value="Maintain" xil_pn:valueState="default"/>
<property xil_pn:name="Case Implementation Style" xil_pn:value="None" xil_pn:valueState="default"/>
<property xil_pn:name="Change Device Speed To" xil_pn:value="-2" xil_pn:valueState="default"/>
<property xil_pn:name="Change Device Speed To Post Trace" xil_pn:value="-2" xil_pn:valueState="default"/>
<property xil_pn:name="Combinatorial Logic Optimization" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Compile EDK Simulation Library" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Compile SIMPRIM (Timing) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Compile UNISIM (Functional) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Compile XilinxCoreLib (CORE Generator) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Compile for HDL Debugging" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Configuration Clk (Configuration Pins)" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
<property xil_pn:name="Configuration Pin Done" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
<property xil_pn:name="Configuration Pin M0" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
<property xil_pn:name="Configuration Pin M1" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
<property xil_pn:name="Configuration Pin M2" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
<property xil_pn:name="Configuration Pin Program" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
<property xil_pn:name="Configuration Rate" xil_pn:value="4" xil_pn:valueState="default"/>
<property xil_pn:name="Configuration Rate spartan6" xil_pn:value="2" xil_pn:valueState="default"/>
<property xil_pn:name="Correlate Output to Input Design" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Create ASCII Configuration File" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Create Binary Configuration File" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Create Bit File" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Create I/O Pads from Ports" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Create IEEE 1532 Configuration File spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Create Logic Allocation File" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Create Mask File" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Create ReadBack Data Files" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Cross Clock Analysis" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="DSP Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
<property xil_pn:name="Decoder Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Delay Values To Be Read from SDF" xil_pn:value="Setup Time" xil_pn:valueState="default"/>
<property xil_pn:name="Device" xil_pn:value="xc6slx9" xil_pn:valueState="non-default"/>
<property xil_pn:name="Device Family" xil_pn:value="Spartan6" xil_pn:valueState="non-default"/>
<property xil_pn:name="Device Speed Grade/Select ABS Minimum" xil_pn:value="-2" xil_pn:valueState="default"/>
<property xil_pn:name="Disable Detailed Package Model Insertion" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Do Not Escape Signal and Instance Names in Netlist" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Done (Output Events)" xil_pn:value="Default (4)" xil_pn:valueState="default"/>
<property xil_pn:name="Drive Awake Pin During Suspend/Wake Sequence spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Drive Done Pin High" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Enable BitStream Compression" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Enable Cyclic Redundancy Checking (CRC) spartan6" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Enable Debugging of Serial Mode BitStream" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Enable External Master Clock spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Enable Hardware Co-Simulation" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Enable Internal Done Pipe" xil_pn:value="true" xil_pn:valueState="non-default"/>
<property xil_pn:name="Enable Message Filtering" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Enable Multi-Pin Wake-Up Suspend Mode spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Enable Multi-Threading" xil_pn:value="Off" xil_pn:valueState="default"/>
<property xil_pn:name="Enable Multi-Threading par spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
<property xil_pn:name="Enable Outputs (Output Events)" xil_pn:value="Default (5)" xil_pn:valueState="default"/>
<property xil_pn:name="Enable Suspend/Wake Global Set/Reset spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Encrypt Bitstream spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Encrypt Key Select spartan6" xil_pn:value="BBRAM" xil_pn:valueState="default"/>
<property xil_pn:name="Equivalent Register Removal Map" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Equivalent Register Removal XST" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Essential Bits" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Evaluation Development Board" xil_pn:value="None Specified" xil_pn:valueState="default"/>
<property xil_pn:name="Exclude Compilation of Deprecated EDK Cores" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Exclude Compilation of EDK Sub-Libraries" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Extra Cost Tables Map" xil_pn:value="0" xil_pn:valueState="default"/>
<property xil_pn:name="Extra Effort (Highest PAR level only)" xil_pn:value="None" xil_pn:valueState="default"/>
<property xil_pn:name="FPGA Start-Up Clock" xil_pn:value="CCLK" xil_pn:valueState="default"/>
<property xil_pn:name="FSM Encoding Algorithm" xil_pn:value="Auto" xil_pn:valueState="default"/>
<property xil_pn:name="FSM Style" xil_pn:value="LUT" xil_pn:valueState="default"/>
<property xil_pn:name="Filter Files From Compile Order" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Flatten Output Netlist" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Functional Model Target Language ArchWiz" xil_pn:value="Verilog" xil_pn:valueState="default"/>
<property xil_pn:name="Functional Model Target Language Coregen" xil_pn:value="Verilog" xil_pn:valueState="default"/>
<property xil_pn:name="Functional Model Target Language Schematic" xil_pn:value="Verilog" xil_pn:valueState="default"/>
<property xil_pn:name="GTS Cycle During Suspend/Wakeup Sequence spartan6" xil_pn:value="4" xil_pn:valueState="default"/>
<property xil_pn:name="GWE Cycle During Suspend/Wakeup Sequence spartan6" xil_pn:value="5" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Architecture Only (No Entity Declaration)" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Asynchronous Delay Report" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Clock Region Report" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Constraints Interaction Report" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Constraints Interaction Report Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Datasheet Section" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Datasheet Section Post Trace" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Detailed MAP Report" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Multiple Hierarchical Netlist Files" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Post-Place &amp; Route Power Report" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Post-Place &amp; Route Simulation Model" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Generate RTL Schematic" xil_pn:value="Yes" xil_pn:valueState="default"/>
<property xil_pn:name="Generate SAIF File for Power Optimization/Estimation Par" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Testbench File" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Timegroups Section" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Generate Timegroups Section Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Generics, Parameters" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Global Optimization Goal" xil_pn:value="AllClockNets" xil_pn:valueState="default"/>
<property xil_pn:name="Global Optimization map spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
<property xil_pn:name="Global Set/Reset Port Name" xil_pn:value="GSR_PORT" xil_pn:valueState="default"/>
<property xil_pn:name="Global Tristate Port Name" xil_pn:value="GTS_PORT" xil_pn:valueState="default"/>
<property xil_pn:name="Hierarchy Separator" xil_pn:value="/" xil_pn:valueState="default"/>
<property xil_pn:name="ISim UUT Instance Name" xil_pn:value="UUT" xil_pn:valueState="default"/>
<property xil_pn:name="Ignore User Timing Constraints Map" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Ignore User Timing Constraints Par" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Implementation Top" xil_pn:value="Architecture|papilio_pro_j1|Behavioral" xil_pn:valueState="non-default"/>
<property xil_pn:name="Implementation Top File" xil_pn:value="src/papilio-pro-j1.vhd" xil_pn:valueState="non-default"/>
<property xil_pn:name="Implementation Top Instance Path" xil_pn:value="/papilio_pro_j1" xil_pn:valueState="non-default"/>
<property xil_pn:name="Include 'uselib Directive in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Include SIMPRIM Models in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Include UNISIM Models in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Include sdf_annotate task in Verilog File" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Incremental Compilation" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Insert Buffers to Prevent Pulse Swallowing" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Instantiation Template Target Language Xps" xil_pn:value="Verilog" xil_pn:valueState="default"/>
<property xil_pn:name="JTAG Pin TCK" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
<property xil_pn:name="JTAG Pin TDI" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
<property xil_pn:name="JTAG Pin TDO" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
<property xil_pn:name="JTAG Pin TMS" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
<property xil_pn:name="Keep Hierarchy" xil_pn:value="No" xil_pn:valueState="default"/>
<property xil_pn:name="LUT Combining Map" xil_pn:value="Off" xil_pn:valueState="default"/>
<property xil_pn:name="LUT Combining Xst" xil_pn:value="Auto" xil_pn:valueState="default"/>
<property xil_pn:name="Language" xil_pn:value="VHDL" xil_pn:valueState="default"/>
<property xil_pn:name="Last Applied Goal" xil_pn:value="Balanced" xil_pn:valueState="default"/>
<property xil_pn:name="Last Applied Strategy" xil_pn:value="Xilinx Default (unlocked)" xil_pn:valueState="default"/>
<property xil_pn:name="Last Unlock Status" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Launch SDK after Export" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Library for Verilog Sources" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Load glbl" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Logical Shifter Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Manual Implementation Compile Order" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Map Slice Logic into Unused Block RAMs" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Mask Pins for Multi-Pin Wake-Up Suspend Mode spartan6" xil_pn:value="0x00" xil_pn:valueState="default"/>
<property xil_pn:name="Max Fanout" xil_pn:value="100000" xil_pn:valueState="default"/>
<property xil_pn:name="Maximum Compression" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Maximum Number of Lines in Report" xil_pn:value="1000" xil_pn:valueState="default"/>
<property xil_pn:name="Maximum Signal Name Length" xil_pn:value="20" xil_pn:valueState="default"/>
<property xil_pn:name="Move First Flip-Flop Stage" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Move Last Flip-Flop Stage" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="MultiBoot: Insert IPROG CMD in the Bitfile spartan6" xil_pn:value="Enable" xil_pn:valueState="default"/>
<property xil_pn:name="MultiBoot: Next Configuration Mode spartan6" xil_pn:value="001" xil_pn:valueState="default"/>
<property xil_pn:name="MultiBoot: Starting Address for Golden Configuration spartan6" xil_pn:value="0x00000000" xil_pn:valueState="default"/>
<property xil_pn:name="MultiBoot: Starting Address for Next Configuration spartan6" xil_pn:value="0x00000000" xil_pn:valueState="default"/>
<property xil_pn:name="MultiBoot: Use New Mode for Next Configuration spartan6" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="MultiBoot: User-Defined Register for Failsafe Scheme spartan6" xil_pn:value="0x0000" xil_pn:valueState="default"/>
<property xil_pn:name="Multiplier Style" xil_pn:value="LUT" xil_pn:valueState="default"/>
<property xil_pn:name="Mux Extraction" xil_pn:value="Yes" xil_pn:valueState="default"/>
<property xil_pn:name="Mux Style" xil_pn:value="Auto" xil_pn:valueState="default"/>
<property xil_pn:name="Netlist Hierarchy" xil_pn:value="As Optimized" xil_pn:valueState="default"/>
<property xil_pn:name="Netlist Translation Type" xil_pn:value="Timestamp" xil_pn:valueState="default"/>
<property xil_pn:name="Number of Clock Buffers" xil_pn:value="16" xil_pn:valueState="default"/>
<property xil_pn:name="Number of Paths in Error/Verbose Report" xil_pn:value="3" xil_pn:valueState="default"/>
<property xil_pn:name="Number of Paths in Error/Verbose Report Post Trace" xil_pn:value="3" xil_pn:valueState="default"/>
<property xil_pn:name="Optimization Effort" xil_pn:value="Normal" xil_pn:valueState="default"/>
<property xil_pn:name="Optimization Effort spartan6" xil_pn:value="Normal" xil_pn:valueState="default"/>
<property xil_pn:name="Optimization Goal" xil_pn:value="Speed" xil_pn:valueState="default"/>
<property xil_pn:name="Optimization Strategy (Cover Mode)" xil_pn:value="Area" xil_pn:valueState="default"/>
<property xil_pn:name="Optimize Instantiated Primitives" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Other Bitgen Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other Bitgen Command Line Options spartan6" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other Compiler Options" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other Compiler Options Map" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other Compiler Options Par" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other Compiler Options Translate" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other Compxlib Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other Map Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other NETGEN Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other Ngdbuild Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other Place &amp; Route Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other Simulator Commands Behavioral" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other Simulator Commands Post-Map" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other Simulator Commands Post-Route" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other Simulator Commands Post-Translate" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other XPWR Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Other XST Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Output Extended Identifiers" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Output File Name" xil_pn:value="papilio_pro_forth" xil_pn:valueState="non-default"/>
<property xil_pn:name="Overwrite Compiled Libraries" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Pack I/O Registers into IOBs" xil_pn:value="Auto" xil_pn:valueState="default"/>
<property xil_pn:name="Pack I/O Registers/Latches into IOBs" xil_pn:value="Off" xil_pn:valueState="default"/>
<property xil_pn:name="Package" xil_pn:value="tqg144" xil_pn:valueState="default"/>
<property xil_pn:name="Perform Advanced Analysis" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Perform Advanced Analysis Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Perform Timing-Driven Packing and Placement" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Place &amp; Route Effort Level (Overall)" xil_pn:value="High" xil_pn:valueState="default"/>
<property xil_pn:name="Place And Route Mode" xil_pn:value="Normal Place and Route" xil_pn:valueState="default"/>
<property xil_pn:name="Place MultiBoot Settings into Bitstream spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Placer Effort Level (Overrides Overall Level)" xil_pn:value="None" xil_pn:valueState="default"/>
<property xil_pn:name="Placer Effort Level Map" xil_pn:value="High" xil_pn:valueState="default"/>
<property xil_pn:name="Placer Extra Effort Map" xil_pn:value="None" xil_pn:valueState="default"/>
<property xil_pn:name="Port to be used" xil_pn:value="Auto - default" xil_pn:valueState="default"/>
<property xil_pn:name="Post Map Simulation Model Name" xil_pn:value="papilio_pro_forth_map.v" xil_pn:valueState="non-default"/>
<property xil_pn:name="Post Place &amp; Route Simulation Model Name" xil_pn:value="papilio_pro_forth_timesim.v" xil_pn:valueState="non-default"/>
<property xil_pn:name="Post Synthesis Simulation Model Name" xil_pn:value="papilio_pro_forth_synthesis.v" xil_pn:valueState="non-default"/>
<property xil_pn:name="Post Translate Simulation Model Name" xil_pn:value="papilio_pro_forth_translate.v" xil_pn:valueState="non-default"/>
<property xil_pn:name="Power Reduction Map" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Power Reduction Map spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
<property xil_pn:name="Power Reduction Par" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Power Reduction Xst" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Preferred Language" xil_pn:value="Verilog" xil_pn:valueState="default"/>
<property xil_pn:name="Priority Encoder Extraction" xil_pn:value="Yes" xil_pn:valueState="default"/>
<property xil_pn:name="Produce Verbose Report" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Project Description" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Project Generator" xil_pn:value="ProjNav" xil_pn:valueState="default"/>
<property xil_pn:name="Property Specification in Project File" xil_pn:value="Store all values" xil_pn:valueState="default"/>
<property xil_pn:name="RAM Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="RAM Style" xil_pn:value="Auto" xil_pn:valueState="default"/>
<property xil_pn:name="ROM Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="ROM Style" xil_pn:value="Auto" xil_pn:valueState="default"/>
<property xil_pn:name="Read Cores" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Reduce Control Sets" xil_pn:value="Auto" xil_pn:valueState="default"/>
<property xil_pn:name="Regenerate Core" xil_pn:value="Under Current Project Setting" xil_pn:valueState="default"/>
<property xil_pn:name="Register Balancing" xil_pn:value="No" xil_pn:valueState="default"/>
<property xil_pn:name="Register Duplication Map" xil_pn:value="Off" xil_pn:valueState="default"/>
<property xil_pn:name="Register Duplication Xst" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Register Ordering spartan6" xil_pn:value="4" xil_pn:valueState="default"/>
<property xil_pn:name="Release Write Enable (Output Events)" xil_pn:value="Default (6)" xil_pn:valueState="default"/>
<property xil_pn:name="Rename Design Instance in Testbench File to" xil_pn:value="UUT" xil_pn:valueState="default"/>
<property xil_pn:name="Rename Top Level Architecture To" xil_pn:value="Structure" xil_pn:valueState="default"/>
<property xil_pn:name="Rename Top Level Entity to" xil_pn:value="main" xil_pn:valueState="non-default"/>
<property xil_pn:name="Rename Top Level Module To" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Report Fastest Path(s) in Each Constraint" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Report Fastest Path(s) in Each Constraint Post Trace" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Report Paths by Endpoint" xil_pn:value="3" xil_pn:valueState="default"/>
<property xil_pn:name="Report Paths by Endpoint Post Trace" xil_pn:value="3" xil_pn:valueState="default"/>
<property xil_pn:name="Report Type" xil_pn:value="Verbose Report" xil_pn:valueState="default"/>
<property xil_pn:name="Report Type Post Trace" xil_pn:value="Verbose Report" xil_pn:valueState="default"/>
<property xil_pn:name="Report Unconstrained Paths" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Report Unconstrained Paths Post Trace" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Reset On Configuration Pulse Width" xil_pn:value="100" xil_pn:valueState="default"/>
<property xil_pn:name="Resource Sharing" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Retain Hierarchy" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Retry Configuration if CRC Error Occurs spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Revision Select" xil_pn:value="00" xil_pn:valueState="default"/>
<property xil_pn:name="Revision Select Tristate" xil_pn:value="Disable" xil_pn:valueState="default"/>
<property xil_pn:name="Router Effort Level (Overrides Overall Level)" xil_pn:value="None" xil_pn:valueState="default"/>
<property xil_pn:name="Run Design Rules Checker (DRC)" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Run for Specified Time" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Run for Specified Time Map" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Run for Specified Time Par" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Run for Specified Time Translate" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Safe Implementation" xil_pn:value="No" xil_pn:valueState="default"/>
<property xil_pn:name="Security" xil_pn:value="Enable Readback and Reconfiguration" xil_pn:valueState="default"/>
<property xil_pn:name="Selected Module Instance Name" xil_pn:value="/miniuart2_tb" xil_pn:valueState="non-default"/>
<property xil_pn:name="Selected Simulation Root Source Node Behavioral" xil_pn:value="work.miniuart2_tb" xil_pn:valueState="non-default"/>
<property xil_pn:name="Selected Simulation Root Source Node Post-Map" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Selected Simulation Root Source Node Post-Route" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Selected Simulation Root Source Node Post-Translate" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Selected Simulation Source Node" xil_pn:value="UUT" xil_pn:valueState="default"/>
<property xil_pn:name="Set SPI Configuration Bus Width spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
<property xil_pn:name="Setup External Master Clock Division spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
<property xil_pn:name="Shift Register Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Shift Register Minimum Size spartan6" xil_pn:value="2" xil_pn:valueState="default"/>
<property xil_pn:name="Show All Models" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Simulation Model Target" xil_pn:value="Verilog" xil_pn:valueState="default"/>
<property xil_pn:name="Simulation Run Time ISim" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
<property xil_pn:name="Simulation Run Time Map" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
<property xil_pn:name="Simulation Run Time Par" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
<property xil_pn:name="Simulation Run Time Translate" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
<property xil_pn:name="Simulator" xil_pn:value="ISim (VHDL/Verilog)" xil_pn:valueState="default"/>
<property xil_pn:name="Slice Packing" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Slice Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
<property xil_pn:name="Specify 'define Macro Name and Value" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Specify Top Level Instance Names Behavioral" xil_pn:value="work.miniuart2_tb" xil_pn:valueState="default"/>
<property xil_pn:name="Specify Top Level Instance Names Post-Map" xil_pn:value="Default" xil_pn:valueState="default"/>
<property xil_pn:name="Specify Top Level Instance Names Post-Route" xil_pn:value="Default" xil_pn:valueState="default"/>
<property xil_pn:name="Specify Top Level Instance Names Post-Translate" xil_pn:value="Default" xil_pn:valueState="default"/>
<property xil_pn:name="Speed Grade" xil_pn:value="-2" xil_pn:valueState="non-default"/>
<property xil_pn:name="Starting Placer Cost Table (1-100) Map" xil_pn:value="1" xil_pn:valueState="default"/>
<property xil_pn:name="Starting Placer Cost Table (1-100) Map spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
<property xil_pn:name="Starting Placer Cost Table (1-100) Par" xil_pn:value="1" xil_pn:valueState="default"/>
<property xil_pn:name="Synthesis Tool" xil_pn:value="XST (VHDL/Verilog)" xil_pn:valueState="default"/>
<property xil_pn:name="Target Simulator" xil_pn:value="Please Specify" xil_pn:valueState="default"/>
<property xil_pn:name="Target UCF File Name" xil_pn:value="src/papilio-one.ucf" xil_pn:valueState="non-default"/>
<property xil_pn:name="Timing Mode Map" xil_pn:value="Non Timing Driven" xil_pn:valueState="non-default"/>
<property xil_pn:name="Timing Mode Par" xil_pn:value="Performance Evaluation" xil_pn:valueState="default"/>
<property xil_pn:name="Top-Level Module Name in Output Netlist" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Top-Level Source Type" xil_pn:value="HDL" xil_pn:valueState="default"/>
<property xil_pn:name="Trim Unconnected Signals" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Tristate On Configuration Pulse Width" xil_pn:value="0" xil_pn:valueState="default"/>
<property xil_pn:name="Unused IOB Pins" xil_pn:value="Pull Down" xil_pn:valueState="default"/>
<property xil_pn:name="Use 64-bit PlanAhead on 64-bit Systems" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Use Clock Enable" xil_pn:value="Auto" xil_pn:valueState="default"/>
<property xil_pn:name="Use Custom Project File Behavioral" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Use Custom Project File Post-Map" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Use Custom Project File Post-Route" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Use Custom Project File Post-Translate" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Use Custom Simulation Command File Behavioral" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Use Custom Simulation Command File Map" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Use Custom Simulation Command File Par" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Use Custom Simulation Command File Translate" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Use Custom Waveform Configuration File Behav" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Use Custom Waveform Configuration File Map" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Use Custom Waveform Configuration File Par" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Use Custom Waveform Configuration File Translate" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Use DSP Block spartan6" xil_pn:value="Auto" xil_pn:valueState="default"/>
<property xil_pn:name="Use LOC Constraints" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Use RLOC Constraints" xil_pn:value="Yes" xil_pn:valueState="default"/>
<property xil_pn:name="Use Smart Guide" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Use Synchronous Reset" xil_pn:value="Auto" xil_pn:valueState="default"/>
<property xil_pn:name="Use Synchronous Set" xil_pn:value="Auto" xil_pn:valueState="default"/>
<property xil_pn:name="Use Synthesis Constraints File" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="User Browsed Strategy Files" xil_pn:value="/opt/Xilinx/14.7/ISE_DS/ISE/data/default.xds" xil_pn:valueState="non-default"/>
<property xil_pn:name="UserID Code (8 Digit Hexadecimal)" xil_pn:value="0xFFFFFFFF" xil_pn:valueState="default"/>
<property xil_pn:name="VCCAUX Voltage Level spartan6" xil_pn:value="2.5V" xil_pn:valueState="default"/>
<property xil_pn:name="VHDL Source Analysis Standard" xil_pn:value="VHDL-93" xil_pn:valueState="default"/>
<property xil_pn:name="Value Range Check" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Verilog 2001 Xst" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Verilog Macros" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="Wait for DCM and PLL Lock (Output Events) spartan6" xil_pn:value="Default (NoWait)" xil_pn:valueState="default"/>
<property xil_pn:name="Wait for DLL Lock (Output Events)" xil_pn:value="Default (NoWait)" xil_pn:valueState="default"/>
<property xil_pn:name="Wakeup Clock spartan6" xil_pn:value="Startup Clock" xil_pn:valueState="default"/>
<property xil_pn:name="Watchdog Timer Value spartan6" xil_pn:value="0xFFFF" xil_pn:valueState="default"/>
<property xil_pn:name="Working Directory" xil_pn:value="." xil_pn:valueState="non-default"/>
<property xil_pn:name="Write Timing Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="XOR Collapsing" xil_pn:value="true" xil_pn:valueState="default"/>
<!-- -->
<!-- The following properties are for internal use only. These should not be modified.-->
<!-- -->
<property xil_pn:name="PROP_BehavioralSimTop" xil_pn:value="Architecture|miniuart2_tb|behavior" xil_pn:valueState="non-default"/>
<property xil_pn:name="PROP_DesignName" xil_pn:value="forth" xil_pn:valueState="non-default"/>
<property xil_pn:name="PROP_DevFamilyPMName" xil_pn:value="spartan6" xil_pn:valueState="default"/>
<property xil_pn:name="PROP_FPGAConfiguration" xil_pn:value="FPGAConfiguration" xil_pn:valueState="default"/>
<property xil_pn:name="PROP_PostMapSimTop" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="PROP_PostParSimTop" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="PROP_PostSynthSimTop" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="PROP_PostXlateSimTop" xil_pn:value="" xil_pn:valueState="default"/>
<property xil_pn:name="PROP_PreSynthesis" xil_pn:value="PreSynthesis" xil_pn:valueState="default"/>
<property xil_pn:name="PROP_intProjectCreationTimestamp" xil_pn:value="2012-03-04T11:05:19" xil_pn:valueState="non-default"/>
<property xil_pn:name="PROP_intWbtProjectID" xil_pn:value="2646B868CC6AC035FC694292A405C58C" xil_pn:valueState="non-default"/>
<property xil_pn:name="PROP_intWorkingDirLocWRTProjDir" xil_pn:value="Same" xil_pn:valueState="non-default"/>
<property xil_pn:name="PROP_intWorkingDirUsed" xil_pn:value="No" xil_pn:valueState="non-default"/>
</properties>
<bindings/>
<libraries/>
<autoManagedFiles>
<!-- The following files are identified by `include statements in verilog -->
<!-- source files and are automatically managed by Project Navigator. -->
<!-- -->
<!-- Do not hand-edit this section, as it will be overwritten when the -->
<!-- project is analyzed based on files automatically identified as -->
<!-- include files. -->
</autoManagedFiles>
</project>

Binary file not shown.

View File

@ -0,0 +1,97 @@
-------------------------------------------------------------------------------
-- Title : UART
-- Project : UART
-------------------------------------------------------------------------------
-- File : Rxunit.vhd
-- Author : Philippe CARTON
-- (philippe.carton2@libertysurf.fr)
-- Organization:
-- Created : 15/12/2001
-- Last update : 8/1/2003
-- Platform : Foundation 3.1i
-- Simulators : ModelSim 5.5b
-- Synthesizers: Xilinx Synthesis
-- Targets : Xilinx Spartan
-- Dependency : IEEE std_logic_1164
-------------------------------------------------------------------------------
-- Description: RxUnit is a serial to parallel unit Receiver.
-------------------------------------------------------------------------------
-- Copyright (c) notice
-- This core adheres to the GNU public license
--
-------------------------------------------------------------------------------
-- Revisions :
-- Revision Number :
-- Version :
-- Date :
-- Modifier : name <email>
-- Description :
--
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity RxUnit is
port (
Clk : in std_logic; -- system clock signal
Reset : in std_logic; -- Reset input
Enable : in std_logic; -- Enable input
ReadA : in Std_logic; -- Async Read Received Byte
RxD : in std_logic; -- RS-232 data input
RxAv : out std_logic; -- Byte available
DataO : out std_logic_vector(7 downto 0)); -- Byte received
end RxUnit;
architecture Behaviour of RxUnit is
signal RReg : std_logic_vector(7 downto 0); -- receive register
signal RRegL : std_logic; -- Byte received
begin
-- RxAv process
RxAvProc : process(RRegL,Reset,ReadA)
begin
if ReadA = '1' or Reset = '1' then
RxAv <= '0'; -- Negate RxAv when RReg read
elsif Rising_Edge(RRegL) then
RxAv <= '1'; -- Assert RxAv when RReg written
end if;
end process;
-- Rx Process
RxProc : process(Clk,Reset,Enable,RxD,RReg)
variable BitPos : INTEGER range 0 to 10; -- Position of the bit in the frame
variable SampleCnt : INTEGER range 0 to 3; -- Count from 0 to 3 in each bit
begin
if Reset = '1' then -- Reset
RRegL <= '0';
BitPos := 0;
elsif Rising_Edge(Clk) then
if Enable = '1' then
case BitPos is
when 0 => -- idle
RRegL <= '0';
if RxD = '0' then -- Start Bit
SampleCnt := 0;
BitPos := 1;
end if;
when 10 => -- Stop Bit
BitPos := 0; -- next is idle
RRegL <= '1'; -- Indicate byte received
DataO <= RReg; -- Store received byte
when others =>
if (SampleCnt = 1 and BitPos >= 2) then -- Sample RxD on 1
RReg(BitPos-2) <= RxD; -- Deserialisation
end if;
if SampleCnt = 3 then -- Increment BitPos on 3
BitPos := BitPos + 1;
end if;
end case;
if SampleCnt = 3 then
SampleCnt := 0;
else
sampleCnt := SampleCnt + 1;
end if;
end if;
end if;
end process;
end Behaviour;

View File

@ -0,0 +1,100 @@
-------------------------------------------------------------------------------
-- Title : UART
-- Project : UART
-------------------------------------------------------------------------------
-- File : Txunit.vhd
-- Author : Philippe CARTON
-- (philippe.carton2@libertysurf.fr)
-- Organization:
-- Created : 15/12/2001
-- Last update : 8/1/2003
-- Platform : Foundation 3.1i
-- Simulators : ModelSim 5.5b
-- Synthesizers: Xilinx Synthesis
-- Targets : Xilinx Spartan
-- Dependency : IEEE std_logic_1164
-------------------------------------------------------------------------------
-- Description: Txunit is a parallel to serial unit transmitter.
-------------------------------------------------------------------------------
-- Copyright (c) notice
-- This core adheres to the GNU public license
--
-------------------------------------------------------------------------------
-- Revisions :
-- Revision Number :
-- Version :
-- Date :
-- Modifier : name <email>
-- Description :
--
------------------------------------------------------------------------------
library ieee;
use ieee.std_logic_1164.all;
entity TxUnit is
port (
Clk : in std_logic; -- Clock signal
Reset : in std_logic; -- Reset input
Enable : in std_logic; -- Enable input
LoadA : in std_logic; -- Asynchronous Load
TxD : out std_logic; -- RS-232 data output
Busy : out std_logic; -- Tx Busy
DataI : in std_logic_vector(7 downto 0)); -- Byte to transmit
end TxUnit;
architecture Behaviour of TxUnit is
component synchroniser
port (
C1 : in std_logic; -- Asynchronous signal
C : in std_logic; -- Clock
O : out Std_logic);-- Synchronised signal
end component;
signal TBuff : std_logic_vector(7 downto 0); -- transmit buffer
signal TReg : std_logic_vector(7 downto 0); -- transmit register
signal TBufL : std_logic; -- Buffer loaded
signal LoadS : std_logic; -- Synchronised load signal
begin
-- Synchronise Load on Clk
SyncLoad : Synchroniser port map (LoadA, Clk, LoadS);
Busy <= LoadS or TBufL;
-- Tx process
TxProc : process(Clk, Reset, Enable, DataI, TBuff, TReg, TBufL)
variable BitPos : INTEGER range 0 to 10; -- Bit position in the frame
begin
if Reset = '1' then
TBufL <= '0';
BitPos := 0;
TxD <= '1';
elsif Rising_Edge(Clk) then
if LoadS = '1' then
TBuff <= DataI;
TBufL <= '1';
end if;
if Enable = '1' then
case BitPos is
when 0 => -- idle or stop bit
TxD <= '1';
if TBufL = '1' then -- start transmit. next is start bit
TReg <= TBuff;
TBufL <= '0';
BitPos := 1;
end if;
when 1 => -- Start bit
TxD <= '0';
BitPos := 2;
when others =>
TxD <= TReg(BitPos-2); -- Serialisation of TReg
BitPos := BitPos + 1;
end case;
if BitPos = 10 then -- bit8. next is stop bit
BitPos := 0;
end if;
end if;
end if;
end process;
end Behaviour;

View File

@ -0,0 +1,78 @@
library ieee;
use ieee.std_logic_1164.ALL;
use ieee.numeric_std.ALL;
library UNISIM;
use UNISIM.Vcomponents.ALL;
entity clock is
port ( clk_in : in std_logic;
clk : out std_logic;
clk180 : out std_logic);
end clock;
architecture BEHAVIORAL of clock is
signal CLKFB_IN : std_logic;
signal CLKFX_BUF : std_logic;
signal CLKFX180_BUF : std_logic;
signal CLKIN_IBUFG : std_logic;
signal CLK2X_BUF : std_logic;
begin
CLKFX_BUFG_INST : BUFG
port map (I=>CLKFX_BUF,
O=>clk);
CLKFX180_BUFG_INST : BUFG
port map (I=>CLKFX180_BUF,
O=>clk180);
CLKIN_IBUFG_INST : IBUFG
port map (I=>clk_in,
O=>CLKIN_IBUFG);
CLK2X_BUFG_INST : BUFG
port map (I=>CLK2X_BUF,
O=>CLKFB_IN);
DCM_SP_INST : DCM_SP
generic map(
CLK_FEEDBACK => "2X",
CLKDV_DIVIDE => 4.0,
CLKFX_DIVIDE => 1,
CLKFX_MULTIPLY => 2,
CLKIN_DIVIDE_BY_2 => FALSE,
CLKIN_PERIOD => 31.250,
CLKOUT_PHASE_SHIFT => "NONE",
DESKEW_ADJUST => "SYSTEM_SYNCHRONOUS",
DFS_FREQUENCY_MODE => "LOW",
DLL_FREQUENCY_MODE => "LOW",
DUTY_CYCLE_CORRECTION=> TRUE,
FACTORY_JF => x"C080",
PHASE_SHIFT => 0,
STARTUP_WAIT => TRUE)
port map (
CLKIN => CLKIN_IBUFG,
CLKFB => CLKFB_IN,
DSSEN => '0',
PSCLK => '0',
PSEN => '0',
PSINCDEC => '0',
RST => '0',
CLKDV => open,
CLKFX => CLKFX_BUF,
CLKFX180 => CLKFX180_BUF,
CLK2X => CLK2X_BUF,
CLK2X180 => open,
CLK0 => open,
CLK90 => open,
CLK180 => open,
CLK270 => open,
LOCKED => open,
PSDONE => open,
STATUS => open);
end BEHAVIORAL;

View File

@ -0,0 +1,199 @@
/*
Copyright (c) 2011
James Bowman All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of James Bowman nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
*/
module j1(
input sys_clk_i, input sys_rst_i, input [15:0] io_din,
output io_rd, output io_wr, output [15:0] io_addr, output [15:0] io_dout);
reg [15:0] insn;
wire [15:0] immediate = { 1'b0, insn[14:0] };
reg [4:0] dsp; // Data stack pointer
reg [4:0] _dsp;
reg [15:0] st0; // Return stack pointer
reg [15:0] _st0;
wire _dstkW; // D stack write
reg [12:0] pc;
reg [12:0] _pc;
reg [4:0] rsp;
reg [4:0] _rsp;
reg _rstkW; // R stack write
reg [15:0] _rstkD;
wire _ramWE; // RAM write enable
wire [15:0] pc_plus_1;
assign pc_plus_1 = pc + 1;
// The D and R stacks
reg [15:0] dstack[0:31];
reg [15:0] rstack[0:31];
always @(posedge sys_clk_i)
begin
if (_dstkW)
dstack[_dsp] = st0;
if (_rstkW)
rstack[_rsp] = _rstkD;
end
wire [15:0] st1 = dstack[dsp];
wire [15:0] rst0 = rstack[rsp];
// st0sel is the ALU operation. For branch and call the operation
// is T, for 0branch it is N. For ALU ops it is loaded from the instruction
// field.
reg [3:0] st0sel;
always @*
begin
case (insn[14:13])
2'b00: st0sel = 0; // ubranch
2'b10: st0sel = 0; // call
2'b01: st0sel = 1; // 0branch
2'b11: st0sel = insn[11:8]; // ALU
default: st0sel = 4'bxxxx;
endcase
end
// Papilio Pro: main memory to be infered instead of specified explitely.
reg [15:0] ram[0:16383]; initial $readmemh("../j1.hex", ram);
reg [15:0] mem_din;
always @(posedge sys_clk_i) begin
// $monitor("insn_addr= %h, insn = %h, sp=%h, rp=%h, S=%h %h", pc, insn, dsp, rsp, st1, st0);
insn <= ram[_pc];
mem_din <= ram[_st0[15:1]];
if (_ramWE & (_st0[15:14] ==0))
ram[_st0[15:1]] <= st1[15:0];
end
// Compute the new value of T.
always @*
begin
if (insn[15])
_st0 = immediate;
else
case (st0sel)
4'b0000: _st0 = st0;
4'b0001: _st0 = st1;
4'b0010: _st0 = st0 + st1;
4'b0011: _st0 = st0 & st1;
4'b0100: _st0 = st0 | st1;
4'b0101: _st0 = st0 ^ st1;
4'b0110: _st0 = ~st0;
4'b0111: _st0 = {16{(st1 == st0)}};
4'b1000: _st0 = {16{($signed(st1) < $signed(st0))}};
4'b1001: _st0 = st1 >> st0[3:0];
4'b1010: _st0 = st0 - 1;
4'b1011: _st0 = rst0;
4'b1100: _st0 = |st0[15:14] ? io_din : mem_din;
4'b1101: _st0 = st1 << st0[3:0];
4'b1110: _st0 = {rsp, 3'b000, dsp};
4'b1111: _st0 = {16{(st1 < st0)}};
default: _st0 = 16'hxxxx;
endcase
end
wire is_alu = (insn[15:13] == 3'b011);
wire is_lit = (insn[15]);
assign io_rd = (is_alu & (insn[11:8] == 4'hc));
assign io_wr = _ramWE;
assign io_addr = st0;
assign io_dout = st1;
assign _ramWE = is_alu & insn[5];
assign _dstkW = is_lit | (is_alu & insn[7]);
wire [1:0] dd = insn[1:0]; // D stack delta
wire [1:0] rd = insn[3:2]; // R stack delta
always @*
begin
if (is_lit) begin // literal
_dsp = dsp + 1;
_rsp = rsp;
_rstkW = 0;
_rstkD = _pc;
end else if (is_alu) begin
_dsp = dsp + {dd[1], dd[1], dd[1], dd};
_rsp = rsp + {rd[1], rd[1], rd[1], rd};
_rstkW = insn[6];
_rstkD = st0;
end else begin // jump/call
// predicated jump is like DROP
if (insn[15:13] == 3'b001) begin
_dsp = dsp - 1;
end else begin
_dsp = dsp;
end
if (insn[15:13] == 3'b010) begin // call
_rsp = rsp + 1;
_rstkW = 1;
_rstkD = {pc_plus_1[14:0], 1'b0};
end else begin
_rsp = rsp;
_rstkW = 0;
_rstkD = _pc;
end
end
end
always @*
begin
if (sys_rst_i)
_pc = pc;
else
if ((insn[15:13] == 3'b000) |
((insn[15:13] == 3'b001) & (|st0 == 0)) |
(insn[15:13] == 3'b010))
_pc = insn[12:0];
else if (is_alu & insn[12])
_pc = rst0[15:1];
else
_pc = pc_plus_1;
end
always @(posedge sys_clk_i)
begin
if (sys_rst_i) begin
pc <= 0;
dsp <= 0;
st0 <= 0;
rsp <= 0;
end else begin
dsp <= _dsp;
pc <= _pc;
st0 <= _st0;
rsp <= _rsp;
end
end
endmodule // j1

View File

@ -0,0 +1,146 @@
-------------------------------------------------------------------------------
-- Title : MINIUART2 -- this is a modified version without Wishbone interface
-- Project : MINIUART2
-------------------------------------------------------------------------------
-- File : MiniUart.vhd
-- Author : Philippe CARTON
-- (philippe.carton2@libertysurf.fr)
-- Organization:
-- Created : 15/12/2001
-- Last update : 8/1/2003
-- Platform : Foundation 3.1i
-- Simulators : ModelSim 5.5b
-- Synthesizers: Xilinx Synthesis
-- Targets : Xilinx Spartan
-- Dependency : IEEE std_logic_1164, Rxunit.vhd, Txunit.vhd, utils.vhd
-------------------------------------------------------------------------------
-- Description: Uart (Universal Asynchronous Receiver Transmitter) for SoC.
-- Wishbone compatable.
-------------------------------------------------------------------------------
-- Copyright (c) notice
-- This core adheres to the GNU public license
--
-------------------------------------------------------------------------------
-- Revisions :
-- Revision Number :
-- Version :
-- Date :
-- Modifier : name <email>
-- Description :
--
-------------------------------------------------------------------------------
-- Revision History:
-- 2014-12-19: removed wishbone interface (uh@xlerb.de)
library ieee;
use ieee.std_logic_1164.all;
entity MINIUART2 is
generic(BRDIVISOR: INTEGER range 0 to 65535 := 143); -- Baud rate divisor 143 = 115200 at 66 Mhz
port (
clk: in STD_LOGIC;
rst: in STD_LOGIC;
rx: in STD_LOGIC;
tx: out STD_LOGIC;
io_rd: in STD_LOGIC;
io_wr: in STD_LOGIC;
io_addr: in STD_LOGIC;
io_din: in STD_LOGIC_VECTOR (15 downto 0);
io_dout: out STD_LOGIC_VECTOR (15 downto 0));
end MINIUART2;
-- Architecture for UART for synthesis
architecture Behaviour of MINIUART2 is
component Counter
generic(COUNT: INTEGER range 0 to 65535); -- Count revolution
port (
Clk : in std_logic; -- Clock
Reset : in std_logic; -- Reset input
CE : in std_logic; -- Chip Enable
O : out std_logic); -- Output
end component;
component RxUnit
port (
Clk : in std_logic; -- system clock signal
Reset : in std_logic; -- Reset input
Enable : in std_logic; -- Enable input
ReadA : in Std_logic; -- Async Read Received Byte
RxD : in std_logic; -- RS-232 data input
RxAv : out std_logic; -- Byte available
DataO : out std_logic_vector(7 downto 0)); -- Byte received
end component;
component TxUnit
port (
Clk : in std_logic; -- Clock signal
Reset : in std_logic; -- Reset input
Enable : in std_logic; -- Enable input
LoadA : in std_logic; -- Asynchronous Load
TxD : out std_logic; -- RS-232 data output
Busy : out std_logic; -- Tx Busy
DataI : in std_logic_vector(7 downto 0)); -- Byte to transmit
end component;
signal RxData : std_logic_vector(7 downto 0); -- Last Byte received
signal TxData : std_logic_vector(7 downto 0); -- Last bytes transmitted
signal SReg : std_logic_vector(7 downto 0); -- Status register
signal EnabRx : std_logic; -- Enable RX unit
signal EnabTx : std_logic; -- Enable TX unit
signal RxAv : std_logic; -- Data Received
signal TxBusy : std_logic; -- Transmiter Busy
signal ReadA : std_logic; -- Async Read receive buffer
signal LoadA : std_logic; -- Async Load transmit buffer
signal Sig0 : std_logic; -- gnd signal
signal Sig1 : std_logic; -- vcc signal
begin
sig0 <= '0';
sig1 <= '1';
Uart_Rxrate : Counter -- Baud Rate adjust
generic map (COUNT => BRDIVISOR)
port map (clk, rst, sig1, EnabRx);
Uart_Txrate : Counter -- 4 Divider for Tx
generic map (COUNT => 4)
port map (clk, rst, EnabRx, EnabTx);
Uart_TxUnit : TxUnit port map (clk, rst, EnabTX, LoadA, tx, TxBusy, TxData);
Uart_RxUnit : RxUnit port map (clk, rst, EnabRX, ReadA, rx, RxAv, RxData);
-- status register
SReg(0) <= RxAv;
SReg(1) <= TxBusy;
SReg(7 downto 2) <= (others => '0'); -- the rest is silence
process (clk, rst, io_addr, io_wr, io_din)
begin
if Rising_Edge(clk) then
if rst='1' then
LoadA <= '0';
elsif io_wr='1' and io_addr='0' then -- write byte to tx
TxData <= io_din(7 downto 0);
LoadA <= '1';
else
LoadA <= '0';
end if;
end if;
end process;
process (clk, rst, io_addr, io_rd, RxData, TxBusy, RxAv)
begin
if Rising_Edge(clk) then
if rst='1' then
ReadA <= '0';
elsif io_rd='1' and io_addr='0' then
ReadA <= '1';
else
ReadA <= '0';
end if;
end if;
end process;
io_dout(7 downto 0) <= RxData when io_addr='0' else SReg;
io_dout(15 downto 8) <= (others => '0');
end Behaviour;

View File

@ -0,0 +1,117 @@
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
entity papilio_pro_j1 is
port (
clk_in: in std_logic;
rx: in std_logic;
tx: out std_logic;
wing: out std_logic_vector(15 downto 0));
end papilio_pro_j1;
architecture Behavioral of papilio_pro_j1 is
component clock is
port (
clk_in: in std_logic;
clk: out std_logic;
clk180: out std_logic);
end component;
component j1 is
port (
sys_clk_i: in std_logic;
sys_rst_i: in std_logic;
io_rd: out std_logic;
io_wr: out std_logic;
io_addr: out std_logic_vector (15 downto 0);
io_din: in std_logic_vector (15 downto 0);
io_dout: out std_logic_vector (15 downto 0));
end component;
component miniuart2 is
port (
clk: in STD_LOGIC;
rst: in STD_LOGIC;
rx: in STD_LOGIC;
tx: out STD_LOGIC;
io_rd: in STD_LOGIC;
io_wr: in STD_LOGIC;
io_addr: in STD_LOGIC;
io_din: in STD_LOGIC_VECTOR (15 downto 0);
io_dout: out STD_LOGIC_VECTOR (15 downto 0));
end component;
signal clk: std_logic;
signal clk180: std_logic;
signal rst_counter: integer range 0 to 15 := 15;
signal sys_rst: std_logic := '1';
signal io_rd: std_logic;
signal io_wr: std_logic;
signal io_addr: std_logic_vector (15 downto 0);
signal io_din: std_logic_vector (15 downto 0);
signal io_dout: std_logic_vector (15 downto 0);
signal uart_en: std_logic;
signal uart_rd: std_logic;
signal uart_wr: std_logic;
signal uart_dout: std_logic_vector (15 downto 0);
begin
clock_inst: clock
port map (
clk_in => clk_in,
clk => clk,
clk180 => clk180);
j1_inst: j1
port map (
sys_clk_i => clk,
sys_rst_i => sys_rst,
io_rd => io_rd,
io_wr => io_wr,
io_addr => io_addr,
io_din => io_din,
io_dout => io_dout);
uart_inst: miniuart2
port map(
clk => clk180,
rst => sys_rst,
rx => rx,
tx => tx,
io_rd => uart_rd,
io_wr => uart_wr,
io_addr => io_addr(0),
io_din => io_dout,
io_dout => uart_dout);
process (clk, rst_counter)
begin
if rising_edge(clk) and rst_counter>0 then
rst_counter <= rst_counter-1;
end if;
end process;
sys_rst <= '1' when rst_counter>0 else '0';
uart_en <= '1' when io_addr(15 downto 1)="111100000000000" else '0';
uart_rd <= io_rd and uart_en;
uart_wr <= io_wr and uart_en;
process (io_addr, uart_dout)
begin
case io_addr(15 downto 1) is
when "111100000000000" =>
io_din <= uart_dout;
when others =>
io_din <= (others=>'0');
end case;
end process;
wing <= (others=>'0');
end Behavioral;

View File

@ -0,0 +1,143 @@
# UCF file for the Papilio Pro board
# Generated by pin_converter, written by Kevin Lindsey
# https://github.com/thelonious/papilio_pins/tree/development/pin_converter
# Main board wing pin [] to FPGA pin Pxx map
# -------C------- -------B------- -------A-------
# [GND] [C00] P114 [GND] [B00] P99 P100 [A15]
# [2V5] [C01] P115 [2V5] [B01] P97 P98 [A14]
# [3V3] [C02] P116 [3V3] [B02] P92 P93 [A13]
# [5V0] [C03] P117 [5V0] [B03] P87 P88 [A12]
# [C04] P118 [B04] P84 P85 [A11] [5V0]
# [C05] P119 [B05] P82 P83 [A10] [3V3]
# [C06] P120 [B06] P80 P81 [A09] [2V5]
# [C07] P121 [B07] P78 P79 [A08] [GND]
# [GND] [C08] P123 [GND] [B08] P74 P75 [A07]
# [2V5] [C09] P124 [2V5] [B09] P95 P67 [A06]
# [3V3] [C10] P126 [3V3] [B10] P62 P66 [A05]
# [5V0] [C11] P127 [5V0] [B11] P59 P61 [A04]
# [C12] P131 [B12] P57 P58 [A03] [5V0]
# [C13] P132 [B13] P55 P56 [A02] [3V3]
# [C14] P133 [B14] P50 P51 [A01] [2V5]
# [C15] P134 [B15] P47 P48 [A00] [GND]
## Prohibit the automatic placement of pins that are connected to VCC or GND for configuration.
CONFIG PROHIBIT=P144;
CONFIG PROHIBIT=P69;
CONFIG PROHIBIT=P60;
NET CLK_IN LOC="P94" | IOSTANDARD=LVTTL | PERIOD=31.25ns; # CLK
NET RX LOC="P101" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # RX
NET TX LOC="P105" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # TX
NET WING(0) LOC="P48" | IOSTANDARD=LVTTL; # A0
NET WING(1) LOC="P51" | IOSTANDARD=LVTTL; # A1
NET WING(2) LOC="P56" | IOSTANDARD=LVTTL; # A2
NET WING(3) LOC="P58" | IOSTANDARD=LVTTL; # A3
NET WING(4) LOC="P61" | IOSTANDARD=LVTTL; # A4
NET WING(5) LOC="P66" | IOSTANDARD=LVTTL; # A5
NET WING(6) LOC="P67" | IOSTANDARD=LVTTL; # A6
NET WING(7) LOC="P75" | IOSTANDARD=LVTTL; # A7
NET WING(8) LOC="P79" | IOSTANDARD=LVTTL; # A8
NET WING(9) LOC="P81" | IOSTANDARD=LVTTL; # A9
NET WING(10) LOC="P83" | IOSTANDARD=LVTTL; # A10
NET WING(11) LOC="P85" | IOSTANDARD=LVTTL; # A11
NET WING(12) LOC="P88" | IOSTANDARD=LVTTL; # A12
NET WING(13) LOC="P93" | IOSTANDARD=LVTTL; # A13
NET WING(14) LOC="P98" | IOSTANDARD=LVTTL; # A14
NET WING(15) LOC="P100" | IOSTANDARD=LVTTL; # A15
#NET A(0) LOC="P48" | IOSTANDARD=LVTTL; # A0
#NET A(1) LOC="P51" | IOSTANDARD=LVTTL; # A1
#NET A(2) LOC="P56" | IOSTANDARD=LVTTL; # A2
#NET A(3) LOC="P58" | IOSTANDARD=LVTTL; # A3
#NET A(4) LOC="P61" | IOSTANDARD=LVTTL; # A4
#NET A(5) LOC="P66" | IOSTANDARD=LVTTL; # A5
#NET A(6) LOC="P67" | IOSTANDARD=LVTTL; # A6
#NET A(7) LOC="P75" | IOSTANDARD=LVTTL; # A7
#NET A(8) LOC="P79" | IOSTANDARD=LVTTL; # A8
#NET A(9) LOC="P81" | IOSTANDARD=LVTTL; # A9
#NET A(10) LOC="P83" | IOSTANDARD=LVTTL; # A10
#NET A(11) LOC="P85" | IOSTANDARD=LVTTL; # A11
#NET A(12) LOC="P88" | IOSTANDARD=LVTTL; # A12
#NET A(13) LOC="P93" | IOSTANDARD=LVTTL; # A13
#NET A(14) LOC="P98" | IOSTANDARD=LVTTL; # A14
#NET A(15) LOC="P100" | IOSTANDARD=LVTTL; # A15
#NET B(0) LOC="P99" | IOSTANDARD=LVTTL; # B0
#NET B(1) LOC="P97" | IOSTANDARD=LVTTL; # B1
#NET B(2) LOC="P92" | IOSTANDARD=LVTTL; # B2
#NET B(3) LOC="P87" | IOSTANDARD=LVTTL; # B3
#NET B(4) LOC="P84" | IOSTANDARD=LVTTL; # B4
#NET B(5) LOC="P82" | IOSTANDARD=LVTTL; # B5
#NET B(6) LOC="P80" | IOSTANDARD=LVTTL; # B6
#NET B(7) LOC="P78" | IOSTANDARD=LVTTL; # B7
#NET B(8) LOC="P74" | IOSTANDARD=LVTTL; # B8
#NET B(9) LOC="P95" | IOSTANDARD=LVTTL; # B9
#NET B(10) LOC="P62" | IOSTANDARD=LVTTL; # B10
#NET B(11) LOC="P59" | IOSTANDARD=LVTTL; # B11
#NET B(12) LOC="P57" | IOSTANDARD=LVTTL; # B12
#NET B(13) LOC="P55" | IOSTANDARD=LVTTL; # B13
#NET B(14) LOC="P50" | IOSTANDARD=LVTTL; # B14
#NET B(15) LOC="P47" | IOSTANDARD=LVTTL; # B15
#NET C(0) LOC="P114" | IOSTANDARD=LVTTL; # C0
#NET C(1) LOC="P115" | IOSTANDARD=LVTTL; # C1
#NET C(2) LOC="P116" | IOSTANDARD=LVTTL; # C2
#NET C(3) LOC="P117" | IOSTANDARD=LVTTL; # C3
#NET C(4) LOC="P118" | IOSTANDARD=LVTTL; # C4
#NET C(5) LOC="P119" | IOSTANDARD=LVTTL; # C5
#NET C(6) LOC="P120" | IOSTANDARD=LVTTL; # C6
#NET C(7) LOC="P121" | IOSTANDARD=LVTTL; # C7
#NET C(8) LOC="P123" | IOSTANDARD=LVTTL; # C8
#NET C(9) LOC="P124" | IOSTANDARD=LVTTL; # C9
#NET C(10) LOC="P126" | IOSTANDARD=LVTTL; # C10
#NET C(11) LOC="P127" | IOSTANDARD=LVTTL; # C11
#NET C(12) LOC="P131" | IOSTANDARD=LVTTL; # C12
#NET C(13) LOC="P132" | IOSTANDARD=LVTTL; # C13
#NET C(14) LOC="P133" | IOSTANDARD=LVTTL; # C14
#NET C(15) LOC="P134" | IOSTANDARD=LVTTL; # C15
#NET SDRAM_ADDR(0) LOC="P140" | IOSTANDARD=LVTTL; # SDRAM_ADDR0
#NET SDRAM_ADDR(1) LOC="P139" | IOSTANDARD=LVTTL; # SDRAM_ADDR1
#NET SDRAM_ADDR(2) LOC="P138" | IOSTANDARD=LVTTL; # SDRAM_ADDR2
#NET SDRAM_ADDR(3) LOC="P137" | IOSTANDARD=LVTTL; # SDRAM_ADDR3
#NET SDRAM_ADDR(4) LOC="P46" | IOSTANDARD=LVTTL; # SDRAM_ADDR4
#NET SDRAM_ADDR(5) LOC="P45" | IOSTANDARD=LVTTL; # SDRAM_ADDR5
#NET SDRAM_ADDR(6) LOC="P44" | IOSTANDARD=LVTTL; # SDRAM_ADDR6
#NET SDRAM_ADDR(7) LOC="P43" | IOSTANDARD=LVTTL; # SDRAM_ADDR7
#NET SDRAM_ADDR(8) LOC="P41" | IOSTANDARD=LVTTL; # SDRAM_ADDR8
#NET SDRAM_ADDR(9) LOC="P40" | IOSTANDARD=LVTTL; # SDRAM_ADDR9
#NET SDRAM_ADDR(10) LOC="P141" | IOSTANDARD=LVTTL; # SDRAM_ADDR10
#NET SDRAM_ADDR(11) LOC="P35" | IOSTANDARD=LVTTL; # SDRAM_ADDR11
#NET SDRAM_ADDR(12) LOC="P34" | IOSTANDARD=LVTTL; # SDRAM_ADDR12
#NET SDRAM_DATA(0) LOC="P9" | IOSTANDARD=LVTTL; # SDRAM_DATA0
#NET SDRAM_DATA(1) LOC="P10" | IOSTANDARD=LVTTL; # SDRAM_DATA1
#NET SDRAM_DATA(2) LOC="P11" | IOSTANDARD=LVTTL; # SDRAM_DATA2
#NET SDRAM_DATA(3) LOC="P12" | IOSTANDARD=LVTTL; # SDRAM_DATA3
#NET SDRAM_DATA(4) LOC="P14" | IOSTANDARD=LVTTL; # SDRAM_DATA4
#NET SDRAM_DATA(5) LOC="P15" | IOSTANDARD=LVTTL; # SDRAM_DATA5
#NET SDRAM_DATA(6) LOC="P16" | IOSTANDARD=LVTTL; # SDRAM_DATA6
#NET SDRAM_DATA(7) LOC="P8" | IOSTANDARD=LVTTL; # SDRAM_DATA7
#NET SDRAM_DATA(8) LOC="P21" | IOSTANDARD=LVTTL; # SDRAM_DATA8
#NET SDRAM_DATA(9) LOC="P22" | IOSTANDARD=LVTTL; # SDRAM_DATA9
#NET SDRAM_DATA(10) LOC="P23" | IOSTANDARD=LVTTL; # SDRAM_DATA10
#NET SDRAM_DATA(11) LOC="P24" | IOSTANDARD=LVTTL; # SDRAM_DATA11
#NET SDRAM_DATA(12) LOC="P26" | IOSTANDARD=LVTTL; # SDRAM_DATA12
#NET SDRAM_DATA(13) LOC="P27" | IOSTANDARD=LVTTL; # SDRAM_DATA13
#NET SDRAM_DATA(14) LOC="P29" | IOSTANDARD=LVTTL; # SDRAM_DATA14
#NET SDRAM_DATA(15) LOC="P30" | IOSTANDARD=LVTTL; # SDRAM_DATA15
#NET SDRAM_DQML LOC="P7" | IOSTANDARD=LVTTL; # SDRAM_DQML
#NET SDRAM_DQMH LOC="P17" | IOSTANDARD=LVTTL; # SDRAM_DQMH
#NET SDRAM_BA(0) LOC="P143" | IOSTANDARD=LVTTL; # SDRAM_BA0
#NET SDRAM_BA(1) LOC="P142" | IOSTANDARD=LVTTL; # SDRAM_BA1
#NET SDRAM_nWE LOC="P6" | IOSTANDARD=LVTTL; # SDRAM_nWE
#NET SDRAM_nCAS LOC="P5" | IOSTANDARD=LVTTL; # SDRAM_nCAS
#NET SDRAM_nRAS LOC="P2" | IOSTANDARD=LVTTL; # SDRAM_nRAS
#NET SDRAM_CS LOC="P1" | IOSTANDARD=LVTTL; # SDRAM_CS
#NET SDRAM_CLK LOC="P32" | IOSTANDARD=LVTTL; # SDRAM_CLK
#NET SDRAM_CKE LOC="P33" | IOSTANDARD=LVTTL; # SDRAM_CKE
#NET LED1 LOC="P112" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=SLOW; # LED1
#NET JTAG_TMS LOC="P107" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TMS
#NET JTAG_TCK LOC="P109" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TCK
#NET JTAG_TDI LOC="P110" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TDI
#NET JTAG_TDO LOC="P106" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # JTAG_TDO
#NET FLASH_CS LOC="P38" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_CS
#NET FLASH_CK LOC="P70" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_CK
#NET FLASH_SI LOC="P64" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # FLASH_SI
#NET FLASH_SO LOC="P65" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST | PULLUP; # FLASH_SO

View File

@ -0,0 +1,132 @@
-------------------------------------------------------------------------------
-- Title : UART
-- Project : UART
-------------------------------------------------------------------------------
-- File : utils.vhd
-- Author : Philippe CARTON
-- (philippe.carton2@libertysurf.fr)
-- Organization:
-- Created : 15/12/2001
-- Last update : 8/1/2003
-- Platform : Foundation 3.1i
-- Simulators : ModelSim 5.5b
-- Synthesizers: Xilinx Synthesis
-- Targets : Xilinx Spartan
-- Dependency : IEEE std_logic_1164
-------------------------------------------------------------------------------
-- Description: VHDL utility file
-------------------------------------------------------------------------------
-- Copyright (c) notice
-- This core adheres to the GNU public license
--
-------------------------------------------------------------------------------
-- Revisions :
-- Revision Number :
-- Version :
-- Date :
-- Modifier : name <email>
-- Description :
--
------------------------------------------------------------------------------
-------------------------------------------------------------------------------
-- Revision list
-- Version Author Date Changes
--
-- 1.0 Philippe CARTON 19 December 2001 New model
-- philippe.carton2@libertysurf.fr
-------------------------------------------------------------------------------
--------------------------------------------------------------------------------
-- Synchroniser:
-- Synchronize an input signal (C1) with an input clock (C).
-- The result is the O signal which is synchronous of C, and persist for
-- one C clock period.
--------------------------------------------------------------------------------
library IEEE,STD;
use IEEE.std_logic_1164.all;
entity synchroniser is
port (
C1 : in std_logic;-- Asynchronous signal
C : in std_logic;-- Clock
O : out std_logic);-- Synchronised signal
end synchroniser;
architecture Behaviour of synchroniser is
signal C1A : std_logic;
signal C1S : std_logic;
signal R : std_logic;
begin
RiseC1A : process(C1,R)
begin
if Rising_Edge(C1) then
C1A <= '1';
end if;
if (R = '1') then
C1A <= '0';
end if;
end process;
SyncP : process(C,R)
begin
if Rising_Edge(C) then
if (C1A = '1') then
C1S <= '1';
else C1S <= '0';
end if;
if (C1S = '1') then
R <= '1';
else R <= '0';
end if;
end if;
if (R = '1') then
C1S <= '0';
end if;
end process;
O <= C1S;
end Behaviour;
-------------------------------------------------------------------------------
-- Counter
-- This counter is a parametrizable clock divider.
-- The count value is the generic parameter Count.
-- It is CE enabled. (it will count only if CE is high).
-- When it overflow, it will emit a pulse on O.
-- It can be reseted to 0.
-------------------------------------------------------------------------------
library IEEE,STD;
use IEEE.std_logic_1164.all;
entity Counter is
generic(Count: INTEGER range 0 to 65535); -- Count revolution
port (
Clk : in std_logic; -- Clock
Reset : in std_logic; -- Reset input
CE : in std_logic; -- Chip Enable
O : out std_logic); -- Output
end Counter;
architecture Behaviour of Counter is
begin
counter : process(Clk,Reset)
variable Cnt : INTEGER range 0 to Count-1;
begin
if Reset = '1' then
Cnt := Count - 1;
O <= '0';
elsif Rising_Edge(Clk) then
if CE = '1' then
if Cnt = 0 then
O <= '1';
Cnt := Count - 1;
else
O <= '0';
Cnt := Cnt - 1;
end if;
else O <= '0';
end if;
end if;
end process;
end Behaviour;

View File

@ -0,0 +1,249 @@
(
I feel that the Kernel is at it's best for now and that I can proceed
to do some other things. Note that version 1 is just to make the whole
thing work, later on I might look at optimisation where I might have to move
some stuff around so that memory utilization and execution speed efficiency is
achieved.So far the Kernel works without needing tweaks.
Work in progress: Implementing simple ipv4 for the j1eforth model
7 project targets:
1. Add multi-tasking support to the Kernel - 0%
2. Modify j1 sim to use pcap interface for network tx and rx - 0%
3. ARP - 0%
4. ICMP - 0%
5. IP - 0%
6. UDP - 0%
7. TCP - 0%
Hopefully I will get time to do all this and also document the design of
the j1eforth Kernel for those who are starting out with forth and also those
who wish to tinker with the Kernel for fun.
)
hex
forth-wordlist >voc forth
vocabulary ipv4.1
only forth also ipv4.1
ipv4.1 definitions
variable active_struct
: field
create over , +
does>
@ active_struct @ + ;
( ethernet frame )
0
6 field eth_dest ( 48 bit source address )
6 field eth_src ( 48 bit destination address )
2 field eth_type ( 16 bit type )
constant eth_frame%
( arp message )
0
2 field arp_hw ( 16 bit hw type )
2 field arp_proto ( 16 bit protocol )
1 field arp_hlen ( 8 bit hw address length )
1 field arp_plen ( 8 bit protocol address length )
2 field arp_op ( 16 bit operation )
6 field arp_shw ( 48 bit sender hw address )
4 field arp_sp ( 32 bit sender ipv4 address )
6 field arp_thw ( 48 bit target hw address )
4 field arp_tp ( 32 bit target ipv4 address )
constant arp_message%
( arp cache )
0
4 field ac_ip ( 32 bit protocol address )
6 field ac_hw ( 48 bit hw address )
constant arp_cache%
( ipv4 datagram header )
0
1 field ip_vhl ( 4 bit version and 4 bit header length )
1 field ip_tos ( 8 bit type of service )
2 field ip_len ( 16 bit length )
2 field ip_id ( 16 bit identification )
2 field ip_frags ( 3 bit flags 13 bit fragment offset )
1 field ip_ttl ( 8 bit time to live )
1 field ip_proto ( 8 bit protocol number )
2 field ip_checksum ( 16 bit checksum )
4 field ip_source ( 32 bit source address )
4 field ip_dest ( 32 bit destination address )
constant ip_header%
( icmp header )
0
1 field icmp_type ( 8 bits type )
1 field icmp_code ( 8 bits code )
2 field icmp_checksum ( 16 bits checksum )
constant icmp_header%
( udp datagram )
0
2 field udp_source ( 16 bit source port )
2 field udp_dest ( 16 bit destination port )
2 field udp_len ( 16 bit length )
2 field udp_checksum ( 16 bit checksum )
constant udp_datagram%
( tcp header )
0
2 field tcp_source ( 16 bit source port )
2 field tcp_dest ( 16 bit destination port )
4 field tcp_seq ( 32 bit sequence number )
4 field tcp_ack ( 32 bit acknowledgement )
1 field tcp_offset ( 8 bit offset )
2 field tcp_flags ( 16 bit flags )
1 field tcp_window ( 8 bit window size )
2 field tcp_checksum ( 16 bit checksum )
2 field tcp_urgent ( 16 bit urgent pointer )
constant tcp_header%
4000 constant eth_rx_buf
: htons ( n -- n )
dup ff and 8 lshift swap ff00 and 8 rshift or ;
create ip_addr a8c0 , fe0b ,
create ip_netmask ffff , 00ff ,
create hw_addr bd00 , 333b , 7f05 ,
8 constant eth_ip_type
608 constant eth_arp_type
3580 constant eth_rarp_type
100 constant arp_request_type
200 constant arp_reply_type
0 constant icmp_echo_reply
8 constant icmp_echo
0 constant arp_action
: arp_lookup 0 to arp_action ;
: arp_update 1 to arp_action ;
: arp_insert 2 to arp_action ;
: arp_delete 3 to arp_action ;
: +arp_age 4 to arp_action ;
: (arp_lookup) cr ." compare" . . ;
: (arp_update) cr ." update" . . ;
: (arp_insert) cr ." insert" ;
: (arp_delete) cr ." delete" ;
: (+arp_age) cr ." age" ;
: arp_table ( u -- )
create here over allot swap erase
does>
swap arp_cache% * +
arp_action 0 to arp_action
case
0 of (arp_lookup) endof
1 of (arp_update) endof
2 of (arp_insert) endof
3 of (arp_delete) endof
4 of (+arp_age) endof
." unknown cache option"
endcase ;
arp_cache% 8 * arp_table arp_cache
: eth_rx f008 @ ;
: eth_tx f008 ! ;
: checksum ( address count -- checksum)
over + 0 -rot
do
i @ + i @ over u> if 1+ then
-2 +loop
dup 10 rshift swap ffff and +
dup 10 rshift +
ffff xor ;
: arp_in ( -- )
eth_frame% active_struct +!
arp_op @ arp_request_type = if
100 arp_hw !
eth_ip_type arp_proto !
6 arp_hlen c!
4 arp_plen c!
arp_reply_type arp_op !
arp_shw arp_thw 6 cmove
hw_addr arp_shw 6 cmove
arp_sp arp_tp 4 cmove
ip_addr arp_sp 4 cmove
arp_thw
eth_rx_buf active_struct !
eth_dest 6 cmove
hw_addr eth_src 6 cmove
eth_arp_type eth_type !
eth_tx
else
( arp_update )
then ;
: icmp_in
ip_len @ htons
ip_header% active_struct +!
icmp_type c@ 8 = if
0 icmp_type c!
icmp_checksum @ fff7 = if
9 icmp_checksum +!
else 8 icmp_checksum +! then
else
cr ." weird icmp packet"
then eth_tx ;
: udp_in cr ." got udp packet." ;
: tcp_in cr ." got tcp packet." ;
: ip_in ( -- )
eth_frame% active_struct +!
ip_vhl @ 45 = if
ip_proto c@ case
1 of
ip_source dup ip_dest 4 cmove
ip_addr swap 4 cmove
icmp_in
endof
6 of tcp_in endof
17 of udp_in endof
cr ." unknown ip protocol:"
endcase
else
cr ." unsupported ip version detected"
then ;
: process ( -- )
eth_type @ case
eth_arp_type of arp_in endof
eth_ip_type of ip_in endof
cr ." unknown ethernet protocol"
endcase ;
: pcap_poll
eth_rx_buf active_struct !
active_struct @ 5dc erase
eth_rx ;
: round
pcap_poll 0 <> if
process
then ;
: main
begin
round
again
;
( main )
forth definitions
ipv4.1 definitions

View File

@ -0,0 +1,946 @@
(
eForth 1.04 for j1 Simulator by Edward A., July 2014
Much of the code is derived from the following sources:
j1 Cross-compiler by James Bowman August 2010
8086 eForth 1.0 by Bill Muench and C. H. Ting, 1990
)
only forth definitions hex
wordlist constant meta.1
wordlist constant target.1
wordlist constant assembler.1
: (order) ( w wid*n n -- wid*n w n )
dup if
1- swap >r recurse over r@ xor if
1+ r> -rot exit then r> drop then ;
: -order ( wid -- ) get-order (order) nip set-order ;
: +order ( wid -- ) dup >r -order get-order r> swap 1+ set-order ;
: ]asm ( -- ) assembler.1 +order ; immediate
get-current meta.1 set-current
: [a] ( "name" -- )
parse-word assembler.1 search-wordlist 0=
abort" [a]?" compile, ; immediate
: a: ( "name" -- )
get-current >r assembler.1 set-current
: r> set-current ;
target.1 +order meta.1 +order
a: asm[ ( -- ) assembler.1 -order ; immediate
create tflash 1000 cells here over erase allot
variable tdp
: there tdp @ ;
: tc! tflash + c! ;
: tc@ tflash + c@ ;
: t! over ff and over tc! swap 8 rshift swap 1+ tc! ;
: t@ dup tc@ swap 1+ tc@ 8 lshift or ;
: talign there 1 and tdp +! ;
: tc, there tc! 1 tdp +! ;
: t, there t! 2 tdp +! ;
: $literal [char] " word count dup tc, 0 ?do
count tc, loop drop talign ;
: tallot tdp +! ;
: org tdp ! ;
a: t 0000 ;
a: n 0100 ;
a: t+n 0200 ;
a: t&n 0300 ;
a: t|n 0400 ;
a: t^n 0500 ;
a: ~t 0600 ;
a: n==t 0700 ;
a: n<t 0800 ;
a: n>>t 0900 ;
a: t-1 0a00 ;
a: rt 0b00 ;
a: [t] 0c00 ;
a: n<<t 0d00 ;
a: dsp 0e00 ;
a: nu<t 0f00 ;
a: t==0 0010 ;
a: t<>0 0110 ;
a: n<>t 0210 ;
a: t+1 0310 ;
a: t<<1 0410 ;
a: t>>1 0510 ;
a: n>t 0610 ;
a: nu>t 0710 ;
a: t<0 0810 ;
a: t>0 0910 ;
a: abst 0a10 ;
a: mxnt 0b10 ;
a: mnnt 0c10 ;
a: negt 0d10 ;
a: n-t 0e10 ;
a: n>=t 0f10 ;
a: t->n 0080 or ;
a: t->r 0040 or ;
a: n->[t] 0020 or ;
a: d-1 0003 or ;
a: d+1 0001 or ;
a: r-1 000c or ;
a: r-2 0008 or ;
a: r+1 0004 or ;
a: alu 6000 or t, ;
a: return [a] t 1000 or [a] r-1 [a] alu ;
a: branch 2/ 0000 or t, ;
a: ?branch 2/ 2000 or t, ;
a: call 2/ 4000 or t, ;
a: literal
dup 8000 and if
ffff xor recurse
[a] ~t [a] alu
else
8000 or t,
then ;
variable tlast
variable tuser
0001 constant =ver
0002 constant =ext
0040 constant =comp
0080 constant =imed
7f1f constant =mask
0002 constant =cell
0010 constant =base
0008 constant =bksp
000a constant =lf
000d constant =cr
4000 constant =em
0000 constant =cold
8 constant =vocs
80 constant =us
=em 100 - constant =tib
=tib =us - constant =up
=cold =us + constant =pick
=pick 100 + constant =code
: thead
talign
tlast @ t, there tlast !
parse-word dup tc, 0 ?do count tc, loop drop talign ;
: twords
cr tlast @
begin
dup tflash + count 1f and type space =cell - t@
?dup 0= until ;
: [t]
parse-word target.1 search-wordlist 0=
abort" [t]?" >body @ ; immediate
: [last] tlast @ ; immediate
: ( [char] ) parse 2drop ; immediate
: literal [a] literal ;
: lookback there =cell - t@ ;
: call? lookback e000 and 4000 = ;
: call>goto there =cell - dup t@ 1fff and swap t! ;
: safe? lookback e000 and 6000 = lookback 004c and 0= and ;
: alu>return there =cell - dup t@ 1000 or [a] r-1 swap t! ;
: t:
>in @ thead >in !
get-current >r target.1 set-current create
r> set-current 947947 talign there , does> @ [a] call ;
: exit
call? if
call>goto else safe? if
alu>return else
[a] return
then
then ;
: t;
947947 <> if
abort" unstructured" then true if
exit else [a] return then ;
: u:
>in @ thead >in !
get-current >r target.1 set-current create
r> set-current talign tuser @ dup ,
[a] literal exit =cell tuser +! does> @ [a] literal ;
: [u]
parse-word target.1 search-wordlist 0=
abort" [t]?" >body @ =up - =cell + ; immediate
: immediate tlast @ tflash + dup c@ =imed or swap c! ;
: compile-only tlast @ tflash + dup c@ =comp or swap c! ;
0 tlast !
=up tuser !
: hex# ( u -- addr len ) 0 <# base @ >r hex =lf hold # # # # r> base ! #> ;
: save-hex ( <name> -- )
parse-word w/o create-file throw
there 0 do i t@ over >r hex# r> write-file throw 2 +loop
close-file throw ;
: save-target ( <name> -- )
parse-word w/o create-file throw >r
tflash there r@ write-file throw r> close-file ;
: begin there ;
: until [a] ?branch ;
: if there 0 [a] ?branch ;
: skip there 0 [a] branch ;
: then begin 2/ over t@ or swap t! ;
: else skip swap then ;
: while if swap ;
: repeat [a] branch then ;
: again [a] branch ;
: aft drop skip begin swap ;
: noop ]asm t alu asm[ ;
: + ]asm t+n d-1 alu asm[ ;
: xor ]asm t^n d-1 alu asm[ ;
: and ]asm t&n d-1 alu asm[ ;
: or ]asm t|n d-1 alu asm[ ;
: invert ]asm ~t alu asm[ ;
: = ]asm n==t d-1 alu asm[ ;
: < ]asm n<t d-1 alu asm[ ;
: u< ]asm nu<t d-1 alu asm[ ;
: swap ]asm n t->n alu asm[ ;
: dup ]asm t t->n d+1 alu asm[ ;
: drop ]asm n d-1 alu asm[ ;
: over ]asm n t->n d+1 alu asm[ ;
: nip ]asm t d-1 alu asm[ ;
: >r ]asm n t->r r+1 d-1 alu asm[ ;
: r> ]asm rt t->n r-1 d+1 alu asm[ ;
: r@ ]asm rt t->n d+1 alu asm[ ;
: @ ]asm [t] alu asm[ ;
: ! ]asm t n->[t] d-1 alu
n d-1 alu asm[ ;
: dsp ]asm dsp t->n d+1 alu asm[ ;
: lshift ]asm n<<t d-1 alu asm[ ;
: rshift ]asm n>>t d-1 alu asm[ ;
: 1- ]asm t-1 alu asm[ ;
: 2r> ]asm rt t->n r-1 d+1 alu
rt t->n r-1 d+1 alu
n t->n alu asm[ ;
: 2>r ]asm n t->n alu
n t->r r+1 d-1 alu
n t->r r+1 d-1 alu asm[ ;
: 2r@ ]asm rt t->n r-1 d+1 alu
rt t->n r-1 d+1 alu
n t->n d+1 alu
n t->n d+1 alu
n t->r r+1 d-1 alu
n t->r r+1 d-1 alu
n t->n alu asm[ ;
: unloop
]asm t r-1 alu
t r-1 alu asm[ ;
( new J1+ ALU operations )
: 0= ]asm t==0 alu asm[ ;
: 0<> ]asm t<>0 alu asm[ ;
: <> ]asm n<>t d-1 alu asm[ ;
: 1+ ]asm t+1 alu asm[ ;
: 2* ]asm t<<1 alu asm[ ;
( : 2/ ]asm t>>1 alu asm[ ; ) ( uncommenting causes error )
: > ]asm n>t d-1 alu asm[ ;
: u> ]asm nu>t d-1 alu asm[ ;
: 0< ]asm t<0 alu asm[ ;
: 0> ]asm t>0 alu asm[ ;
: abs ]asm abst alu asm[ ;
: max ]asm mxnt d-1 alu asm[ ;
: min ]asm mnnt d-1 alu asm[ ;
: negate ]asm negt alu asm[ ;
( : - ]asm n-t d-1 alu asm[ ; ) ( uncommenting causes error )
: >= ]asm n>=t d-1 alu asm[ ;
: dup@ ]asm [t] t->n d+1 alu asm[ ;
: dup>r ]asm t t->r r+1 alu asm[ ;
: 2dupxor ]asm t^n t->n d+1 alu asm[ ;
: 2dup= ]asm n==t t->n d+1 alu asm[ ;
: !nip ]asm t n->[t] d-1 alu asm[ ;
: 2dup! ]asm t n->[t] alu asm[ ;
: up1 ]asm t d+1 alu asm[ ;
: down1 ]asm t d-1 alu asm[ ;
: copy ]asm n alu asm[ ;
a: down e for down1 next copy exit ;
a: up e for up1 next noop exit ;
: for >r begin ;
: next r@ while r> 1- >r repeat r> drop ;
=pick org
]asm down up asm[
there constant =pickbody
copy ]asm return asm[
9c ]asm call asm[ bc ]asm branch asm[
9a ]asm call asm[ ba ]asm branch asm[
98 ]asm call asm[ b8 ]asm branch asm[
96 ]asm call asm[ b6 ]asm branch asm[
94 ]asm call asm[ b4 ]asm branch asm[
92 ]asm call asm[ b2 ]asm branch asm[
90 ]asm call asm[ b0 ]asm branch asm[
8e ]asm call asm[ ae ]asm branch asm[
8c ]asm call asm[ ac ]asm branch asm[
8a ]asm call asm[ aa ]asm branch asm[
88 ]asm call asm[ a8 ]asm branch asm[
86 ]asm call asm[ a6 ]asm branch asm[
84 ]asm call asm[ a4 ]asm branch asm[
82 ]asm call asm[ a2 ]asm branch asm[
80 ]asm call asm[ a0 ]asm branch asm[
]asm return asm[
=cold org
0 t,
there constant =uzero
=base t, ( base )
0 t, ( temp )
0 t, ( >in )
0 t, ( #tib )
=tib t, ( tib )
0 t, ( 'eval )
0 t, ( 'abort )
0 t, ( hld )
( context )
0 t, 0 t, 0 t, 0 t, 0 t, 0 t, 0 t, 0 t, 0 t,
( forth-wordlist )
0 t, ( na, of last definition, linked )
0 t, ( wid|0, next or last wordlist in chain )
0 t, ( na, wordlist name pointer )
( current )
0 t, ( wid, new definitions )
0 t, ( wid, head of chain )
0 t, ( dp )
0 t, ( last )
0 t, ( '?key )
0 t, ( 'emit )
0 t, ( 'boot )
0 t, ( '\ )
0 t, ( '?name )
0 t, ( '$,n )
0 t, ( 'overt )
0 t, ( '; )
0 t, ( 'create )
there constant =ulast
=ulast =uzero - constant =udiff
=code org
t: noop noop t;
t: + + t;
t: xor xor t;
t: and and t;
t: or or t;
t: invert invert t;
t: = = t;
t: < < t;
t: u< u< t;
t: swap swap t;
t: u> u> t;
t: dup dup t;
t: drop drop t;
t: over over t;
t: nip nip t;
t: lshift lshift t;
t: rshift rshift t;
t: 1- 1- t;
t: >r r> swap >r >r t; compile-only
t: r> r> r> swap >r t; compile-only
t: r@ r> r> dup >r swap >r t; compile-only
t: @ ( a -- w ) @ t;
t: ! ( w a -- ) ! t;
t: <> <> t;
t: 0< 0< t;
t: 0= 0= t;
t: 0<> 0<> t;
t: > > t;
t: 0> 0> t;
t: >= >= t;
t: tuck swap over t;
t: -rot swap >r swap r> t;
t: 2/ 1 literal rshift t;
t: 2* 2* t;
t: 1+ 1+ t;
t: sp@ dsp ff literal and t;
t: execute ( ca -- ) >r t;
t: bye ( -- ) f002 literal ! t;
t: c@ ( b -- c )
dup @ swap 1 literal and if
8 literal rshift else ff literal and then exit t;
t: c! ( c b -- )
swap ff literal and dup 8 literal lshift or swap
tuck dup @ swap 1 literal and 0 literal = ff literal xor
>r over xor r> and xor swap ! t;
t: um+ ( w w -- w cy )
over over + >r
r@ 0 literal >= >r
over over and
0< r> or >r
or 0< r> and invert 1+
r> swap t;
t: dovar ( -- a ) r> t; compile-only
t: up dovar =up t, t;
t: douser ( -- a ) up @ r> @ + t; compile-only
u: base
u: temp
u: >in
u: #tib
u: tib
u: 'eval
u: 'abort
u: hld
u: context
=vocs =cell * tuser +!
u: forth-wordlist
=cell tuser +!
=cell tuser +!
u: current
=cell tuser +!
u: dp
u: last
u: '?key
u: 'emit
u: 'boot
u: '\
u: 'name?
u: '$,n
u: 'overt
u: ';
u: 'create
t: ?dup ( w -- w w | 0 ) dup if dup then exit t;
t: rot ( w1 w2 w3 -- w2 w3 w1 ) >r swap r> swap t;
t: 2drop ( w w -- ) drop drop t;
t: 2dup ( w1 w2 -- w1 w2 w1 w2 ) over over t;
t: negate ( n -- -n ) negate t;
t: dnegate ( d -- -d )
invert >r invert 1 literal um+ r> + t;
t: - ( n1 n2 -- n1-n2 ) negate + t;
t: abs ( n -- n ) abs t;
t: max ( n n -- n ) max t;
t: min ( n n -- n ) min t;
t: within ( u ul uh -- t ) over - >r - r> u< t;
t: um/mod ( udl udh u -- ur uq )
2dup u< if
negate f literal
for >r dup um+ >r >r dup um+ r> + dup
r> r@ swap >r um+ r> or if
>r drop 1+ r>
else
drop
then r>
next drop swap exit
then drop 2drop -1 literal dup t;
t: m/mod ( d n -- r q )
dup 0< dup >r if
negate >r dnegate r>
then >r dup 0< if
r@ +
then r> um/mod r> if
swap negate swap then exit t;
t: /mod ( n n -- r q ) over 0< swap m/mod t;
t: mod ( n n -- r ) /mod drop t;
t: / ( n n -- q ) /mod nip t;
t: um* ( u u -- ud )
0 literal swap f literal
for dup um+ >r >r dup um+ r> + r> if
>r over um+ r> + then
next rot drop t;
t: * ( n n -- n ) um* drop t;
t: m* ( n n -- d )
2dup xor 0< >r abs swap abs um* r> if
dnegate then exit t;
t: */mod ( n1 n2 n3 -- r q ) >r m* r> m/mod t;
t: */ ( n1 n2 n3 -- q ) */mod nip t;
t: cell+ ( a -- a ) =cell literal + t;
t: cell- ( a -- a ) =cell literal - t;
t: cells ( n -- n ) 1 literal lshift t;
t: bl ( -- 32 ) 20 literal t;
t: >char ( c -- c )
7f literal and dup 7f literal bl within if
drop 5f literal then exit t;
t: +! ( n a -- ) tuck @ + swap ! t;
t: 2! ( d a -- ) swap over ! cell+ ! t;
t: 2@ ( a -- d ) dup cell+ @ swap @ t;
t: count ( b -- b +n ) dup 1+ swap c@ t;
t: here ( -- a ) dp @ t;
t: aligned ( b -- a )
dup 0 literal =cell literal um/mod drop dup if
=cell literal swap - then + t;
t: align ( -- ) here aligned dp ! t;
t: pad ( -- a ) here 50 literal + aligned t;
t: @execute ( a -- ) @ ?dup if execute then exit t;
t: fill ( b u c -- )
swap for swap aft 2dup c! 1+ then next 2drop t;
t: erase 0 literal fill t;
t: digit ( u -- c ) 9 literal over < 7 literal and + 30 literal + t;
t: extract ( n base -- n c ) 0 literal swap um/mod swap digit t;
t: <# ( -- ) pad hld ! t;
t: hold ( c -- ) hld @ 1- dup hld ! c! t;
t: # ( u -- u ) base @ extract hold t;
t: #s ( u -- 0 ) begin # dup while repeat t;
t: sign ( n -- ) 0< if 2d literal hold then exit t;
t: #> ( w -- b u ) drop hld @ pad over - t;
t: str ( n -- b u ) dup >r abs <# #s r> sign #> t;
t: hex ( -- ) 10 literal base ! t;
t: decimal ( -- ) a literal base ! t;
t: digit? ( c base -- u t )
>r 30 literal - 9 literal over < if
dup 20 literal > if
20 literal -
then
7 literal - dup a literal < or
then dup r> u< t;
t: number? ( a -- n t | a f )
base @ >r 0 literal over count
over c@ 24 literal = if
hex swap 1+ swap 1- then
over c@ 2d literal = >r
swap r@ - swap r@ + ?dup if
1-
for dup >r c@ base @ digit?
while swap base @ * + r> 1+
next r@ nip if
negate then swap
else r> r> 2drop 2drop 0 literal
then dup
then r> 2drop r> base ! t;
t: ?rx ( -- c t | f ) f001 literal @ 1 literal and 0<> t;
t: tx! ( c -- )
begin
f001 literal @ 2 literal and 0=
until f000 literal ! t;
t: ?key ( -- c ) '?key @execute t;
t: emit ( c -- ) 'emit @execute t;
t: key ( -- c )
begin
?key
until f000 literal @ t;
t: nuf? ( -- t ) ?key dup if drop key =cr literal = then exit t;
t: space ( -- ) bl emit t;
t: spaces ( +n -- ) 0 literal max for aft space then next t;
t: type ( b u -- ) for aft count emit then next drop t;
t: cr ( -- ) =cr literal emit =lf literal emit t;
t: do$ ( -- a ) r> r@ r> count + aligned >r swap >r t; compile-only
t: $"| ( -- a ) do$ noop t; compile-only
t: .$ ( a -- ) count type t;
t: ."| ( -- ) do$ .$ t; compile-only
t: .r ( n +n -- ) >r str r> over - spaces type t;
t: u.r ( u +n -- ) >r <# #s #> r> over - spaces type t;
t: u. ( u -- ) <# #s #> space type t;
t: . ( w -- ) base @ a literal xor if u. exit then str space type t;
t: cmove ( b1 b2 u -- ) for aft >r dup c@ r@ c! 1+ r> 1+ then next 2drop t;
t: pack$ ( b u a -- a ) dup >r 2dup ! 1+ swap cmove r> t;
t: ? ( a -- ) @ . t;
t: (parse) ( b u c -- b u delta ; <string> )
temp ! over >r dup if
1- temp @ bl = if
for
count temp @ swap - 0< invert r@ 0> and
while next r> drop 0 literal dup exit
then 1- r>
then over swap
for
count temp @ swap - temp @ bl = if
0< then
while next dup >r else r> drop dup >r 1-
then over - r> r> - exit
then over r> - t;
t: parse ( c -- b u ; <string> )
>r
tib @ >in @ +
#tib @ >in @ - r>
(parse)
>in +! t;
t: .( ( -- ) 29 literal parse type t; immediate
t: ( ( -- ) 29 literal parse 2drop t; immediate
t: <\> ( -- ) #tib @ >in ! t; immediate
t: \ ( -- ) '\ @execute t; immediate
t: word ( c -- a ; <string> ) parse here cell+ pack$ t;
t: token ( -- a ; <string> ) bl word t;
t: name> ( na -- ca ) count 1f literal and + aligned t;
t: same? ( a a u -- a a f \ -0+ )
1-
for aft over r@ + c@
over r@ + c@ - ?dup
if r> drop exit then then
next 0 literal t;
t: find ( a va -- ca na | a f )
swap
dup c@ temp !
dup @ >r
cell+ swap
begin @ dup
if dup @ =mask literal and r@ xor
if cell+ -1 literal else cell+ temp @ same? then
else r> drop swap cell- swap exit
then
while 2 literal cells -
repeat r> drop nip cell- dup name> swap t;
t: <name?> ( a -- ca na | a f )
context dup 2@ xor if cell- then >r
begin
r> cell+ dup >r @ ?dup
while
find ?dup
until r> drop exit then r> drop 0 literal t;
t: name? ( a -- ca na | a f ) 'name? @execute t;
t: ^h ( bot eot cur -- bot eot cur )
>r over r@ < dup if
=bksp literal dup emit space
emit then r> + t;
t: tap ( bot eot cur c -- bot eot cur )
dup emit over c! 1+ t;
t: ktap ( bot eot cur c -- bot eot cur )
dup =cr literal xor if
=bksp literal xor if
bl tap exit
then ^h exit
then drop nip dup t;
t: accept ( b u -- b u )
over + over
begin
2dup xor
while
key dup bl - 7f literal u< if tap else ktap then
repeat drop over - t;
t: query ( -- ) tib @ 50 literal accept #tib ! drop 0 literal >in ! t;
t: abort2 do$ drop t;
t: abort1 space .$ 3f literal emit cr 'abort @execute abort2 t;
t: <?abort"> if do$ abort1 exit then abort2 t; compile-only
t: forget ( -- )
token name? ?dup if
cell- dup dp !
@ dup context ! last !
drop exit
then abort1 t;
t: $interpret ( a -- )
name? ?dup if
@ =comp literal and
<?abort"> $literal compile-only" execute exit
else number? if
exit then abort1 then t;
t: [ ( -- ) [t] $interpret literal 'eval ! t; immediate
t: .ok ( -- )
[t] $interpret literal 'eval @ = if
."| $literal ok"
then cr t;
t: eval ( -- )
begin
token dup c@
while
'eval @execute
repeat drop .ok t;
t: $eval ( a u -- )
>in @ >r #tib @ >r tib @ >r
[t] >in literal 0 literal swap !
#tib ! tib ! eval r> tib ! r> #tib ! r> >in ! t; compile-only
t: preset ( -- ) =tib literal #tib cell+ ! t;
t: quit ( -- )
[ begin
query eval
again t;
t: abort drop preset .ok quit t;
t: ' ( -- ca ) token name? if exit then abort1 t;
t: allot ( n -- ) aligned dp +! t;
t: , ( w -- ) here dup cell+ dp ! ! t;
t: call, ( ca -- ) 1 literal rshift 4000 literal or , t; compile-only
t: ?branch ( ca -- ) 1 literal rshift 2000 literal or , t; compile-only
t: branch ( ca -- ) 1 literal rshift 0000 literal or , t; compile-only
t: [compile] ( -- ; <string> ) ' call, t; immediate
t: compile ( -- ) r> dup @ , cell+ >r t; compile-only
t: recurse last @ name> call, t; immediate
t: pick dup 2* 2* =pickbody literal + >r t;
t: literal ( w -- )
dup 8000 literal and if
ffff literal xor [t] literal ]asm call asm[ compile invert
else
8000 literal or ,
then exit t; immediate
t: ['] ' [t] literal ]asm call asm[ t; immediate
t: $," ( -- ) 22 literal parse here pack$ count + aligned dp ! t;
t: for ( -- a ) compile [t] >r ]asm call asm[ here t; compile-only immediate
t: begin ( -- a ) here t; compile-only immediate
t: (next) ( n -- ) r> r> ?dup if 1- >r @ >r exit then cell+ >r t; compile-only
t: next ( -- ) compile (next) , t; compile-only immediate
t: (do) ( limit index -- index ) r> dup >r swap rot >r >r cell+ >r t; compile-only
t: do ( limit index -- ) compile (do) 0 literal , here t; compile-only immediate
t: (leave) r> drop r> drop r> drop t; compile-only
t: leave compile (leave) noop t; compile-only immediate
t: (loop)
r> r> 1+ r> 2dup <> if
>r >r @ >r exit
then >r 1- >r cell+ >r t; compile-only
t: (unloop) r> r> drop r> drop r> drop >r t; compile-only
t: unloop compile (unloop) noop t; compile-only immediate
t: (?do)
2dup <> if
r> dup >r swap rot >r >r cell+ >r exit
then 2drop exit t; compile-only
t: ?do ( limit index -- ) compile (?do) 0 literal , here t; compile-only immediate
t: loop ( -- ) compile (loop) dup , compile (unloop) cell- here 1 literal rshift swap ! t; compile-only immediate
t: (+loop)
r> swap r> r> 2dup - >r
2 literal pick r@ + r@ xor 0< 0=
3 literal pick r> xor 0< 0= or if
>r + >r @ >r exit
then >r >r drop cell+ >r t; compile-only
t: +loop ( n -- ) compile (+loop) dup , compile (unloop) cell- here 1 literal rshift swap ! t; compile-only immediate
t: (i) ( -- index ) r> r> tuck >r >r t; compile-only
t: i ( -- index ) compile (i) noop t; compile-only immediate
t: until ( a -- ) ?branch t; compile-only immediate
t: again ( a -- ) branch t; compile-only immediate
t: if ( -- a ) here 0 literal ?branch t; compile-only immediate
t: then ( a -- ) here 1 literal rshift over @ or swap ! t; compile-only immediate
t: repeat ( a a -- ) branch [t] then ]asm call asm[ t; compile-only immediate
t: skip here 0 literal branch t; compile-only immediate
t: aft ( a -- a a ) drop [t] skip ]asm call asm[ [t] begin ]asm call asm[ swap t; compile-only immediate
t: else ( a -- a ) [t] skip ]asm call asm[ swap [t] then ]asm call asm[ t; compile-only immediate
t: while ( a -- a a ) [t] if ]asm call asm[ swap t; compile-only immediate
t: (case) r> swap >r >r t; compile-only
t: case compile (case) 30 literal t; compile-only immediate
t: (of) r> r@ swap >r = t; compile-only
t: of compile (of) [t] if ]asm call asm[ t; compile-only immediate
t: endof [t] else ]asm call asm[ 31 literal t; compile-only immediate
t: (endcase) r> r> drop >r t;
t: endcase
begin
dup 31 literal =
while
drop
[t] then ]asm call asm[
repeat
30 literal <> <?abort"> $literal bad case construct."
compile (endcase) noop t; compile-only immediate
t: $" ( -- ; <string> ) compile $"| $," t; compile-only immediate
t: ." ( -- ; <string> ) compile ."| $," t; compile-only immediate
t: >body ( ca -- pa ) cell+ t;
t: (to) ( n -- ) r> dup cell+ >r @ ! t; compile-only
t: to ( n -- ) compile (to) ' >body , t; compile-only immediate
t: (+to) ( n -- ) r> dup cell+ >r @ +! t; compile-only
t: +to ( n -- ) compile (+to) ' >body , t; compile-only immediate
t: get-current ( -- wid ) current @ t;
t: set-current ( wid -- ) current ! t;
t: definitions ( -- ) context @ set-current t;
t: ?unique ( a -- a )
dup get-current find if ."| $literal redef " over .$ then drop t;
t: <$,n> ( na -- )
dup c@ if
?unique
dup count + aligned
dp !
dup last !
cell-
get-current @
swap ! exit
then drop $"| $literal name" abort1 t;
t: $,n ( na -- ) '$,n @execute t;
t: $compile ( a -- )
name? ?dup if
@ =imed literal and if
execute exit
else call, exit
then
then
number? if
[t] literal ]asm call asm[ exit then abort1 t;
t: abort" compile <?abort"> $," t; immediate
t: <overt> ( -- ) last @ get-current ! t;
t: overt ( -- ) 'overt @execute t;
t: exit r> drop t;
t: <;> ( -- )
compile [t] exit ]asm call asm[
[ overt 0 literal here ! t; compile-only immediate
t: ; ( -- ) '; @execute t; compile-only immediate
t: ] ( -- ) [t] $compile literal 'eval ! t;
t: : ( -- ; <string> ) token $,n ] t;
t: immediate ( -- ) =imed literal last @ @ or last @ ! t;
t: user ( u -- ; <string> ) token $,n overt compile douser , t;
t: <create> ( -- ; <string> ) token $,n overt [t] dovar ]asm literal asm[ call, t;
t: create ( -- ; <string> ) 'create @execute t;
t: variable ( -- ; <string> ) create 0 literal , t;
t: (does>) ( -- )
r> 1 literal rshift here 1 literal rshift
last @ name> dup cell+ ]asm 8000 literal asm[ or , ! , t; compile-only
t: compile-only ( -- ) =comp literal last @ @ or last @ ! t;
t: does> ( -- ) compile (does>) noop t; immediate
t: char ( <char> -- char ) ( -- c ) bl word 1+ c@ t;
t: [char] char [t] literal ]asm call asm[ t; immediate
t: constant create , (does>) @ t;
t: defer create 0 literal ,
(does>)
@ ?dup 0 literal =
<?abort"> $literal uninitialized" execute t;
t: is ' >body ! t; immediate
t: .id ( na -- )
?dup if
count 1f literal and type exit then
cr ."| $literal {noname}" t;
t: wordlist ( -- wid ) align here 0 literal , dup current cell+ dup @ , ! 0 literal , t;
t: order@ ( a -- u*wid u ) dup @ dup if >r cell+ order@ r> swap 1+ exit then nip t;
t: get-order ( -- u*wid u ) context order@ t;
t: >wid ( wid -- ) cell+ t;
t: .wid ( wid -- )
space dup >wid cell+ @ ?dup if .id drop exit then 0 literal u.r t;
t: !wid ( wid -- ) >wid cell+ last @ swap ! t;
t: vocs ( -- ) ( list all wordlists )
cr ."| $literal vocs:" current cell+
begin
@ ?dup
while
dup .wid >wid
repeat t;
t: order ( -- ) ( list search order )
cr ."| $literal search:" get-order
begin
?dup
while
swap .wid 1-
repeat
cr ."| $literal define:" get-current .wid t;
t: set-order ( u*wid n -- ) ( 16.6.1.2197 )
dup -1 literal = if
drop forth-wordlist 1 literal then
=vocs literal over u< <?abort"> $literal over size of #vocs"
context swap
begin
dup
while
>r swap over ! cell+ r>
1-
repeat swap ! t;
t: only ( -- ) -1 literal set-order t;
t: also ( -- ) get-order over swap 1+ set-order t;
t: previous ( -- ) get-order swap drop 1- set-order t;
t: >voc ( wid 'name' -- )
create dup , !wid
(does>)
@ >r get-order swap drop r> swap set-order t;
t: widof ( "vocabulary" -- wid ) ' >body @ t;
t: vocabulary ( 'name' -- ) wordlist >voc t;
t: _type ( b u -- ) for aft count >char emit then next drop t;
t: dm+ ( a u -- a )
over 4 literal u.r space
for aft count 3 literal u.r then next t;
t: dump ( a u -- )
base @ >r hex 10 literal /
for cr 10 literal 2dup dm+ -rot
2 literal spaces _type
next drop r> base ! t;
t: .s ( ... -- ... ) cr sp@ 1- f literal and for r@ pick . next ."| $literal <tos" t;
t: (>name) ( ca va -- na | f )
begin
@ ?dup
while
2dup name> xor
while cell-
repeat nip exit
then drop 0 literal t;
t: >name ( ca -- na | f )
>r get-order
begin
?dup
while
swap
r@ swap
(>name)
?dup if
>r
1- for aft drop then next
r> r> drop
exit
then
1-
repeat
r> drop 0 literal t;
t: see ( -- ; <string> )
' cr
begin
dup @ ?dup 700c literal xor
while
3fff literal and 1 literal lshift
>name ?dup if
space .id
else
dup @ 7fff literal and u.
then
cell+
repeat 2drop t;
t: (words) ( -- )
cr
begin
@ ?dup
while
dup .id space cell-
repeat t;
t: words
get-order
begin
?dup
while
swap
cr cr ."| $literal :" dup .wid cr
(words)
1-
repeat t;
t: ver ( -- n ) =ver literal 100 literal * =ext literal + t;
t: hi ( -- )
cr ."| $literal eforth j1+ v"
base @ hex
ver <# # # 2e literal hold # #>
type base ! cr t;
t: cold ( -- )
=uzero literal =up literal =udiff literal cmove
preset forth-wordlist dup context ! dup current 2! overt
4000 literal cell+ dup cell- @ $eval
'boot @execute
quit
cold t;
target.1 -order set-current
there [u] dp t!
[last] [u] last t!
[t] ?rx [u] '?key t!
[t] tx! [u] 'emit t!
[t] <\> [u] '\ t!
[t] $interpret [u] 'eval t!
[t] abort [u] 'abort t!
[t] hi [u] 'boot t!
[t] <name?> [u] 'name? t!
[t] <overt> [u] 'overt t!
[t] <$,n> [u] '$,n t!
[t] <;> [u] '; t!
[t] <create> [u] 'create t!
[t] cold 2/ =cold t!
save-target j1.bin
save-hex j1.hex
meta.1 -order
bye

View File

@ -0,0 +1,186 @@
#include <pcap.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <sys/stat.h>
#if defined(unix) || defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
#include <unistd.h>
#include <termios.h>
int getch(void) { /* reads from keypress, doesn't echo */
struct termios oldattr, newattr;
int ch;
tcgetattr( STDIN_FILENO, &oldattr );
newattr = oldattr;
newattr.c_iflag &= ~( ICRNL );
newattr.c_lflag &= ~( ICANON | ECHO );
tcsetattr( STDIN_FILENO, TCSANOW, &newattr );
ch = getchar();
tcsetattr( STDIN_FILENO, TCSANOW, &oldattr );
// printf("%d\n", ch);
if(ch==0x1b) exit(0);
return ch==127 ? 8 : ch;
}
int putch(int c) { /* output character to sstdout & flush */
int res=putchar(c);
fflush(stdout);
return res;
}
#endif
int len = 0;
static pcap_t* handle = NULL;
static void pcapdev_init(void) {
char errbuf[PCAP_ERRBUF_SIZE];
pcap_if_t* devices;
if (pcap_findalldevs(&devices, errbuf) == -1) {
fprintf(stderr, "error pcap_findalldevs: %s\n", errbuf);
return;
}
pcap_if_t* device;
for(device = devices; device; device = device->next) {
if (device->description) {
printf(" (%s)\n", device->description);
}
else {
fprintf(stderr, "no device\n");
return;
}
}
device = devices->next->next;
if (NULL == (handle= pcap_open_live(device->name
, 65536, 1, 10 , errbuf))) {
fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n");
pcap_freealldevs(devices);
return;
}
pcap_freealldevs(devices);
}
static unsigned short t;
static unsigned short s;
static unsigned short d[0x20]; /* data stack */
static unsigned short r[0x20]; /* return stack */
static unsigned short pc; /* program counter, counts cells */
static unsigned char dsp, rsp; /* point to top entry */
static unsigned short* memory; /* ram */
static int sx[4] = { 0, 1, -2, -1 }; /* 2-bit sign extension */
static void push(int v) // push v on the data stack
{
dsp = 0x1f & (dsp + 1);
d[dsp] = t;
t = v;
}
static int pop(void) // pop value from the data stack and return it
{
int v = t;
t = d[dsp];
dsp = 0x1f & (dsp - 1);
return v;
}
char eth_poll() {
const u_char* packet;
struct pcap_pkthdr* header;
int res = 0;
while (res == 0)
{
res = pcap_next_ex(handle, &header, &packet);
}
len = (int)header->len;
memcpy(&memory[0x2000], packet, len);
return len;
}
void eth_transmit(void) {
if ((pcap_sendpacket(handle, (char *)(&memory[0x2000]), len) == -1))
{
printf("sorry send error\n");
exit(1);
}
}
static void execute(int entrypoint)
{
int _pc, _t;
int insn = 0x4000 | entrypoint; // first insn: "call entrypoint"
pcapdev_init();
do {
_pc = pc + 1;
if (insn & 0x8000) { // literal
push(insn & 0x7fff);
} else {
int target = insn & 0x1fff;
switch (insn >> 13) {
case 0: // jump
_pc = target;
break;
case 1: // conditional jump
if (pop() == 0)
_pc = target;
break;
case 2: // call
rsp = 31 & (rsp + 1);
r[rsp] = _pc << 1;
_pc = target;
break;
case 3: // alu
if (insn & 0x1000) {/* r->pc */
_pc = r[rsp] >> 1;
}
s = d[dsp];
switch ((insn >> 8) & 0xf) {
case 0: _t = t; break; /* noop */
case 1: _t = s; break; /* copy */
case 2: _t = t+s; break; /* + */
case 3: _t = t&s; break; /* and */
case 4: _t = t|s; break; /* or */
case 5: _t = t^s; break; /* xor */
case 6: _t = ~t; break; /* invert */
case 7: _t = -(t==s); break; /* = */
case 8: _t = -((signed short)s < (signed short)t); break; /* < */
case 9: _t = s>>t; break; /* rshift */
case 0xa: _t = t-1; break; /* 1- */
case 0xb: _t = r[rsp]; break; /* r@ */
case 0xc: _t = (t==0xf008)?eth_poll():(t==0xf001)?1:(t==0xf000)?getch():memory[t>>1]; break; /* @ */
case 0xd: _t = s<<t; break; /* lshift */
case 0xe: _t = (rsp<<8) + dsp; break; /* dsp */
case 0xf: _t = -(s<t); break; /* u< */
}
dsp = 31 & (dsp + sx[insn & 3]); /* dstack+- */
rsp = 31 & (rsp + sx[(insn >> 2) & 3]); /* rstack+- */
if (insn & 0x80) /* t->s */
d[dsp] = t;
if (insn & 0x40) /* t->r */
r[rsp] = t;
if (insn & 0x20) /* s->[t] */
(t==0xf008)?eth_transmit(): (t==0xf002)?(rsp=0):(t==0xf000)?putch(s):(memory[t>>1]=s); /* ! */
t = _t;
break;
}
}
pc = _pc;
insn = memory[pc];
} while (1);
}
/* end of cpu */
/* start of i/o demo */
int main(int argc , char *argv[])
{
unsigned short m[0x4000]; /* 32kb or RAM */
FILE *f = fopen("j1.bin", "rb");
fread(m, 0x2000, sizeof(m[0]), f); /* 0kb - 16kb data and code */
fclose(f);
if (argc>1) { // program name is counted as one
struct stat st;
f = fopen(argv[1], "r");
stat(argv[1], &st);
(&m[0x2000])[0] = st.st_size; /* 16kb - 32kb memory mapped i/o */
fread(&m[0x2001], 0x2000, sizeof(m[0]), f);
fclose(f);
}
memory = m;
execute(0x00);
return 0;
}

File diff suppressed because it is too large Load Diff

588
verilog/j1eforth/j1eforth.v Normal file
View File

@ -0,0 +1,588 @@
`define FOMU 1
`default_nettype none
// Correctly map pins for the iCE40UP5K SB_RGBA_DRV hard macro.
// The variables EVT, PVT and HACKER are set from the yosys commandline e.g. yosys -D HACKER=1
`ifdef EVT
`define BLUEPWM RGB0PWM
`define REDPWM RGB1PWM
`define GREENPWM RGB2PWM
`elsif HACKER
`define BLUEPWM RGB0PWM
`define GREENPWM RGB2PWM
`define REDPWM RGB1PWM
`elsif PVT
`define GREENPWM RGB0PWM
`define REDPWM RGB1PWM
`define BLUEPWM RGB2PWM
`else
`error_board_not_supported
`endif
module top(
// 48MHz Clock Input
input clki,
// LED outputs
output rgb0, // blue
output rgb1, // green
output rgb2, // red
// USB Pins
output usb_dp,
output usb_dn,
output usb_dp_pu,
// SPI
output spi_mosi,
input spi_miso,
output spi_clk,
output spi_cs,
// USER pads
input user_1,
input user_2,
input user_3,
input user_4
);
// Connect to system clk_48mhz (with buffering)
wire clk, clk_48mhz;
SB_GB clk_gb (
.USER_SIGNAL_TO_GLOBAL_BUFFER(clki),
.GLOBAL_BUFFER_OUTPUT(clk)
);
assign clk_48mhz = clk;
// RGB LED Driver
reg [2:0] setRGB;
SB_RGBA_DRV #(
.CURRENT_MODE("0b1"), // half current
.RGB0_CURRENT("0b000011"), // 4 mA
.RGB1_CURRENT("0b000011"), // 4 mA
.RGB2_CURRENT("0b000011") // 4 mA
) RGBA_DRIVER (
.CURREN(1'b1),
.RGBLEDEN(1'b1),
.`BLUEPWM(setRGB[0]), // Blue
.`REDPWM(setRGB[1]), // Red
.`GREENPWM(setRGB[2]), // Green
.RGB0(rgb0),
.RGB1(rgb1),
.RGB2(rgb2)
);
// user buttons
wire [3:0] buttons;
assign buttons = { user_4, user_3, user_2, user_1 };
// SPRAM driver
// https://github.com/damdoy/ice40_ultraplus_examples/blob/master/spram/top.v
// 4 x 16384 x 16bit
reg [15:0] sram_address; // 16bit 0-65535 address
reg [15:0] sram_data_read; // data read from SPRAM after bank switching
reg [15:0] sram_data_write; // data to write to SPRAM
assign sram_data_in = sram_data_write;
wire [15:0] sram_data_in; // to SB_SPRAM256KA
wire [15:0] sram_data_out00; // from SB_SPRAM256KA bank 00
wire [15:0] sram_data_out01; // from SB_SPRAM256KA bank 01
wire [15:0] sram_data_out10; // from SB_SPRAM256KA bank 10
wire [15:0] sram_data_out11; // from SB_SPRAM256KA bank 11
wire sram_wren;
reg sram_readwrite;
assign sram_wren = sram_readwrite;
always @(posedge clk_48mhz) begin
// SPRAM automatic bank switching for reading data from SB_SPRAM256KA banks
case( sram_address[15:14])
2'b00: sram_data_read = sram_data_out00;
2'b01: sram_data_read = sram_data_out01;
2'b10: sram_data_read = sram_data_out10;
2'b11: sram_data_read = sram_data_out11;
endcase
end
SB_SPRAM256KA spram00 (
.ADDRESS(sram_address),
.DATAIN(sram_data_in),
.MASKWREN(4'b1111),
.WREN(sram_wren),
.CHIPSELECT(sram_address[15:14]==2'b00),
.CLOCK(clk_48mhz),
.STANDBY(1'b0),
.SLEEP(1'b0),
.POWEROFF(1'b1),
.DATAOUT(sram_data_out00)
);
SB_SPRAM256KA spram01 (
.ADDRESS(sram_address),
.DATAIN(sram_data_in),
.MASKWREN(4'b1111),
.WREN(sram_wren),
.CHIPSELECT(sram_address[15:14]==2'b01),
.CLOCK(clk_48mhz),
.STANDBY(1'b0),
.SLEEP(1'b0),
.POWEROFF(1'b1),
.DATAOUT(sram_data_out01)
);
SB_SPRAM256KA spram10 (
.ADDRESS(sram_address),
.DATAIN(sram_data_in),
.MASKWREN(4'b1111),
.WREN(sram_wren),
.CHIPSELECT(sram_address[15:14]==2'b10),
.CLOCK(clk_48mhz),
.STANDBY(1'b0),
.SLEEP(1'b0),
.POWEROFF(1'b1),
.DATAOUT(sram_data_out10)
);
SB_SPRAM256KA spram11 (
.ADDRESS(sram_address),
.DATAIN(sram_data_in),
.MASKWREN(4'b1111),
.WREN(sram_wren),
.CHIPSELECT(sram_address[15:14]==2'b11),
.CLOCK(clk_48mhz),
.STANDBY(1'b0),
.SLEEP(1'b0),
.POWEROFF(1'b1),
.DATAOUT(sram_data_out11)
);
// Generate RESET
reg [31:0] RST_d;
reg [31:0] RST_q;
reg ready = 0;
always @* begin
RST_d = RST_q >> 1;
end
always @(posedge clk_48mhz) begin
if (ready) begin
RST_q <= RST_d;
end else begin
ready <= 1;
RST_q <= 32'b111111111111111111111111111111;
end
end
wire reset_main;
assign reset_main = RST_q[0];
wire run_main;
assign run_main = 1'b1;
// USB_ACM UART CODE
// Generate reset signal
reg [5:0] reset_cnt = 0;
wire reset = ~reset_cnt[5];
always @(posedge clk_48mhz)
reset_cnt <= reset_cnt + reset;
// uart pipeline in
reg [7:0] uart_in_data;
reg uart_in_valid;
wire uart_in_ready;
wire [7:0] uart_out_data;
wire uart_out_valid;
wire uart_out_ready;
// usb uart - this instanciates the entire USB device.
usb_uart uart (
.clk_48mhz (clk_48mhz),
.reset (reset),
// pins
.pin_usb_p( usb_dp ),
.pin_usb_n( usb_dn ),
// uart pipeline in
.uart_in_data( uart_in_data ),
.uart_in_valid( uart_in_valid ),
.uart_in_ready( uart_in_ready ),
.uart_out_data( uart_out_data ),
.uart_out_valid( uart_out_valid ),
.uart_out_ready( uart_out_ready )
);
// USB Host Detect Pull Up
assign usb_dp_pu = 1'b1;
// j1eforth ROM
reg [15:0] rom[0:3336]; initial $readmemh("j1eforth-plus/j1.hex", rom);
// CYCLE to control each stage
// CYCLE allows 1 clk_48mhz cycle for BRAM access and 3 clk_48mhz cycles for SPRAM access
// INIT to determine if copying rom to ram or executing
// INIT 0 SPRAM, INIT 1 ROM to SPRAM, INIT 2 J1 CPU
reg [3:0] CYCLE = 0;
reg [1:0] INIT = 0;
// Address for 0 to SPRAM, copying ROM, plus storage
reg [15:0] copyaddress = 0;
reg [15:0] bramREAD;
reg bramENABLE = 0;
// instruction being executed with decoding information
// +---------------------------------------------------------------+
// | F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
// +---------------------------------------------------------------+
// | 1 | LITERAL VALUE |
// +---------------------------------------------------------------+
// | 0 | 0 | 0 | BRANCH TARGET ADDRESS |
// +---------------------------------------------------------------+
// | 0 | 0 | 1 | CONDITIONAL BRANCH TARGET ADDRESS |
// +---------------------------------------------------------------+
// | 0 | 1 | 0 | CALL TARGET ADDRESS |
// +---------------------------------------------------------------+
// | 0 | 1 | 1 |R2P| ALU OPERATION |T2N|T2R|N2A|J1+| RSTACK| DSTACK|
// +---------------------------------------------------------------+
// | F | E | D | C | B | A | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
// +---------------------------------------------------------------+
reg [15:0] instruction;
wire [15:0] immediate = { 1'b0, instruction[14:0] };
wire is_lit = instruction[15];
wire is_alu = ( instruction[15:13] == 3'b011 );
wire is_call = ( instruction[15:13] == 3'b010 );
wire dstackWrite = (is_lit | ( is_alu & instruction[7] ) );
wire rstackWrite = (is_call | ( is_alu & instruction[6] ) );
wire [4:0] ddelta = { instruction[1], instruction[1], instruction[1], instruction[1:0] };
wire [4:0] rdelta = { instruction[3], instruction[3], instruction[3], instruction[3:2] };
// data and return stacks with pointers
reg [15:0] dstack[0:31];
reg [15:0] rstack[0:31];
reg [15:0] stackTop = 0;
reg [15:0] newStackTop;
reg [4:0] dsp = 0;
reg [4:0] newDSP;
reg [15:0] stackNext;
reg [15:0] rstackTop;
reg [4:0] rsp = 0;
reg [4:0] newRSP;
reg [15:0] rStackTop;
reg [15:0] rstackWData;
// program counter
reg [12:0] pc = 0;
reg [12:0] newPC;
wire [12:0] pcPlusOne;
assign pcPlusOne = pc + 1;
// value read from SPRAM
reg [15:0] memoryInput;
// UART input and output buffers
reg [7:0] uartInBuffer [0:31];
reg [4:0] uartInBufferNext = 0;
reg [4:0] uartInBufferTop = 0;
reg [7:0] uartOutBuffer [0:31];
reg [4:0] uartOutBufferNext = 0;
reg [4:0] uartOutBufferTop = 0;
reg [4:0] newUartOutBufferTop = 0;
// READ from BRAM ROM
always @(posedge clk_48mhz) begin
if( bramENABLE )
bramREAD <= rom[copyaddress];
end
// UART
always @(posedge clk_48mhz) begin
end
// MAIN LOOP
always @(posedge clk_48mhz) begin
if( reset == 1 ) begin
pc <= 0;
dsp <= 0;
stackTop <= 0;
rsp <= 0;
CYCLE <= 0;
INIT <= 0;
copyaddress <= 0;
uartInBufferNext <= 0;
uartInBufferTop <= 0;
uartOutBufferNext <= 0;
uartOutBufferTop <= 0;
newUartOutBufferTop <= 0;
end else begin
case( INIT )
0: begin // 0 to SPRAM
case( CYCLE )
0: begin
// SETUP WRITE of 0 to SPRAM[copyaddress]
sram_address <= copyaddress;
sram_data_write <= 0;
sram_readwrite <= 1;
end
11: begin
sram_readwrite <= 0;
copyaddress = copyaddress + 1;
end
12: begin
if( copyaddress == 16384 ) begin
INIT <= 1;
copyaddress <= 0;
end
end
default: begin
end
endcase
end // 0 to SPRAM
1: begin // COPY ROM to SPRAM
bramENABLE = 1;
case( CYCLE )
2: begin
// SETUP WRITE of 0 to SPRAM[copyaddress]
sram_address <= copyaddress;
sram_data_write <= bramREAD;
sram_readwrite <= 1;
end
11: begin
sram_readwrite <= 0;
copyaddress = copyaddress + 1;
end
12: begin
if( copyaddress == 4096 ) begin
INIT <= 2;
copyaddress <= 0;
bramENABLE = 0;
end
end
default: begin
end
endcase
end // COPY ROM to SPRAM
2: begin // SPARE INIT
bramENABLE = 1;
case( CYCLE )
12: begin
INIT <= 3;
end
default: begin
end
endcase
end // SPARE INIT
3: begin // MAIN J1 CPU LOOP
// READ from UART if character available and store
if( uart_out_valid ) begin
uartInBuffer[uartInBufferTop] <= uart_out_data;
uart_out_ready <= 1;
uartInBufferTop <= uartInBufferTop + 1;
end
// WRITE to UART if characters in buffer and UART is ready
if( ~(uartOutBufferNext == uartOutBufferTop) & ~( uart_in_valid ) ) begin
uart_in_data <= uartOutBuffer[uartOutBufferNext];
uart_in_valid <= 1;
uartOutBufferNext <= uartOutBufferNext + 1;
end
uartOutBufferTop = newUartOutBufferTop;
case( CYCLE )
0: begin
// Read stackNext and rStackTop
stackNext <= dstack[dsp];
rStackTop <= rstack[rsp];
// start READ memoryInput = [stackTop] result ready in 2 cycles
sram_address <= stackTop >> 1;
sram_readwrite <= 0;
end
3: begin
// wait then read the data from SPRAM
memoryInput <= sram_data_read;
end
4: begin
// start READ instruction = [pc] result ready in 2 cycles
sram_address <= pc;
sram_readwrite <= 0;
end
7: begin
// wait then read the instruction from SPRAM
instruction = sram_data_read;
end
8: begin
// J1 CPU instruction execute
if( is_lit ) begin
// LITERAL Push value onto stack
newStackTop <= immediate;
newPC <= pcPlusOne;
newDSP <= dsp + 1;
newRSP <= rsp;
end else begin
case( instruction[14:13] )
2'b00: begin
// BRANCH
newStackTop <= stackTop;
newPC <= instruction[12:0];
newDSP <= dsp;
newRSP <= rsp;
end
2'b01: begin
// 0BRANCH
newStackTop <= stackNext;
newPC <= ( stackTop == 0 ) ? instruction[12:0] : pcPlusOne;
newDSP <= dsp - 1;
newRSP <= rsp;
end
2'b10: begin
// CALL
newStackTop <= stackTop;
newPC <= instruction[12:0];
newDSP <= dsp;
newRSP <= rsp + 1;
rstackWData <= pcPlusOne << 1;
end
2'b11: begin
case( instruction[4] )
// ALU
1'b0: begin
// J1 ALUOP
case( instruction[11:8] )
4'b0000: newStackTop = stackTop;
4'b0001: newStackTop = stackNext;
4'b0010: newStackTop = stackTop + stackNext;
4'b0011: newStackTop = stackTop & stackNext;
4'b0100: newStackTop = stackTop | stackNext;
4'b0101: newStackTop = stackTop ^ stackNext;
4'b0110: newStackTop = ~stackTop;
4'b0111: newStackTop = {16{(stackNext == stackTop)}};
4'b1000: newStackTop = {16{($signed(stackNext) < $signed(stackTop))}};
4'b1001: newStackTop = stackNext >> stackTop[3:0];
4'b1010: newStackTop = stackTop - 1;
4'b1011: newStackTop = rStackTop;
4'b1100: begin
case( stackTop)
16'hf000: begin
newStackTop = { 8'b0, uartInBuffer[uartInBufferNext] };
uartInBufferNext = uartInBufferNext + 1;
end
16'hf001: newStackTop = {14'b0, ( uartOutBufferTop + 1 == uartOutBufferNext ), ~(uartInBufferNext == uartInBufferTop)}; // Read UART status
16'hf002: newStackTop = setRGB; // Read to rgbLED status
16'hf003: newStackTop = {12'b0, buttons}; // Read buttons status
default: newStackTop = memoryInput; // memoryInput
endcase
end
4'b1101: newStackTop = stackNext << stackTop[3:0];
4'b1110: newStackTop = {rsp, 3'b000, dsp};
4'b1111: newStackTop = {16{($unsigned(stackNext) < $unsigned(stackTop))}};
endcase
end
1'b1: begin
// J1+ ALUOP
case( instruction[11:8] )
4'b0000: newStackTop = {16{(stackTop == 0)}};
4'b0001: newStackTop = ~{16{(stackTop == 0)}};
4'b0010: newStackTop = ~{16{(stackNext == stackTop)}};
4'b0011: newStackTop = stackTop + 1;
4'b0100: newStackTop = stackTop << 1;
4'b0101: newStackTop = stackTop >> 1;
4'b0110: newStackTop = {16{($signed(stackNext) > $signed(stackTop))}};
4'b0111: newStackTop = {16{($unsigned(stackNext) > $unsigned(stackTop))}};
4'b1000: newStackTop = {16{($signed(stackTop) < 0)}};
4'b1001: newStackTop = {16{($signed(stackTop) > 0)}};
4'b1010: newStackTop = ( $signed(stackTop) < 0 ) ? - stackTop : stackTop;
4'b1011: newStackTop = ( $signed(stackNext) > $signed(stackTop) ) ? stackNext : stackTop;
4'b1100: newStackTop = ( $signed(stackNext) < $signed(stackTop) ) ? stackNext : stackTop;
4'b1101: newStackTop = -stackTop;
4'b1110: newStackTop = stackNext - stackTop;
4'b1111: newStackTop = {16{($signed(stackNext) >= $signed(stackTop))}};
endcase
end
endcase // J1 / J1+
// UPDATE newDSP newRSP
newDSP <= dsp + ddelta;
newRSP <= rsp + rdelta;
rstackWData <= stackTop;
// r2pc - return from call or next instruction
newPC <= ( instruction[12] ) ? rStackTop >> 1 : pcPlusOne;
// n2memt mem[t] = n WRITE to SPRAM or UART/LED
if( instruction[5] ) begin
case( stackTop )
16'hf000: begin
// OUTPUT to UART via buffer
uartOutBuffer[uartOutBufferTop] <= stackNext[7:0];
newUartOutBufferTop <= uartOutBufferTop + 1;
end
16'hf002: setRGB <= stackNext; // OUTPUT to rgbLED
default: begin
// WRITE to SPRAM
sram_address <= stackTop >> 1;
sram_data_write <= stackNext;
sram_readwrite <= 1;
end
endcase
end
end // ALU
endcase // branch 0branch call alu
end // not is_lit
end // J1 CPU Instruction execute
9: begin
// Write to dstack and rstack
if( dstackWrite )
dstack[newDSP] <= stackTop;
if( rstackWrite )
rstack[newRSP] <= rstackWData;
end
10: begin
// Update dsp, rsp, pc, stackTop
dsp <= newDSP;
pc <= newPC;
stackTop <= newStackTop;
rsp <= newRSP;
end
12: begin
// reset sram_readwrite
sram_readwrite <= 0;
end
default: begin
end
endcase
end // MAIN J1 CPU LOOP
default: begin
end
endcase // INIT
// Reset UART Output
if(uart_in_ready & uart_in_valid)
uart_in_valid <= 0;
// Move to next CYCLE ( 0 to 12 , then back to 0 )
CYCLE = ( CYCLE == 12 ) ? 0 : CYCLE + 1;
end // NOT RESET
end // MAIN LOOP
endmodule

View File

@ -0,0 +1,16 @@
# Configuration for the Fomu hacker board.
set_io rgb0 A5 # Blue LED
set_io rgb1 B5 # Green LED
set_io rgb2 C5 # Red LED
set_io clki F5 # Clock input from 48MHz Oscillator
set_io spi_mosi F1 # SPI Master Out, Slave In Pin
set_io spi_miso E1 # SPI Master In, Slave Out Pin
set_io spi_clk D1 # SPI Master Clock Output Pin
set_io spi_cs C1 # SPI Chip Select
set_io user_1 F4 # User touch pad 1
set_io user_2 E5 # User touch pad 2
set_io user_3 E4 # User touch pad 3
set_io user_4 F2 # User touch pad 4
set_io usb_dn A2 # USB D- pad
set_io usb_dp A4 # USB D+ pad
set_io usb_dp_pu D5 # USB D+ pull up (indicates device connected)

View File

@ -0,0 +1,27 @@
module rising_edge_detector (
input clk,
input in,
output out
);
reg in_q;
always @(posedge clk) begin
in_q <= in;
end
assign out = !in_q && in;
endmodule
module falling_edge_detector (
input clk,
input in,
output out
);
reg in_q;
always @(posedge clk) begin
in_q <= in;
end
assign out = in_q && !in;
endmodule

View File

@ -0,0 +1,53 @@
module width_adapter #(
parameter [31:0] INPUT_WIDTH = 8,
parameter [31:0] OUTPUT_WIDTH = 1
) (
input clk,
input reset,
input data_in_put,
output data_in_free,
input [INPUT_WIDTH-1:0] data_in,
output data_out_put,
input data_out_free,
output [OUTPUT_WIDTH-1:0] data_out
);
generate
if (INPUT_WIDTH > OUTPUT_WIDTH) begin
// wide to narrow conversion
reg [INPUT_WIDTH:0] data_in_q;
reg has_data;
always @(posedge clk) begin
if (!has_data && data_in_put) begin
data_in_q <= {1'b1, data_in};
has_data <= 1;
end
if (has_data && data_out_free) begin
data_in_q <= data_in_q >> OUTPUT_WIDTH;
end
if (data_in_q == 1'b1) begin
has_data <= 0;
end
end
assign data_out = data_in_q[OUTPUT_WIDTH:1];
assign data_out_put = has_data;
end else if (INPUT_WIDTH < OUTPUT_WIDTH) begin
// narrow to wide conversion
end else begin
assign data_in_free = data_out_free;
assign data_out_put = data_in_put;
assign data_out = data_in;
end
endgenerate
endmodule

View File

@ -0,0 +1,39 @@
module usb_fs_in_arb #(
parameter NUM_IN_EPS = 1
) (
////////////////////
// endpoint interface
////////////////////
input [NUM_IN_EPS-1:0] in_ep_req,
output reg [NUM_IN_EPS-1:0] in_ep_grant,
input [(NUM_IN_EPS*8)-1:0] in_ep_data,
////////////////////
// protocol engine interface
////////////////////
output reg [7:0] arb_in_ep_data
);
integer i;
reg grant;
always @* begin
grant = 0;
arb_in_ep_data <= 0;
for (i = 0; i < NUM_IN_EPS; i = i + 1) begin
in_ep_grant[i] <= 0;
if (in_ep_req[i] && !grant) begin
in_ep_grant[i] <= 1;
arb_in_ep_data <= in_ep_data[i * 8 +: 8];
grant = 1;
end
end
// if (!grant) begin
// arb_in_ep_data <= 0;
// end
end
endmodule

View File

@ -0,0 +1,421 @@
// The IN Protocol Engine sends data to the host.
module usb_fs_in_pe #(
parameter NUM_IN_EPS = 11,
parameter MAX_IN_PACKET_SIZE = 32
) (
input clk,
input reset,
input [NUM_IN_EPS-1:0] reset_ep,
input [6:0] dev_addr,
////////////////////
// endpoint interface
////////////////////
output reg [NUM_IN_EPS-1:0] in_ep_data_free = 0,
input [NUM_IN_EPS-1:0] in_ep_data_put,
input [7:0] in_ep_data,
input [NUM_IN_EPS-1:0] in_ep_data_done,
input [NUM_IN_EPS-1:0] in_ep_stall,
output reg [NUM_IN_EPS-1:0] in_ep_acked = 0,
////////////////////
// rx path
////////////////////
// Strobed on reception of packet.
input rx_pkt_start,
input rx_pkt_end,
input rx_pkt_valid,
// Most recent packet received.
input [3:0] rx_pid,
input [6:0] rx_addr,
input [3:0] rx_endp,
input [10:0] rx_frame_num,
////////////////////
// tx path
////////////////////
// Strobe to send new packet.
output reg tx_pkt_start = 0,
input tx_pkt_end,
// Packet type to send
output reg [3:0] tx_pid = 0,
// Data payload to send if any
output tx_data_avail,
input tx_data_get,
output reg [7:0] tx_data,
output [7:0] debug
);
////////////////////////////////////////////////////////////////////////////////
// endpoint state machine
////////////////////////////////////////////////////////////////////////////////
reg [1:0] ep_state [NUM_IN_EPS - 1:0];
reg [1:0] ep_state_next [NUM_IN_EPS - 1:0];
// latched on valid IN token
reg [3:0] current_endp = 0;
wire [1:0] current_ep_state = ep_state[current_endp][1:0];
localparam READY_FOR_PKT = 0;
localparam PUTTING_PKT = 1;
localparam GETTING_PKT = 2;
localparam STALL = 3;
assign debug[1:0] = ( current_endp == 1 ) ? current_ep_state : 0;
////////////////////////////////////////////////////////////////////////////////
// in transfer state machine
////////////////////////////////////////////////////////////////////////////////
localparam IDLE = 0;
localparam RCVD_IN = 1;
localparam SEND_DATA = 2;
localparam WAIT_ACK = 3;
reg [1:0] in_xfr_state = IDLE;
reg [1:0] in_xfr_state_next;
assign debug[3:2] = ( current_endp == 1 ) ? in_xfr_state : 0;
reg in_xfr_start = 0;
reg in_xfr_end = 0;
assign debug[4] = tx_data_avail;
assign debug[5] = tx_data_get;
// data toggle state
reg [NUM_IN_EPS - 1:0] data_toggle = 0;
// endpoint data buffer
reg [7:0] in_data_buffer [(MAX_IN_PACKET_SIZE * NUM_IN_EPS) - 1:0];
// Address registers - one bit longer (6) than required (5) to permit fullness != emptyness
reg [5:0] ep_put_addr [NUM_IN_EPS - 1:0];
reg [5:0] ep_get_addr [NUM_IN_EPS - 1:0];
integer i = 0;
initial begin
for (i = 0; i < NUM_IN_EPS; i = i + 1) begin
ep_put_addr[i] = 0;
ep_get_addr[i] = 0;
ep_state[i] = 0;
end
end
reg [3:0] in_ep_num = 0;
// the actual address (note using only the real 5 bits of the incoming address + the high order buffer select)
wire [8:0] buffer_put_addr = {in_ep_num[3:0], ep_put_addr[in_ep_num][4:0]};
wire [8:0] buffer_get_addr = {current_endp[3:0], ep_get_addr[current_endp][4:0]};
// endpoint data packet buffer has a data packet ready to send
reg [NUM_IN_EPS - 1:0] endp_ready_to_send = 0;
// endpoint has some space free in its buffer
reg [NUM_IN_EPS - 1:0] endp_free = 0;
wire token_received =
rx_pkt_end &&
rx_pkt_valid &&
rx_pid[1:0] == 2'b01 &&
rx_addr == dev_addr &&
rx_endp < NUM_IN_EPS;
wire setup_token_received =
token_received &&
rx_pid[3:2] == 2'b11;
wire in_token_received =
token_received &&
rx_pid[3:2] == 2'b10;
wire ack_received =
rx_pkt_end &&
rx_pkt_valid &&
rx_pid == 4'b0010;
assign debug[ 6 ] = rx_pkt_start;
assign debug[ 7 ] = rx_pkt_end;
wire more_data_to_send =
ep_get_addr[current_endp][5:0] < ep_put_addr[current_endp][5:0];
wire [5:0] current_ep_get_addr = ep_get_addr[current_endp][5:0];
wire [5:0] current_ep_put_addr = ep_put_addr[current_endp][5:0];
wire tx_data_avail_i =
in_xfr_state == SEND_DATA &&
more_data_to_send;
assign tx_data_avail = tx_data_avail_i;
////////////////////////////////////////////////////////////////////////////////
// endpoint state machine
////////////////////////////////////////////////////////////////////////////////
genvar ep_num;
generate
for (ep_num = 0; ep_num < NUM_IN_EPS; ep_num = ep_num + 1) begin
// Manage next state
always @* begin
in_ep_acked[ep_num] <= 0;
ep_state_next[ep_num] <= ep_state[ep_num];
if (in_ep_stall[ep_num]) begin
ep_state_next[ep_num] <= STALL;
end else begin
case (ep_state[ep_num])
READY_FOR_PKT : begin
ep_state_next[ep_num] <= PUTTING_PKT;
end
PUTTING_PKT : begin
// if either the user says they're done or the buffer is full, move on to GETTING_PKT
if ( ( in_ep_data_done[ep_num] ) || ( ep_put_addr[ep_num][5] ) ) begin
ep_state_next[ep_num] <= GETTING_PKT;
end else begin
ep_state_next[ep_num] <= PUTTING_PKT;
end
end
GETTING_PKT : begin
// here we're waiting to send the data out, and receive an ACK token back
// No token, and we're here for a while.
if (in_xfr_end && current_endp == ep_num) begin
ep_state_next[ep_num] <= READY_FOR_PKT;
in_ep_acked[ep_num] <= 1;
end else begin
ep_state_next[ep_num] <= GETTING_PKT;
end
end
STALL : begin
if (setup_token_received && rx_endp == ep_num) begin
ep_state_next[ep_num] <= READY_FOR_PKT;
end else begin
ep_state_next[ep_num] <= STALL;
end
end
default begin
ep_state_next[ep_num] <= READY_FOR_PKT;
end
endcase
end
endp_free[ep_num] = !ep_put_addr[ep_num][5];
in_ep_data_free[ep_num] = endp_free[ep_num] && ep_state[ep_num] == PUTTING_PKT;
end
// Handle the data pointer (advancing and clearing)
always @(posedge clk) begin
if (reset || reset_ep[ep_num]) begin
ep_state[ep_num] <= READY_FOR_PKT;
end else begin
ep_state[ep_num] <= ep_state_next[ep_num];
case (ep_state[ep_num])
READY_FOR_PKT : begin
// make sure we start with a clear buffer (and the extra bit!)
ep_put_addr[ep_num][5:0] <= 0;
end
PUTTING_PKT : begin
// each time we are putting, and there's a data_put signal, increment the address
if (in_ep_data_put[ep_num] && ( ~ep_put_addr[ep_num][5] ) ) begin
ep_put_addr[ep_num][5:0] <= ep_put_addr[ep_num][5:0] + 1;
end
end
GETTING_PKT : begin
end
STALL : begin
end
endcase
end
end
end
endgenerate
// Decide which in_ep_num we're talking to
// Using the data put register is OK here
integer ep_num_decoder;
always @* begin
in_ep_num <= 0;
for (ep_num_decoder = 0; ep_num_decoder < NUM_IN_EPS; ep_num_decoder = ep_num_decoder + 1) begin
if (in_ep_data_put[ep_num_decoder]) begin
in_ep_num <= ep_num_decoder;
end
end
end
// Handle putting the new data into the buffer
always @(posedge clk) begin
case (ep_state[in_ep_num])
PUTTING_PKT : begin
if (in_ep_data_put[in_ep_num] && !ep_put_addr[in_ep_num][5]) begin
in_data_buffer[buffer_put_addr] <= in_ep_data;
end
end
endcase
end
////////////////////////////////////////////////////////////////////////////////
// in transfer state machine
////////////////////////////////////////////////////////////////////////////////
reg rollback_in_xfr;
always @* begin
in_xfr_state_next <= in_xfr_state;
in_xfr_start <= 0;
in_xfr_end <= 0;
tx_pkt_start <= 0;
tx_pid <= 4'b0000;
rollback_in_xfr <= 0;
case (in_xfr_state)
IDLE : begin
rollback_in_xfr <= 1;
if (in_token_received) begin
in_xfr_state_next <= RCVD_IN;
end else begin
in_xfr_state_next <= IDLE;
end
end
// Got an IN token
RCVD_IN : begin
tx_pkt_start <= 1;
if (ep_state[current_endp] == STALL) begin
in_xfr_state_next <= IDLE;
tx_pid <= 4'b1110; // STALL
end else if (ep_state[current_endp] == GETTING_PKT) begin
// if we were in GETTING_PKT (done getting data from the device), Send it!
in_xfr_state_next <= SEND_DATA;
tx_pid <= {data_toggle[current_endp], 3'b011}; // DATA0/1
in_xfr_start <= 1;
end else begin
in_xfr_state_next <= IDLE;
tx_pid <= 4'b1010; // NAK
end
end
SEND_DATA : begin
// Send the data from the buffer now (until the out (get) address = the in (put) address)
if (!more_data_to_send) begin
in_xfr_state_next <= WAIT_ACK;
end else begin
in_xfr_state_next <= SEND_DATA;
end
end
WAIT_ACK : begin
// FIXME: need to handle smash/timeout
// Could wait here forever (although another token will come along)
if (ack_received) begin
in_xfr_state_next <= IDLE;
in_xfr_end <= 1;
end else if (in_token_received) begin
in_xfr_state_next <= RCVD_IN;
rollback_in_xfr <= 1;
end else if (rx_pkt_end) begin
in_xfr_state_next <= IDLE;
rollback_in_xfr <= 1;
end else begin
in_xfr_state_next <= WAIT_ACK;
end
end
endcase
end
always @(posedge clk)
tx_data <= in_data_buffer[buffer_get_addr];
integer j;
always @(posedge clk) begin
if (reset) begin
in_xfr_state <= IDLE;
end else begin
in_xfr_state <= in_xfr_state_next;
// tx_data <= in_data_buffer[buffer_get_addr];
if (setup_token_received) begin
data_toggle[rx_endp] <= 1;
end
if (in_token_received) begin
current_endp <= rx_endp;
end
if (rollback_in_xfr) begin
ep_get_addr[current_endp][5:0] <= 0;
end
case (in_xfr_state)
IDLE : begin
end
RCVD_IN : begin
end
SEND_DATA : begin
if (tx_data_get && tx_data_avail_i) begin
ep_get_addr[current_endp][5:0] <= ep_get_addr[current_endp][5:0] + 1;
end
end
WAIT_ACK : begin
if (ack_received) begin
data_toggle[current_endp] <= !data_toggle[current_endp];
end
end
endcase
end
for (j = 0; j < NUM_IN_EPS; j = j + 1) begin
if (reset || reset_ep[j]) begin
data_toggle[j] <= 0;
ep_get_addr[j][5:0] <= 0;
end
end
end
endmodule

View File

@ -0,0 +1,25 @@
module usb_fs_out_arb #(
parameter NUM_OUT_EPS = 1
) (
////////////////////
// endpoint interface
////////////////////
input [NUM_OUT_EPS-1:0] out_ep_req,
output reg [NUM_OUT_EPS-1:0] out_ep_grant
);
integer i;
reg grant;
always @* begin
grant = 0;
for (i = 0; i < NUM_OUT_EPS; i = i + 1) begin
out_ep_grant[i] <= 0;
if (out_ep_req[i] && !grant) begin
out_ep_grant[i] <= 1;
grant = 1;
end
end
end
endmodule

View File

@ -0,0 +1,417 @@
// The OUT Protocol Engine receives data from the host.
module usb_fs_out_pe #(
parameter NUM_OUT_EPS = 1,
parameter MAX_OUT_PACKET_SIZE = 32
) (
input clk,
input reset,
input [NUM_OUT_EPS-1:0] reset_ep,
input [6:0] dev_addr,
////////////////////
// endpoint interface
////////////////////
output [NUM_OUT_EPS-1:0] out_ep_data_avail,
output reg [NUM_OUT_EPS-1:0] out_ep_setup = 0,
input [NUM_OUT_EPS-1:0] out_ep_data_get,
output reg [7:0] out_ep_data,
input [NUM_OUT_EPS-1:0] out_ep_stall,
output reg [NUM_OUT_EPS-1:0] out_ep_acked = 0,
// Added to provide a more constant way of detecting the current OUT EP than data get
input [NUM_OUT_EPS-1:0] out_ep_grant,
////////////////////
// rx path
////////////////////
// Strobed on reception of packet.
input rx_pkt_start,
input rx_pkt_end,
input rx_pkt_valid,
// Most recent packet received.
input [3:0] rx_pid,
input [6:0] rx_addr,
input [3:0] rx_endp,
input [10:0] rx_frame_num,
// rx_data is pushed into endpoint controller.
input rx_data_put,
input [7:0] rx_data,
////////////////////
// tx path
////////////////////
// Strobe to send new packet.
output reg tx_pkt_start = 0,
input tx_pkt_end,
output reg [3:0] tx_pid = 0
);
////////////////////////////////////////////////////////////////////////////////
// endpoint state machine
////////////////////////////////////////////////////////////////////////////////
localparam READY_FOR_PKT = 0;
localparam PUTTING_PKT = 1;
localparam GETTING_PKT = 2;
localparam STALL = 3;
reg [1:0] ep_state [NUM_OUT_EPS - 1:0];
reg [1:0] ep_state_next [NUM_OUT_EPS - 1:0];
////////////////////////////////////////////////////////////////////////////////
// out transfer state machine
////////////////////////////////////////////////////////////////////////////////
localparam IDLE = 0;
localparam RCVD_OUT = 1;
localparam RCVD_DATA_START = 2;
localparam RCVD_DATA_END = 3;
reg [1:0] out_xfr_state = IDLE;
reg [1:0] out_xfr_state_next;
reg out_xfr_start = 0;
reg new_pkt_end = 0;
reg rollback_data = 0;
reg [3:0] out_ep_num = 0;
reg [NUM_OUT_EPS - 1:0] out_ep_data_avail_i = 0;
reg [NUM_OUT_EPS - 1:0] out_ep_data_avail_j = 0;
// set when the endpoint buffer is unable to receive the out transfer
reg nak_out_transfer = 0;
// data toggle state
reg [NUM_OUT_EPS - 1:0] data_toggle = 0;
// latched on valid OUT/SETUP token
reg [3:0] current_endp = 0;
wire [1:0] current_ep_state = ep_state[current_endp];
// endpoint data buffer
reg [7:0] out_data_buffer [(MAX_OUT_PACKET_SIZE * NUM_OUT_EPS) - 1:0];
// current get_addr when outputting a packet from the buffer
reg [5:0] ep_get_addr [NUM_OUT_EPS - 1:0];
reg [5:0] ep_get_addr_next [NUM_OUT_EPS - 1:0];
// endpoint put_addrs when inputting a packet into the buffer
reg [5:0] ep_put_addr [NUM_OUT_EPS - 1:0];
// total buffer put addr, uses endpoint number and that endpoints current
// put address
wire [8:0] buffer_put_addr = {current_endp[3:0], ep_put_addr[current_endp][4:0]};
wire [8:0] buffer_get_addr = {out_ep_num[3:0], ep_get_addr[out_ep_num][4:0]};
wire token_received =
rx_pkt_end &&
rx_pkt_valid &&
rx_pid[1:0] == 2'b01 &&
rx_addr == dev_addr &&
rx_endp < NUM_OUT_EPS;
wire out_token_received =
token_received &&
rx_pid[3:2] == 2'b00;
wire setup_token_received =
token_received &&
rx_pid[3:2] == 2'b11;
wire invalid_packet_received =
rx_pkt_end &&
!rx_pkt_valid;
wire data_packet_received =
rx_pkt_end &&
rx_pkt_valid &&
rx_pid[2:0] == 3'b011;
wire non_data_packet_received =
rx_pkt_end &&
rx_pkt_valid &&
rx_pid[2:0] != 3'b011;
//reg last_data_toggle = 0;
wire bad_data_toggle =
data_packet_received &&
rx_pid[3] != data_toggle[rx_endp];
//last_data_toggle == data_toggle[current_endp];
////////////////////////////////////////////////////////////////////////////////
// endpoint state machine
////////////////////////////////////////////////////////////////////////////////
genvar ep_num;
generate
for (ep_num = 0; ep_num < NUM_OUT_EPS; ep_num = ep_num + 1) begin
always @* begin
ep_state_next[ep_num] <= ep_state[ep_num];
if (out_ep_stall[ep_num]) begin
ep_state_next[ep_num] <= STALL;
end else begin
case (ep_state[ep_num])
READY_FOR_PKT : begin
if (out_xfr_start && rx_endp == ep_num) begin
ep_state_next[ep_num] <= PUTTING_PKT;
end else begin
ep_state_next[ep_num] <= READY_FOR_PKT;
end
end
PUTTING_PKT : begin
if (new_pkt_end && current_endp == ep_num) begin
ep_state_next[ep_num] <= GETTING_PKT;
end else if (rollback_data && current_endp == ep_num) begin
ep_state_next[ep_num] <= READY_FOR_PKT;
end else begin
ep_state_next[ep_num] <= PUTTING_PKT;
end
end
GETTING_PKT : begin
if (ep_get_addr[ep_num][5:0] >= (ep_put_addr[ep_num][5:0] - 6'H2)) begin
ep_state_next[ep_num] <= READY_FOR_PKT;
end else begin
ep_state_next[ep_num] <= GETTING_PKT;
end
end
STALL : begin
if (setup_token_received && rx_endp == ep_num) begin
ep_state_next[ep_num] <= READY_FOR_PKT;
end else begin
ep_state_next[ep_num] <= STALL;
end
end
default begin
ep_state_next[ep_num] <= READY_FOR_PKT;
end
endcase
end
// Determine the next get_address (init, inc, maintain)
if (ep_state_next[ep_num][1:0] == READY_FOR_PKT) begin
ep_get_addr_next[ep_num][5:0] <= 0;
end else if (ep_state_next[ep_num][1:0] == GETTING_PKT && out_ep_data_get[ep_num]) begin
ep_get_addr_next[ep_num][5:0] <= ep_get_addr[ep_num][5:0] + 6'H1;
end else begin
ep_get_addr_next[ep_num][5:0] <= ep_get_addr[ep_num][5:0];
end
end // end of the always @*
// Advance the state to the next one.
always @(posedge clk) begin
if (reset || reset_ep[ep_num]) begin
ep_state[ep_num] <= READY_FOR_PKT;
end else begin
ep_state[ep_num] <= ep_state_next[ep_num];
end
ep_get_addr[ep_num][5:0] <= ep_get_addr_next[ep_num][5:0];
end
assign out_ep_data_avail[ep_num] =
(ep_get_addr[ep_num][5:0] < (ep_put_addr[ep_num][5:0] - 6'H2)) &&
(ep_state[ep_num][1:0] == GETTING_PKT);
end
endgenerate
integer i;
always @(posedge clk) begin
if (reset) begin
out_ep_setup <= 0;
end else begin
if (setup_token_received) begin
out_ep_setup[rx_endp] <= 1;
end else if (out_token_received) begin
out_ep_setup[rx_endp] <= 0;
end
end
for (i = 0; i < NUM_OUT_EPS; i = i + 1) begin
if (reset_ep[i]) begin
out_ep_setup[i] <= 0;
end
end
end
always @(posedge clk) out_ep_data <= out_data_buffer[buffer_get_addr][7:0];
// use the bus grant line to determine the out_ep_num (where the data is)
integer ep_num_decoder;
always @* begin
out_ep_num <= 0;
for (ep_num_decoder = 0; ep_num_decoder < NUM_OUT_EPS; ep_num_decoder = ep_num_decoder + 1) begin
if (out_ep_grant[ep_num_decoder]) begin
out_ep_num <= ep_num_decoder;
end
end
end
////////////////////////////////////////////////////////////////////////////////
// out transfer state machine
////////////////////////////////////////////////////////////////////////////////
always @* begin
out_ep_acked <= 0;
out_xfr_start <= 0;
out_xfr_state_next <= out_xfr_state;
tx_pkt_start <= 0;
tx_pid <= 0;
new_pkt_end <= 0;
rollback_data <= 0;
case (out_xfr_state)
IDLE : begin
if (out_token_received || setup_token_received) begin
out_xfr_state_next <= RCVD_OUT;
out_xfr_start <= 1;
end else begin
out_xfr_state_next <= IDLE;
end
end
RCVD_OUT : begin
if (rx_pkt_start) begin
out_xfr_state_next <= RCVD_DATA_START;
end else begin
out_xfr_state_next <= RCVD_OUT;
end
end
RCVD_DATA_START : begin
if (bad_data_toggle) begin
out_xfr_state_next <= IDLE;
rollback_data <= 1;
tx_pkt_start <= 1;
tx_pid <= 4'b0010; // ACK
end else if (invalid_packet_received || non_data_packet_received) begin
out_xfr_state_next <= IDLE;
rollback_data <= 1;
end else if (data_packet_received) begin
out_xfr_state_next <= RCVD_DATA_END;
end else begin
out_xfr_state_next <= RCVD_DATA_START;
end
end
RCVD_DATA_END : begin
out_xfr_state_next <= IDLE;
tx_pkt_start <= 1;
if (ep_state[current_endp] == STALL) begin
tx_pid <= 4'b1110; // STALL
end else if (nak_out_transfer) begin
tx_pid <= 4'b1010; // NAK
rollback_data <= 1;
end else begin
tx_pid <= 4'b0010; // ACK
new_pkt_end <= 1;
out_ep_acked[current_endp] <= 1;
//end else begin
// tx_pid <= 4'b0010; // ACK
// rollback_data <= 1;
end
end
default begin
out_xfr_state_next <= IDLE;
end
endcase
end
wire current_ep_busy =
(ep_state[current_endp] == GETTING_PKT) ||
(ep_state[current_endp] == READY_FOR_PKT);
integer j;
always @(posedge clk) begin
if (reset) begin
out_xfr_state <= IDLE;
end else begin
out_xfr_state <= out_xfr_state_next;
if (out_xfr_start) begin
current_endp <= rx_endp;
//last_data_toggle <= setup_token_received ? 0 : data_toggle[rx_endp];
end
if (new_pkt_end) begin
data_toggle[current_endp] <= !data_toggle[current_endp];
end
if (setup_token_received) begin
data_toggle[rx_endp] <= 0;
end
case (out_xfr_state)
IDLE : begin
end
RCVD_OUT : begin
if (current_ep_busy) begin
nak_out_transfer <= 1;
end else begin
nak_out_transfer <= 0;
ep_put_addr[current_endp][5:0] <= 0;
end
end
RCVD_DATA_START : begin
if (!nak_out_transfer && rx_data_put && !ep_put_addr[current_endp][5]) begin
out_data_buffer[buffer_put_addr][7:0] <= rx_data;
end
if (!nak_out_transfer && rx_data_put) begin
ep_put_addr[current_endp][5:0] <= ep_put_addr[current_endp][5:0] + 6'H1;
end
end
RCVD_DATA_END : begin
end
endcase
end
for (j = 0; j < NUM_OUT_EPS; j = j + 1) begin
if (reset || reset_ep[j]) begin
data_toggle[j] <= 0;
ep_put_addr[j][5:0] <= 0;
end
end
end
endmodule

View File

@ -0,0 +1,239 @@
module usb_fs_pe #(
parameter [4:0] NUM_OUT_EPS = 1,
parameter [4:0] NUM_IN_EPS = 1
) (
input clk,
input [6:0] dev_addr,
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// USB Endpoint Interface
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////
// global endpoint interface
////////////////////
input reset,
////////////////////
// out endpoint interfaces
////////////////////
input [NUM_OUT_EPS-1:0] out_ep_req,
output [NUM_OUT_EPS-1:0] out_ep_grant,
output [NUM_OUT_EPS-1:0] out_ep_data_avail,
output [NUM_OUT_EPS-1:0] out_ep_setup,
input [NUM_OUT_EPS-1:0] out_ep_data_get,
output [7:0] out_ep_data,
input [NUM_OUT_EPS-1:0] out_ep_stall,
output [NUM_OUT_EPS-1:0] out_ep_acked,
////////////////////
// in endpoint interfaces
////////////////////
input [NUM_IN_EPS-1:0] in_ep_req,
output [NUM_IN_EPS-1:0] in_ep_grant,
output [NUM_IN_EPS-1:0] in_ep_data_free,
input [NUM_IN_EPS-1:0] in_ep_data_put,
input [(NUM_IN_EPS*8)-1:0] in_ep_data,
input [NUM_IN_EPS-1:0] in_ep_data_done,
input [NUM_IN_EPS-1:0] in_ep_stall,
output [NUM_IN_EPS-1:0] in_ep_acked,
////////////////////
// sof interface
////////////////////
output sof_valid,
output [10:0] frame_index,
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/// USB TX/RX Interface
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
output usb_p_tx,
output usb_n_tx,
input usb_p_rx,
input usb_n_rx,
output usb_tx_en,
output [7:0] debug
);
// in pe interface
wire [7:0] arb_in_ep_data;
// rx interface
wire bit_strobe;
wire rx_pkt_start;
wire rx_pkt_end;
wire [3:0] rx_pid;
wire [6:0] rx_addr;
wire [3:0] rx_endp;
wire [10:0] rx_frame_num;
wire rx_data_put;
wire [7:0] rx_data;
wire rx_pkt_valid;
// tx mux
wire in_tx_pkt_start;
wire [3:0] in_tx_pid;
wire out_tx_pkt_start;
wire [3:0] out_tx_pid;
// tx interface
wire tx_pkt_start;
wire tx_pkt_end;
wire [3:0] tx_pid;
wire tx_data_avail;
wire tx_data_get;
wire [7:0] tx_data;
// sof interface
assign sof_valid = rx_pkt_end && rx_pkt_valid && rx_pid == 4'b0101;
assign frame_index = rx_frame_num;
usb_fs_in_arb #(
.NUM_IN_EPS(NUM_IN_EPS)
) usb_fs_in_arb_inst (
// endpoint interface
.in_ep_req(in_ep_req),
.in_ep_grant(in_ep_grant),
.in_ep_data(in_ep_data),
// protocol engine interface
.arb_in_ep_data(arb_in_ep_data)
);
usb_fs_out_arb #(
.NUM_OUT_EPS(NUM_OUT_EPS)
) usb_fs_out_arb_inst (
// endpoint interface
.out_ep_req(out_ep_req),
.out_ep_grant(out_ep_grant)
);
usb_fs_in_pe #(
.NUM_IN_EPS(NUM_IN_EPS)
) usb_fs_in_pe_inst (
.clk(clk),
.reset(reset),
.reset_ep({NUM_IN_EPS{1'b0}}),
.dev_addr(dev_addr),
// endpoint interface
.in_ep_data_free(in_ep_data_free),
.in_ep_data_put(in_ep_data_put),
.in_ep_data(arb_in_ep_data),
.in_ep_data_done(in_ep_data_done),
.in_ep_stall(in_ep_stall),
.in_ep_acked(in_ep_acked),
// rx path
.rx_pkt_start(rx_pkt_start),
.rx_pkt_end(rx_pkt_end),
.rx_pkt_valid(rx_pkt_valid),
.rx_pid(rx_pid),
.rx_addr(rx_addr),
.rx_endp(rx_endp),
.rx_frame_num(rx_frame_num),
// tx path
.tx_pkt_start(in_tx_pkt_start),
.tx_pkt_end(tx_pkt_end),
.tx_pid(in_tx_pid),
.tx_data_avail(tx_data_avail),
.tx_data_get(tx_data_get),
.tx_data(tx_data),
.debug(debug)
);
usb_fs_out_pe #(
.NUM_OUT_EPS(NUM_OUT_EPS)
) usb_fs_out_pe_inst (
.clk(clk),
.reset(reset),
.reset_ep({NUM_OUT_EPS{1'b0}}),
.dev_addr(dev_addr),
// endpoint interface
.out_ep_data_avail(out_ep_data_avail),
.out_ep_data_get(out_ep_data_get),
.out_ep_data(out_ep_data),
.out_ep_setup(out_ep_setup),
.out_ep_stall(out_ep_stall),
.out_ep_acked(out_ep_acked),
.out_ep_grant(out_ep_grant),
// rx path
.rx_pkt_start(rx_pkt_start),
.rx_pkt_end(rx_pkt_end),
.rx_pkt_valid(rx_pkt_valid),
.rx_pid(rx_pid),
.rx_addr(rx_addr),
.rx_endp(rx_endp),
.rx_frame_num(rx_frame_num),
.rx_data_put(rx_data_put),
.rx_data(rx_data),
// tx path
.tx_pkt_start(out_tx_pkt_start),
.tx_pkt_end(tx_pkt_end),
.tx_pid(out_tx_pid)
);
usb_fs_rx usb_fs_rx_inst (
.clk_48mhz(clk),
.reset(reset),
.dp(usb_p_rx),
.dn(usb_n_rx),
.bit_strobe(bit_strobe),
.pkt_start(rx_pkt_start),
.pkt_end(rx_pkt_end),
.pid(rx_pid),
.addr(rx_addr),
.endp(rx_endp),
.frame_num(rx_frame_num),
.rx_data_put(rx_data_put),
.rx_data(rx_data),
.valid_packet(rx_pkt_valid)
);
usb_fs_tx_mux usb_fs_tx_mux_inst (
// interface to IN Protocol Engine
.in_tx_pkt_start(in_tx_pkt_start),
.in_tx_pid(in_tx_pid),
// interface to OUT Protocol Engine
.out_tx_pkt_start(out_tx_pkt_start),
.out_tx_pid(out_tx_pid),
// interface to tx module
.tx_pkt_start(tx_pkt_start),
.tx_pid(tx_pid)
);
usb_fs_tx usb_fs_tx_inst (
.clk_48mhz(clk),
.reset(reset),
.bit_strobe(bit_strobe),
.oe(usb_tx_en),
.dp(usb_p_tx),
.dn(usb_n_tx),
.pkt_start(tx_pkt_start),
.pkt_end(tx_pkt_end),
.pid(tx_pid),
.tx_data_avail(tx_data_avail),
.tx_data_get(tx_data_get),
.tx_data(tx_data)
);
endmodule

View File

@ -0,0 +1,366 @@
module usb_fs_rx (
// A 48MHz clock is required to recover the clock from the incoming data.
input clk_48mhz,
input reset,
// USB data+ and data- lines.
input dp,
input dn,
// pulse on every bit transition.
output bit_strobe,
// Pulse on beginning of new packet.
output pkt_start,
// Pulse on end of current packet.
output pkt_end,
// Most recent packet decoded.
output [3:0] pid,
output reg [6:0] addr = 0,
output reg [3:0] endp = 0,
output reg [10:0] frame_num = 0,
// Pulse on valid data on rx_data.
output rx_data_put,
output [7:0] rx_data,
// Most recent packet passes PID and CRC checks
output valid_packet
);
wire clk = clk_48mhz;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////
//////// usb receive path
////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// double flop for metastability
/*
all asynchronous inputs into the RTL need to be double-flopped to protect
against metastable scenarios. if the RTL clock samples an asynchronous signal
at the same time the signal is transitioning the result is undefined. flopping
the signal twice ensures it will be either 1 or 0 and nothing in between.
*/
reg [3:0] dpair_q = 0;
always @(posedge clk) begin
dpair_q[3:0] <= {dpair_q[1:0], dp, dn};
end
////////////////////////////////////////////////////////////////////////////////
// line state recovery state machine
/*
the recieve path doesn't currently use a differential reciever. because of
this there is a chance that one of the differential pairs will appear to have
changed to the new state while the other is still in the old state. the
following state machine detects transitions and waits an extra sampling clock
before decoding the state on the differential pair. this transition period
will only ever last for one clock as long as there is no noise on the line.
if there is enough noise on the line then the data may be corrupted and the
packet will fail the data integrity checks.
*/
reg [2:0] line_state = 0;
localparam DT = 3'b100;
localparam DJ = 3'b010;
localparam DK = 3'b001;
localparam SE0 = 3'b000;
localparam SE1 = 3'b011;
wire [1:0] dpair = dpair_q[3:2];
always @(posedge clk) begin
case (line_state)
// if we are in a transition state, then we can sample the pair and
// move to the next corresponding line state
DT : begin
case (dpair)
2'b10 : line_state <= DJ;
2'b01 : line_state <= DK;
2'b00 : line_state <= SE0;
2'b11 : line_state <= SE1;
endcase
end
// if we are in a valid line state and the value of the pair changes,
// then we need to move to the transition state
DJ : if (dpair != 2'b10) line_state <= DT;
DK : if (dpair != 2'b01) line_state <= DT;
SE0 : if (dpair != 2'b00) line_state <= DT;
SE1 : if (dpair != 2'b11) line_state <= DT;
// if we are in an invalid state we should move to the transition state
default : line_state <= DT;
endcase
end
////////////////////////////////////////////////////////////////////////////////
// clock recovery
/*
the DT state from the line state recovery state machine is used to align to
transmit clock. the line state is sampled in the middle of the bit time.
example of signal relationships
-------------------------------
line_state DT DJ DJ DJ DT DK DK DK DK DK DK DT DJ DJ DJ
line_state_valid ________----____________----____________----________----____
bit_phase 0 0 1 2 3 0 1 2 3 0 1 2 0 1 2
*/
reg [1:0] bit_phase = 0;
wire line_state_valid = (bit_phase == 1);
assign bit_strobe = (bit_phase == 2);
always @(posedge clk) begin
// keep track of phase within each bit
if (line_state == DT) begin
bit_phase <= 0;
end else begin
bit_phase <= bit_phase + 1;
end
end
////////////////////////////////////////////////////////////////////////////////
// packet detection
/*
usb uses a sync to denote the beginning of a packet and two single-ended-0 to
denote the end of a packet. this state machine recognizes the beginning and
end of packets for subsequent layers to process.
*/
reg [5:0] line_history = 0;
reg packet_valid = 0;
reg next_packet_valid;
wire packet_start = next_packet_valid && !packet_valid;
wire packet_end = !next_packet_valid && packet_valid;
always @* begin
if (line_state_valid) begin
// check for packet start: KJKJKK
if (!packet_valid && line_history[5:0] == 6'b100101) begin
next_packet_valid <= 1;
end
// check for packet end: SE0 SE0
else if (packet_valid && line_history[3:0] == 4'b0000) begin
next_packet_valid <= 0;
end else begin
next_packet_valid <= packet_valid;
end
end else begin
next_packet_valid <= packet_valid;
end
end
always @(posedge clk) begin
if (reset) begin
line_history <= 6'b101010;
packet_valid <= 0;
end else begin
// keep a history of the last two states on the line
if (line_state_valid) begin
line_history[5:0] <= {line_history[3:0], line_state[1:0]};
end
end
packet_valid <= next_packet_valid;
end
////////////////////////////////////////////////////////////////////////////////
// NRZI decode
/*
in order to ensure there are enough bit transitions for a receiver to recover
the clock usb uses NRZI encoding.
https://en.wikipedia.org/wiki/Non-return-to-zero
*/
reg dvalid_raw;
reg din;
always @* begin
case (line_history[3:0])
4'b0101 : din <= 1;
4'b0110 : din <= 0;
4'b1001 : din <= 0;
4'b1010 : din <= 1;
default : din <= 0;
endcase
if (packet_valid && line_state_valid) begin
case (line_history[3:0])
4'b0101 : dvalid_raw <= 1;
4'b0110 : dvalid_raw <= 1;
4'b1001 : dvalid_raw <= 1;
4'b1010 : dvalid_raw <= 1;
default : dvalid_raw <= 0;
endcase
end else begin
dvalid_raw <= 0;
end
end
reg [5:0] bitstuff_history = 0;
always @(posedge clk) begin
if (reset || packet_end) begin
bitstuff_history <= 6'b000000;
end else begin
if (dvalid_raw) begin
bitstuff_history <= {bitstuff_history[4:0], din};
end
end
end
wire dvalid = dvalid_raw && !(bitstuff_history == 6'b111111);
////////////////////////////////////////////////////////////////////////////////
// save and check pid
/*
shift in the entire 8-bit pid with an additional 9th bit used as a sentinal.
*/
reg [8:0] full_pid = 0;
wire pid_valid = full_pid[4:1] == ~full_pid[8:5];
wire pid_complete = full_pid[0];
always @(posedge clk) begin
if (packet_start) begin
full_pid <= 9'b100000000;
end
if (dvalid && !pid_complete) begin
full_pid <= {din, full_pid[8:1]};
end
end
////////////////////////////////////////////////////////////////////////////////
// check crc5
reg [4:0] crc5 = 0;
wire crc5_valid = crc5 == 5'b01100;
wire crc5_invert = din ^ crc5[4];
always @(posedge clk) begin
if (packet_start) begin
crc5 <= 5'b11111;
end
if (dvalid && pid_complete) begin
crc5[4] <= crc5[3];
crc5[3] <= crc5[2];
crc5[2] <= crc5[1] ^ crc5_invert;
crc5[1] <= crc5[0];
crc5[0] <= crc5_invert;
end
end
////////////////////////////////////////////////////////////////////////////////
// check crc16
reg [15:0] crc16 = 0;
wire crc16_valid = crc16 == 16'b1000000000001101;
wire crc16_invert = din ^ crc16[15];
always @(posedge clk) begin
if (packet_start) begin
crc16 <= 16'b1111111111111111;
end
if (dvalid && pid_complete) begin
crc16[15] <= crc16[14] ^ crc16_invert;
crc16[14] <= crc16[13];
crc16[13] <= crc16[12];
crc16[12] <= crc16[11];
crc16[11] <= crc16[10];
crc16[10] <= crc16[9];
crc16[9] <= crc16[8];
crc16[8] <= crc16[7];
crc16[7] <= crc16[6];
crc16[6] <= crc16[5];
crc16[5] <= crc16[4];
crc16[4] <= crc16[3];
crc16[3] <= crc16[2];
crc16[2] <= crc16[1] ^ crc16_invert;
crc16[1] <= crc16[0];
crc16[0] <= crc16_invert;
end
end
////////////////////////////////////////////////////////////////////////////////
// output control signals
wire pkt_is_token = full_pid[2:1] == 2'b01;
wire pkt_is_data = full_pid[2:1] == 2'b11;
wire pkt_is_handshake = full_pid[2:1] == 2'b10;
// TODO: need to check for data packet babble
// TODO: do i need to check for bitstuff error?
assign valid_packet = pid_valid && (
(pkt_is_handshake) ||
(pkt_is_data && crc16_valid) ||
(pkt_is_token && crc5_valid)
);
reg [11:0] token_payload = 0;
wire token_payload_done = token_payload[0];
always @(posedge clk) begin
if (packet_start) begin
token_payload <= 12'b100000000000;
end
if (dvalid && pid_complete && pkt_is_token && !token_payload_done) begin
token_payload <= {din, token_payload[11:1]};
end
end
always @(posedge clk) begin
if (token_payload_done && pkt_is_token) begin
addr <= token_payload[7:1];
endp <= token_payload[11:8];
frame_num <= token_payload[11:1];
end
end
assign pkt_start = packet_start;
assign pkt_end = packet_end;
assign pid = full_pid[4:1];
//assign addr = token_payload[7:1];
//assign endp = token_payload[11:8];
//assign frame_num = token_payload[11:1];
////////////////////////////////////////////////////////////////////////////////
// deserialize and output data
//assign rx_data_put = dvalid && pid_complete && pkt_is_data;
reg [8:0] rx_data_buffer = 0;
wire rx_data_buffer_full = rx_data_buffer[0];
assign rx_data_put = rx_data_buffer_full;
assign rx_data = rx_data_buffer[8:1];
always @(posedge clk) begin
if (packet_start || rx_data_buffer_full) begin
rx_data_buffer <= 9'b100000000;
end
if (dvalid && pid_complete && pkt_is_data) begin
rx_data_buffer <= {din, rx_data_buffer[8:1]};
end
end
endmodule // usb_fs_rx

View File

@ -0,0 +1,243 @@
module usb_fs_tx (
// A 48MHz clock is required to receive USB data at 12MHz
// it's simpler to juse use 48MHz everywhere
input clk_48mhz,
input reset,
// bit strobe from rx to align with senders clock
input bit_strobe,
// output enable to take ownership of bus and data out
output reg oe = 0,
output reg dp = 0,
output reg dn = 0,
// pulse to initiate new packet transmission
input pkt_start,
output pkt_end,
// pid to send
input [3:0] pid,
// tx logic pulls data until there is nothing available
input tx_data_avail,
output reg tx_data_get = 0,
input [7:0] tx_data
);
wire clk = clk_48mhz;
// save packet parameters at pkt_start
reg [3:0] pidq = 0;
always @(posedge clk) begin
if (pkt_start) begin
pidq <= pid;
end
end
reg [7:0] data_shift_reg = 0;
reg [7:0] oe_shift_reg = 0;
reg [7:0] se0_shift_reg = 0;
wire serial_tx_data = data_shift_reg[0];
wire serial_tx_oe = oe_shift_reg[0];
wire serial_tx_se0 = se0_shift_reg[0];
// serialize sync, pid, data payload, and crc16
reg byte_strobe = 0;
reg [2:0] bit_count = 0;
reg [4:0] bit_history_q = 0;
wire [5:0] bit_history = {serial_tx_data, bit_history_q};
wire bitstuff = bit_history == 6'b111111;
reg bitstuff_q = 0;
reg bitstuff_qq = 0;
reg bitstuff_qqq = 0;
reg bitstuff_qqqq = 0;
always @(posedge clk) begin
bitstuff_q <= bitstuff;
bitstuff_qq <= bitstuff_q;
bitstuff_qqq <= bitstuff_qq;
bitstuff_qqqq <= bitstuff_qqq;
end
assign pkt_end = bit_strobe && se0_shift_reg[1:0] == 2'b01;
reg data_payload = 0;
reg [31:0] pkt_state = 0;
localparam IDLE = 0;
localparam SYNC = 1;
localparam PID = 2;
localparam DATA_OR_CRC16_0 = 3;
localparam CRC16_1 = 4;
localparam EOP = 5;
reg [15:0] crc16 = 0;
always @(posedge clk) begin
case (pkt_state)
IDLE : begin
if (pkt_start) begin
pkt_state <= SYNC;
end
end
SYNC : begin
if (byte_strobe) begin
pkt_state <= PID;
data_shift_reg <= 8'b10000000;
oe_shift_reg <= 8'b11111111;
se0_shift_reg <= 8'b00000000;
end
end
PID : begin
if (byte_strobe) begin
if (pidq[1:0] == 2'b11) begin
pkt_state <= DATA_OR_CRC16_0;
end else begin
pkt_state <= EOP;
end
data_shift_reg <= {~pidq, pidq};
oe_shift_reg <= 8'b11111111;
se0_shift_reg <= 8'b00000000;
end
end
DATA_OR_CRC16_0 : begin
if (byte_strobe) begin
if (tx_data_avail) begin
pkt_state <= DATA_OR_CRC16_0;
data_payload <= 1;
tx_data_get <= 1;
data_shift_reg <= tx_data;
oe_shift_reg <= 8'b11111111;
se0_shift_reg <= 8'b00000000;
end else begin
pkt_state <= CRC16_1;
data_payload <= 0;
tx_data_get <= 0;
data_shift_reg <= ~{crc16[8], crc16[9], crc16[10], crc16[11], crc16[12], crc16[13], crc16[14], crc16[15]};
oe_shift_reg <= 8'b11111111;
se0_shift_reg <= 8'b00000000;
end
end else begin
tx_data_get <= 0;
end
end
CRC16_1 : begin
if (byte_strobe) begin
pkt_state <= EOP;
data_shift_reg <= ~{crc16[0], crc16[1], crc16[2], crc16[3], crc16[4], crc16[5], crc16[6], crc16[7]};
oe_shift_reg <= 8'b11111111;
se0_shift_reg <= 8'b00000000;
end
end
EOP : begin
if (byte_strobe) begin
pkt_state <= IDLE;
oe_shift_reg <= 8'b00000111;
se0_shift_reg <= 8'b00000111;
end
end
endcase
if (bit_strobe && !bitstuff) begin
byte_strobe <= (bit_count == 3'b000);
end else begin
byte_strobe <= 0;
end
if (pkt_start) begin
bit_count <= 1;
bit_history_q <= 0;
end else if (bit_strobe) begin
// bitstuff
if (bitstuff /* && !serial_tx_se0*/) begin
bit_history_q <= bit_history[5:1];
data_shift_reg[0] <= 0;
// normal deserialize
end else begin
bit_count <= bit_count + 1;
data_shift_reg <= (data_shift_reg >> 1);
oe_shift_reg <= (oe_shift_reg >> 1);
se0_shift_reg <= (se0_shift_reg >> 1);
bit_history_q <= bit_history[5:1];
end
end
end
// calculate crc16
wire crc16_invert = serial_tx_data ^ crc16[15];
always @(posedge clk) begin
if (pkt_start) begin
crc16 <= 16'b1111111111111111;
end
if (bit_strobe && data_payload && !bitstuff_qqqq && !pkt_start) begin
crc16[15] <= crc16[14] ^ crc16_invert;
crc16[14] <= crc16[13];
crc16[13] <= crc16[12];
crc16[12] <= crc16[11];
crc16[11] <= crc16[10];
crc16[10] <= crc16[9];
crc16[9] <= crc16[8];
crc16[8] <= crc16[7];
crc16[7] <= crc16[6];
crc16[6] <= crc16[5];
crc16[5] <= crc16[4];
crc16[4] <= crc16[3];
crc16[3] <= crc16[2];
crc16[2] <= crc16[1] ^ crc16_invert;
crc16[1] <= crc16[0];
crc16[0] <= crc16_invert;
end
end
reg [2:0] dp_eop = 0;
// nrzi and differential driving
always @(posedge clk) begin
if (pkt_start) begin
// J
dp <= 1;
dn <= 0;
dp_eop <= 3'b100;
end else if (bit_strobe) begin
oe <= serial_tx_oe;
if (serial_tx_se0) begin
dp <= dp_eop[0];
dn <= 0;
dp_eop <= dp_eop >> 1;
end else if (serial_tx_data) begin
// value should stay the same, do nothing
end else begin
dp <= !dp;
dn <= !dn;
end
end
end
endmodule

View File

@ -0,0 +1,16 @@
module usb_fs_tx_mux (
// interface to IN Protocol Engine
input in_tx_pkt_start,
input [3:0] in_tx_pid,
// interface to OUT Protocol Engine
input out_tx_pkt_start,
input [3:0] out_tx_pid,
// interface to tx module
output tx_pkt_start,
output [3:0] tx_pid
);
assign tx_pkt_start = in_tx_pkt_start | out_tx_pkt_start;
assign tx_pid = out_tx_pkt_start ? out_tx_pid : in_tx_pid;
endmodule

View File

@ -0,0 +1,31 @@
// detects USB port reset signal from host
module usb_reset_det (
input clk,
output reset,
input usb_p_rx,
input usb_n_rx
);
// reset detection
reg [16:0] reset_timer = 0;
reg reset_i = 0;
wire timer_expired = reset_timer > 16'd30000;
always @(posedge clk) reset_i <= timer_expired;
assign reset = reset_i;
always @(posedge clk) begin
if (usb_p_rx || usb_n_rx) begin
reset_timer <= 0;
end else begin
// SE0 detected from host
if (!timer_expired) begin
// timer not expired yet, keep counting
reset_timer <= reset_timer + 1;
end
end
end
endmodule

View File

@ -0,0 +1,473 @@
module usb_serial_ctrl_ep #(
parameter MAX_IN_PACKET_SIZE = 32,
parameter MAX_OUT_PACKET_SIZE = 32
) (
input clk,
input reset,
output [6:0] dev_addr,
////////////////////
// out endpoint interface
////////////////////
output out_ep_req,
input out_ep_grant,
input out_ep_data_avail,
input out_ep_setup,
output out_ep_data_get,
input [7:0] out_ep_data,
output out_ep_stall,
input out_ep_acked,
////////////////////
// in endpoint interface
////////////////////
output in_ep_req,
input in_ep_grant,
input in_ep_data_free,
output in_ep_data_put,
output reg [7:0] in_ep_data = 0,
output in_ep_data_done,
output reg in_ep_stall,
input in_ep_acked
);
localparam IDLE = 0;
localparam SETUP = 1;
localparam DATA_IN = 2;
localparam DATA_OUT = 3;
localparam STATUS_IN = 4;
localparam STATUS_OUT = 5;
reg [5:0] ctrl_xfr_state = IDLE;
reg [5:0] ctrl_xfr_state_next;
reg setup_stage_end = 0;
reg data_stage_end = 0;
reg status_stage_end = 0;
reg send_zero_length_data_pkt = 0;
// the default control endpoint gets assigned the device address
reg [6:0] dev_addr_i = 0;
assign dev_addr = dev_addr_i;
assign out_ep_req = out_ep_data_avail;
assign out_ep_data_get = out_ep_data_avail;
reg out_ep_data_valid = 0;
always @(posedge clk) out_ep_data_valid <= out_ep_data_avail && out_ep_grant;
// need to record the setup data
reg [3:0] setup_data_addr = 0;
reg [9:0] raw_setup_data [7:0];
wire [7:0] bmRequestType = raw_setup_data[0];
wire [7:0] bRequest = raw_setup_data[1];
wire [15:0] wValue = {raw_setup_data[3][7:0], raw_setup_data[2][7:0]};
wire [15:0] wIndex = {raw_setup_data[5][7:0], raw_setup_data[4][7:0]};
wire [15:0] wLength = {raw_setup_data[7][7:0], raw_setup_data[6][7:0]};
// keep track of new out data start and end
wire pkt_start;
wire pkt_end;
rising_edge_detector detect_pkt_start (
.clk(clk),
.in(out_ep_data_avail),
.out(pkt_start)
);
falling_edge_detector detect_pkt_end (
.clk(clk),
.in(out_ep_data_avail),
.out(pkt_end)
);
assign out_ep_stall = 1'b0;
wire setup_pkt_start = pkt_start && out_ep_setup;
// wire has_data_stage = wLength != 16'b0000000000000000; // this version for some reason causes a 16b carry which is slow
wire has_data_stage = |wLength;
wire out_data_stage;
assign out_data_stage = has_data_stage && !bmRequestType[7];
wire in_data_stage;
assign in_data_stage = has_data_stage && bmRequestType[7];
reg [7:0] bytes_sent = 0;
reg [6:0] rom_length = 0;
wire all_data_sent =
(bytes_sent >= rom_length) ||
(bytes_sent >= wLength[7:0]); // save it from the full 16b
wire more_data_to_send =
!all_data_sent;
wire in_data_transfer_done;
rising_edge_detector detect_in_data_transfer_done (
.clk(clk),
.in(all_data_sent),
.out(in_data_transfer_done)
);
assign in_ep_data_done = (in_data_transfer_done && ctrl_xfr_state == DATA_IN) || send_zero_length_data_pkt;
assign in_ep_req = ctrl_xfr_state == DATA_IN && more_data_to_send;
assign in_ep_data_put = ctrl_xfr_state == DATA_IN && more_data_to_send && in_ep_data_free;
reg [6:0] rom_addr = 0;
reg save_dev_addr = 0;
reg [6:0] new_dev_addr = 0;
////////////////////////////////////////////////////////////////////////////////
// control transfer state machine
////////////////////////////////////////////////////////////////////////////////
always @* begin
setup_stage_end <= 0;
data_stage_end <= 0;
status_stage_end <= 0;
send_zero_length_data_pkt <= 0;
case (ctrl_xfr_state)
IDLE : begin
if (setup_pkt_start) begin
ctrl_xfr_state_next <= SETUP;
end else begin
ctrl_xfr_state_next <= IDLE;
end
end
SETUP : begin
if (pkt_end) begin
setup_stage_end <= 1;
if (in_data_stage) begin
ctrl_xfr_state_next <= DATA_IN;
end else if (out_data_stage) begin
ctrl_xfr_state_next <= DATA_OUT;
end else begin
ctrl_xfr_state_next <= STATUS_IN;
send_zero_length_data_pkt <= 1;
end
end else begin
ctrl_xfr_state_next <= SETUP;
end
end
DATA_IN : begin
if (in_ep_stall) begin
ctrl_xfr_state_next <= IDLE;
data_stage_end <= 1;
status_stage_end <= 1;
end else if (in_ep_acked && all_data_sent) begin
ctrl_xfr_state_next <= STATUS_OUT;
data_stage_end <= 1;
end else begin
ctrl_xfr_state_next <= DATA_IN;
end
end
DATA_OUT : begin
if (out_ep_acked) begin
ctrl_xfr_state_next <= STATUS_IN;
send_zero_length_data_pkt <= 1;
data_stage_end <= 1;
end else begin
ctrl_xfr_state_next <= DATA_OUT;
end
end
STATUS_IN : begin
if (in_ep_acked) begin
ctrl_xfr_state_next <= IDLE;
status_stage_end <= 1;
end else begin
ctrl_xfr_state_next <= STATUS_IN;
end
end
STATUS_OUT: begin
if (out_ep_acked) begin
ctrl_xfr_state_next <= IDLE;
status_stage_end <= 1;
end else begin
ctrl_xfr_state_next <= STATUS_OUT;
end
end
default begin
ctrl_xfr_state_next <= IDLE;
end
endcase
end
always @(posedge clk) begin
if (reset) begin
ctrl_xfr_state <= IDLE;
end else begin
ctrl_xfr_state <= ctrl_xfr_state_next;
end
end
always @(posedge clk) begin
in_ep_stall <= 0;
if (out_ep_setup && out_ep_data_valid) begin
raw_setup_data[setup_data_addr] <= out_ep_data;
setup_data_addr <= setup_data_addr + 1;
end
if (setup_stage_end) begin
case (bRequest)
'h06 : begin
// GET_DESCRIPTOR
case (wValue[15:8])
1 : begin
// DEVICE
rom_addr <= 'h00;
rom_length <= 'h12;
end
2 : begin
// CONFIGURATION
rom_addr <= 'h12;
rom_length <= 'h43;
end
6 : begin
// DEVICE_QUALIFIER
in_ep_stall <= 1;
rom_addr <= 'h00;
rom_length <= 'h00;
end
endcase
end
'h05 : begin
// SET_ADDRESS
rom_addr <= 'h00;
rom_length <= 'h00;
// we need to save the address after the status stage ends
// this is because the status stage token will still be using
// the old device address
save_dev_addr <= 1;
new_dev_addr <= wValue[6:0];
end
'h09 : begin
// SET_CONFIGURATION
rom_addr <= 'h00;
rom_length <= 'h00;
end
'h20 : begin
// SET_LINE_CODING
rom_addr <= 'h00;
rom_length <= 'h00;
end
'h21 : begin
// GET_LINE_CODING
rom_addr <= 'h55;
rom_length <= 'h07;
end
'h22 : begin
// SET_CONTROL_LINE_STATE
rom_addr <= 'h00;
rom_length <= 'h00;
end
'h23 : begin
// SEND_BREAK
rom_addr <= 'h00;
rom_length <= 'h00;
end
default begin
rom_addr <= 'h00;
rom_length <= 'h00;
end
endcase
end
if (ctrl_xfr_state == DATA_IN && more_data_to_send && in_ep_grant && in_ep_data_free) begin
rom_addr <= rom_addr + 1;
bytes_sent <= bytes_sent + 1;
end
if (status_stage_end) begin
setup_data_addr <= 0;
bytes_sent <= 0;
rom_addr <= 0;
rom_length <= 0;
if (save_dev_addr) begin
save_dev_addr <= 0;
dev_addr_i <= new_dev_addr;
end
end
if (reset) begin
dev_addr_i <= 0;
setup_data_addr <= 0;
save_dev_addr <= 0;
end
end
`define CDC_ACM_ENDPOINT 2
`define CDC_RX_ENDPOINT 1
`define CDC_TX_ENDPOINT 1
always @* begin
case (rom_addr)
// device descriptor
'h000 : in_ep_data <= 18; // bLength
'h001 : in_ep_data <= 1; // bDescriptorType
'h002 : in_ep_data <= 'h00; // bcdUSB[0]
'h003 : in_ep_data <= 'h02; // bcdUSB[1]
'h004 : in_ep_data <= 'h02; // bDeviceClass (Communications Device Class)
'h005 : in_ep_data <= 'h00; // bDeviceSubClass (Abstract Control Model)
'h006 : in_ep_data <= 'h00; // bDeviceProtocol (No class specific protocol required)
'h007 : in_ep_data <= MAX_IN_PACKET_SIZE; // bMaxPacketSize0
'h008 : in_ep_data <= 'h50; // idVendor[0] http://wiki.openmoko.org/wiki/USB_Product_IDs
'h009 : in_ep_data <= 'h1d; // idVendor[1]
'h00A : in_ep_data <= 'h30; // idProduct[0]
'h00B : in_ep_data <= 'h61; // idProduct[1]
'h00C : in_ep_data <= 0; // bcdDevice[0]
'h00D : in_ep_data <= 0; // bcdDevice[1]
'h00E : in_ep_data <= 0; // iManufacturer
'h00F : in_ep_data <= 0; // iProduct
'h010 : in_ep_data <= 0; // iSerialNumber
'h011 : in_ep_data <= 1; // bNumConfigurations
// configuration descriptor
'h012 : in_ep_data <= 9; // bLength
'h013 : in_ep_data <= 2; // bDescriptorType
'h014 : in_ep_data <= (9+9+5+5+4+5+7+9+7+7); // wTotalLength[0]
'h015 : in_ep_data <= 0; // wTotalLength[1]
'h016 : in_ep_data <= 2; // bNumInterfaces
'h017 : in_ep_data <= 1; // bConfigurationValue
'h018 : in_ep_data <= 0; // iConfiguration
'h019 : in_ep_data <= 'hC0; // bmAttributes
'h01A : in_ep_data <= 50; // bMaxPower
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
'h01B : in_ep_data <= 9; // bLength
'h01C : in_ep_data <= 4; // bDescriptorType
'h01D : in_ep_data <= 0; // bInterfaceNumber
'h01E : in_ep_data <= 0; // bAlternateSetting
'h01F : in_ep_data <= 1; // bNumEndpoints
'h020 : in_ep_data <= 2; // bInterfaceClass (Communications Device Class)
'h021 : in_ep_data <= 2; // bInterfaceSubClass (Abstract Control Model)
'h022 : in_ep_data <= 0; // bInterfaceProtocol (0 = ?, 1 = AT Commands: V.250 etc)
'h023 : in_ep_data <= 0; // iInterface
// CDC Header Functional Descriptor, CDC Spec 5.2.3.1, Table 26
'h024 : in_ep_data <= 5; // bFunctionLength
'h025 : in_ep_data <= 'h24; // bDescriptorType
'h026 : in_ep_data <= 'h00; // bDescriptorSubtype
'h027 : in_ep_data <= 'h10;
'h028 : in_ep_data <= 'h01; // bcdCDC
// Call Management Functional Descriptor, CDC Spec 5.2.3.2, Table 27
'h029 : in_ep_data <= 5; // bFunctionLength
'h02A : in_ep_data <= 'h24; // bDescriptorType
'h02B : in_ep_data <= 'h01; // bDescriptorSubtype
'h02C : in_ep_data <= 'h00; // bmCapabilities
'h02D : in_ep_data <= 1; // bDataInterface
// Abstract Control Management Functional Descriptor, CDC Spec 5.2.3.3, Table 28
'h02E : in_ep_data <= 4; // bFunctionLength
'h02F : in_ep_data <= 'h24; // bDescriptorType
'h030 : in_ep_data <= 'h02; // bDescriptorSubtype
'h031 : in_ep_data <= 'h06; // bmCapabilities
// Union Functional Descriptor, CDC Spec 5.2.3.8, Table 33
'h032 : in_ep_data <= 5; // bFunctionLength
'h033 : in_ep_data <= 'h24; // bDescriptorType
'h034 : in_ep_data <= 'h06; // bDescriptorSubtype
'h035 : in_ep_data <= 0; // bMasterInterface
'h036 : in_ep_data <= 1; // bSlaveInterface0
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
'h037 : in_ep_data <= 7; // bLength
'h038 : in_ep_data <= 5; // bDescriptorType
'h039 : in_ep_data <= `CDC_ACM_ENDPOINT | 'h80; // bEndpointAddress
'h03A : in_ep_data <= 'h03; // bmAttributes (0x03=intr)
'h03B : in_ep_data <= 8; // wMaxPacketSize[0]
'h03C : in_ep_data <= 0; // wMaxPacketSize[1]
'h03D : in_ep_data <= 64; // bInterval
// interface descriptor, USB spec 9.6.5, page 267-269, Table 9-12
'h03E : in_ep_data <= 9; // bLength
'h03F : in_ep_data <= 4; // bDescriptorType
'h040 : in_ep_data <= 1; // bInterfaceNumber
'h041 : in_ep_data <= 0; // bAlternateSetting
'h042 : in_ep_data <= 2; // bNumEndpoints
'h043 : in_ep_data <= 'h0A; // bInterfaceClass
'h044 : in_ep_data <= 'h00; // bInterfaceSubClass
'h045 : in_ep_data <= 'h00; // bInterfaceProtocol
'h046 : in_ep_data <= 0; // iInterface
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
'h047 : in_ep_data <= 7; // bLength
'h048 : in_ep_data <= 5; // bDescriptorType
'h049 : in_ep_data <= `CDC_RX_ENDPOINT; // bEndpointAddress
'h04A : in_ep_data <= 'h02; // bmAttributes (0x02=bulk)
'h04B : in_ep_data <= MAX_IN_PACKET_SIZE; // wMaxPacketSize[0]
'h04C : in_ep_data <= 0; // wMaxPacketSize[1]
'h04D : in_ep_data <= 0; // bInterval
// endpoint descriptor, USB spec 9.6.6, page 269-271, Table 9-13
'h04E : in_ep_data <= 7; // bLength
'h04F : in_ep_data <= 5; // bDescriptorType
'h050 : in_ep_data <= `CDC_TX_ENDPOINT | 'h80; // bEndpointAddress
'h051 : in_ep_data <= 'h02; // bmAttributes (0x02=bulk)
'h052 : in_ep_data <= MAX_OUT_PACKET_SIZE; // wMaxPacketSize[0]
'h053 : in_ep_data <= 0; // wMaxPacketSize[1]
'h054 : in_ep_data <= 0; // bInterval
// LINE_CODING
'h055 : in_ep_data <= 'h80; // dwDTERate[0]
'h056 : in_ep_data <= 'h25; // dwDTERate[1]
'h057 : in_ep_data <= 'h00; // dwDTERate[2]
'h058 : in_ep_data <= 'h00; // dwDTERate[3]
'h059 : in_ep_data <= 1; // bCharFormat (1 stop bit)
'h05A : in_ep_data <= 0; // bParityType (None)
'h05B : in_ep_data <= 8; // bDataBits (8 bits)
default begin
in_ep_data <= 0;
end
endcase
end
endmodule

View File

@ -0,0 +1,331 @@
/*
usb_uart
Luke Valenti's USB module, as adapted by Lawrie Griffiths.
This module was originally tinyfpga_bootloader.v in Luke's code.
It creates the endpoint modules and the protocol engine to run things. Whereas
the original creates a usb_spi_bridge, this one creates a usb_uart_bridge.
Instanciation template
----------------------------------------------------
usb_uart uart (
.clk_48mhz (clk_48mhz),
.reset (reset),
// pins - these must be connected properly to the outside world. See below.
.usb_p_tx(usb_p_tx),
.usb_n_tx(usb_n_tx),
.usb_p_rx(usb_p_rx),
.usb_n_rx(usb_n_rx),
.usb_tx_en(usb_tx_en),
// uart pipeline in
.uart_in_data( uart_in_data ),
.uart_in_valid( uart_in_valid ),
.uart_in_ready( uart_in_ready ),
// uart pipeline out
.uart_out_data( uart_out_data ),
.uart_out_valid( uart_out_valid ),
.uart_out_ready( uart_out_ready ),
.debug( debug )
);
----------------------------------------------------
Then, the actual physical pins need some special handling. Get some
help from the device.
----------------------------------------------------
assign usb_p_rx = usb_tx_en ? 1'b1 : usb_p_in;
assign usb_n_rx = usb_tx_en ? 1'b0 : usb_n_in;
SB_IO #(
.PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
.PULLUP(1'b 0)
)
iobuf_usbp
(
.PACKAGE_PIN(pin_usbp),
.OUTPUT_ENABLE(usb_tx_en),
.D_OUT_0(usb_p_tx),
.D_IN_0(usb_p_in)
);
SB_IO #(
.PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
.PULLUP(1'b 0)
)
iobuf_usbn
(
.PACKAGE_PIN(pin_usbn),
.OUTPUT_ENABLE(usb_tx_en),
.D_OUT_0(usb_n_tx),
.D_IN_0(usb_n_in)
);
----------------------------------------------------
It should be noted that there are no other invocations of usb stuff other than
usb_uart.v. Since it's the top, I'm going to put some doc in here.
General note: USB communications happen over endpoints. The OUT endpoints are out
with respect to the HOST, and IN endpoints are in with respect to the HOST.
Files:
usb_uart.v - top level module creates the end points clusters, (usb_serial_ctrl_ep,
usb_uart_bridge_ep) and the main protocol engine (usb_fs_pe - passing
in the in (3) and out (2) count, along with the actual usb signal
lines). Also, all the end point signals are connected to the protocol
engine in its invocation. The serial end point cluster and the control
end point cluster have two endpoints each - one in and one out.
usb_serial_ctrl_ep - serial control logic. Two end point interfaces are (one in one
out) passed in with their various signal lines. Contains all the
USB setup logic. Returns the configuration etc. Vendor 50 1D
Product 30 61. Two interfaces. Descriptors. Obviously the main
configuration file.
usb_uart_bridge.v - where the data action is for us. Is passed in the out endpoint
and the in endpoint, and also the (strange) UART interface signals
(uart_we, uart_re, uart_di, uart_do, uart_wait). So this translates
between endpoint talk and UART talk.
usb_fs_pe.v - full speed protocol engine - instanciates all the endpoints, making
arrays of in and out end point signals. Also is passed in are all
the actual interfaces to the end points.
Creates the in and out arbitors (usb_fs_in_arb, usb_fs_out_arb)
Creates the in protocol engine (usb_fs_in_pe), and the out protocol
engine (usb_fs_out_pe)
Creates the receiver and transmitter (usb_fs_rx, usb_fs_tx)
Creates the tx mux and the rx mux which permit the different engines
to talk.
usb_fs_in_pe.v - in protocol engine
usb_fs_out_pe.v - out protocol engine
usb_fs_rx.v - Actual rx logic
usb_fs_tx.v - Actual tx logic
edge_detect.v - rising and falling edge detectors
serial.v - width adapter (x widths to y widths)
*/
module usb_uart (
input clk_48mhz,
input reset,
// USB lines. Split into input vs. output and oe control signal to maintain
// highest level of compatibility with synthesis tools.
output usb_p_tx,
output usb_n_tx,
input usb_p_rx,
input usb_n_rx,
output usb_tx_en,
// uart pipeline in (into the module, out of the device, into the host)
input [7:0] uart_in_data,
input uart_in_valid,
output uart_in_ready,
// uart pipeline out (out of the host, into the device, out of the module)
output [7:0] uart_out_data,
output uart_out_valid,
input uart_out_ready,
output [11:0] debug
);
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////
//////// usb engine
////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
wire [6:0] dev_addr;
wire [7:0] out_ep_data;
wire ctrl_out_ep_req;
wire ctrl_out_ep_grant;
wire ctrl_out_ep_data_avail;
wire ctrl_out_ep_setup;
wire ctrl_out_ep_data_get;
wire ctrl_out_ep_stall;
wire ctrl_out_ep_acked;
wire ctrl_in_ep_req;
wire ctrl_in_ep_grant;
wire ctrl_in_ep_data_free;
wire ctrl_in_ep_data_put;
wire [7:0] ctrl_in_ep_data;
wire ctrl_in_ep_data_done;
wire ctrl_in_ep_stall;
wire ctrl_in_ep_acked;
wire serial_out_ep_req;
wire serial_out_ep_grant;
wire serial_out_ep_data_avail;
wire serial_out_ep_setup;
wire serial_out_ep_data_get;
wire serial_out_ep_stall;
wire serial_out_ep_acked;
wire serial_in_ep_req;
wire serial_in_ep_grant;
wire serial_in_ep_data_free;
wire serial_in_ep_data_put;
wire [7:0] serial_in_ep_data;
wire serial_in_ep_data_done;
wire serial_in_ep_stall;
wire serial_in_ep_acked;
wire sof_valid;
wire [10:0] frame_index;
reg [31:0] host_presence_timer = 0;
reg host_presence_timeout = 0;
usb_serial_ctrl_ep ctrl_ep_inst (
.clk(clk_48mhz),
.reset(reset),
.dev_addr(dev_addr),
// out endpoint interface
.out_ep_req(ctrl_out_ep_req),
.out_ep_grant(ctrl_out_ep_grant),
.out_ep_data_avail(ctrl_out_ep_data_avail),
.out_ep_setup(ctrl_out_ep_setup),
.out_ep_data_get(ctrl_out_ep_data_get),
.out_ep_data(out_ep_data),
.out_ep_stall(ctrl_out_ep_stall),
.out_ep_acked(ctrl_out_ep_acked),
// in endpoint interface
.in_ep_req(ctrl_in_ep_req),
.in_ep_grant(ctrl_in_ep_grant),
.in_ep_data_free(ctrl_in_ep_data_free),
.in_ep_data_put(ctrl_in_ep_data_put),
.in_ep_data(ctrl_in_ep_data),
.in_ep_data_done(ctrl_in_ep_data_done),
.in_ep_stall(ctrl_in_ep_stall),
.in_ep_acked(ctrl_in_ep_acked)
);
usb_uart_bridge_ep usb_uart_bridge_ep_inst (
.clk(clk_48mhz),
.reset(reset),
// out endpoint interface
.out_ep_req(serial_out_ep_req),
.out_ep_grant(serial_out_ep_grant),
.out_ep_data_avail(serial_out_ep_data_avail),
.out_ep_setup(serial_out_ep_setup),
.out_ep_data_get(serial_out_ep_data_get),
.out_ep_data(out_ep_data),
.out_ep_stall(serial_out_ep_stall),
.out_ep_acked(serial_out_ep_acked),
// in endpoint interface
.in_ep_req(serial_in_ep_req),
.in_ep_grant(serial_in_ep_grant),
.in_ep_data_free(serial_in_ep_data_free),
.in_ep_data_put(serial_in_ep_data_put),
.in_ep_data(serial_in_ep_data),
.in_ep_data_done(serial_in_ep_data_done),
.in_ep_stall(serial_in_ep_stall),
.in_ep_acked(serial_in_ep_acked),
// uart pipeline in
.uart_in_data( uart_in_data ),
.uart_in_valid( uart_in_valid ),
.uart_in_ready( uart_in_ready ),
// uart pipeline out
.uart_out_data( uart_out_data ),
.uart_out_valid( uart_out_valid ),
.uart_out_ready( uart_out_ready ),
.debug(debug[3:0])
);
wire nak_in_ep_grant;
wire nak_in_ep_data_free;
wire nak_in_ep_acked;
usb_fs_pe #(
.NUM_OUT_EPS(5'd2),
.NUM_IN_EPS(5'd3)
) usb_fs_pe_inst (
.clk(clk_48mhz),
.reset(reset),
.usb_p_tx(usb_p_tx),
.usb_n_tx(usb_n_tx),
.usb_p_rx(usb_p_rx),
.usb_n_rx(usb_n_rx),
.usb_tx_en(usb_tx_en),
.dev_addr(dev_addr),
// out endpoint interfaces
.out_ep_req({serial_out_ep_req, ctrl_out_ep_req}),
.out_ep_grant({serial_out_ep_grant, ctrl_out_ep_grant}),
.out_ep_data_avail({serial_out_ep_data_avail, ctrl_out_ep_data_avail}),
.out_ep_setup({serial_out_ep_setup, ctrl_out_ep_setup}),
.out_ep_data_get({serial_out_ep_data_get, ctrl_out_ep_data_get}),
.out_ep_data(out_ep_data),
.out_ep_stall({serial_out_ep_stall, ctrl_out_ep_stall}),
.out_ep_acked({serial_out_ep_acked, ctrl_out_ep_acked}),
// in endpoint interfaces
.in_ep_req({1'b0, serial_in_ep_req, ctrl_in_ep_req}),
.in_ep_grant({nak_in_ep_grant, serial_in_ep_grant, ctrl_in_ep_grant}),
.in_ep_data_free({nak_in_ep_data_free, serial_in_ep_data_free, ctrl_in_ep_data_free}),
.in_ep_data_put({1'b0, serial_in_ep_data_put, ctrl_in_ep_data_put}),
.in_ep_data({8'b0, serial_in_ep_data[7:0], ctrl_in_ep_data[7:0]}),
.in_ep_data_done({1'b0, serial_in_ep_data_done, ctrl_in_ep_data_done}),
.in_ep_stall({1'b0, serial_in_ep_stall, ctrl_in_ep_stall}),
.in_ep_acked({nak_in_ep_acked, serial_in_ep_acked, ctrl_in_ep_acked}),
// sof interface
.sof_valid(sof_valid),
.frame_index(frame_index),
// Debug
.debug(debug[11:4])
);
////////////////////////////////////////////////////////////////////////////////
// host presence detection
////////////////////////////////////////////////////////////////////////////////
always @(posedge clk_48mhz) begin
if (sof_valid) begin
host_presence_timer <= 0;
host_presence_timeout <= 0;
end else begin
host_presence_timer <= host_presence_timer + 1;
end
if (host_presence_timer > 48000000) begin
host_presence_timeout <= 1;
end
end
endmodule

View File

@ -0,0 +1,315 @@
/*
usb_uart_bridge_ep
This is the endpoint to uart translator. Two things to highlight: the directions
IN and OUT are set with respect to the HOST, and also in USB, the HOST runs all
endpoint interactions.
The out endpoint interface. This is the out w.r.t. the host, hence in to
us. There are request grant, data available and data get signals, stall and
acked signals. And the data itself.
The in endpoint interface. This is the in w.r.t. the host, hence out to us.
This interface also has a req and grant. There's a put signal and a free
signal. Stall and acked. And the data.
To get data in and out there are two pipeline interfaces - one in and one out.
OUT (or into this device)
Roughly, the USB innards signal that a packet has arrived by raising out_ep_data_available.
The data multiplexor has to be switched, so the interface is requested. This is
combinatorial logic so clever req and grant stuff can happen in the same line.
assign out_ep_req = ( out_ep_req_reg || out_ep_data_avail );
With the interface granted, the data is free to get. Every cycle that the out_ep_data_get
signal is high, the input address is advanced. Inside the USB innards, when the
read address pointer equals the address of the write pointer (when all the data is
retreived, the out_ep_data_available flag is lowered and we withdraw our request for
the interface and go back to idle.
Interestingly, if you stop taking data... you lose your buffer. So don't.
IN (or out of this device back to the host)
The IN EP works by providing a buffer and waiting for the local logic to fill it,
or to say that it's done. When this happens the interface switches to a new state where
it waits for a token from the host. When it get the token, it sends the data. When that
is acknoledged, the buffer is released and returned ready to be filled again.
in_ep_data_free signals that there's a buffer waiting. And that signal goes low when
the buffer is full and not available.
In the case where a buffer is not full - just sitting around with some data in it, a decision
has to be made at some point just to send. This is handled by a timeout mechanism, which
asserts in_ep_data_done and lets the buffer be sent.
In the case where the buffer fills to the top, in_ep_data_free goes low by itself.
*/
module usb_uart_bridge_ep (
input clk,
input reset,
////////////////////
// out endpoint interface
////////////////////
output out_ep_req, // request the data interface for the out endpoint
input out_ep_grant, // data interface granted
input out_ep_data_avail, // flagging data available to get from the host - stays up until the cycle upon which it is empty
input out_ep_setup, // [setup packet sent? - not used here]
output out_ep_data_get, // request to get the data
input [7:0] out_ep_data, // data from the host
output out_ep_stall, // an output enabling the device to stop inputs (not used)
input out_ep_acked, // indicating that the outgoing data was acked
////////////////////
// in endpoint interface
////////////////////
output in_ep_req, // request the data interface for the in endpoint
input in_ep_grant, // data interface granted
input in_ep_data_free, // end point is ready for data - (specifically there is a buffer and it has space)
// after going low it takes a while to get another back, but it does this automatically
output in_ep_data_put, // forces end point to read our data
output [7:0] in_ep_data, // data back to the host
output in_ep_data_done, // signalling that we're done sending data
output in_ep_stall, // an output enabling the device to stop outputs (not used)
input in_ep_acked, // indicating that the outgoing data was acked
// uart pipeline in
input [7:0] uart_in_data,
input uart_in_valid,
output uart_in_ready,
// uart pipeline out
output [7:0] uart_out_data,
output uart_out_valid,
input uart_out_ready,
output [3:0] debug
);
// Timeout counter width.
localparam TimeoutWidth = 3;
// We don't stall
assign out_ep_stall = 1'b0;
assign in_ep_stall = 1'b0;
// Registers for the out pipeline (out of the module)
reg [7:0] uart_out_data_reg;
reg [7:0] uart_out_data_overflow_reg;
reg uart_out_valid_reg;
// registers for the out end point (out of the host)
reg out_ep_req_reg;
reg out_ep_data_get_reg;
// out pipeline / out endpoint state machine state (6 states -> 3 bits)
reg [1:0] pipeline_out_state;
localparam PipelineOutState_Idle = 0;
localparam PipelineOutState_WaitData = 1;
localparam PipelineOutState_PushData = 2;
localparam PipelineOutState_WaitPipeline = 3;
// connect the pipeline registers to the outgoing ports
assign uart_out_data = uart_out_data_reg;
assign uart_out_valid = uart_out_valid_reg;
// automatically make the bus request from the data_available
// latch it with out_ep_req_reg
assign out_ep_req = ( out_ep_req_reg || out_ep_data_avail );
wire out_granted_data_available;
assign out_granted_data_available = out_ep_req && out_ep_grant;
assign out_ep_data_get = ( uart_out_ready || ~uart_out_valid_reg ) && out_ep_data_get_reg;
reg [7:0] out_stall_data;
reg out_stall_valid;
// do HOST OUT, DEVICE IN, PIPELINE OUT (!)
always @(posedge clk) begin
if ( reset ) begin
pipeline_out_state <= PipelineOutState_Idle;
uart_out_data_reg <= 0;
uart_out_valid_reg <= 0;
out_ep_req_reg <= 0;
out_ep_data_get_reg <= 0;
out_stall_data <= 0;
out_stall_valid <= 0;
end else begin
case( pipeline_out_state )
PipelineOutState_Idle: begin
// Waiting for the data_available signal indicating that a data packet has arrived
if ( out_granted_data_available ) begin
// indicate that we want the data
out_ep_data_get_reg <= 1;
// although the bus has been requested automatically, we latch the request so we control it
out_ep_req_reg <= 1;
// now wait for the data to set up
pipeline_out_state <= PipelineOutState_WaitData;
uart_out_valid_reg <= 0;
out_stall_data <= 0;
out_stall_valid <= 0;
end
end
PipelineOutState_WaitData: begin
// it takes one cycle for the juices to start flowing
// we got here when we were starting or if the outgoing pipe stalled
if ( uart_out_ready || ~uart_out_valid_reg ) begin
//if we were stalled, we can send the byte we caught while we were stalled
// the actual stalled byte now having been VALID & READY'ed
if ( out_stall_valid ) begin
uart_out_data_reg <= out_stall_data;
uart_out_valid_reg <= 1;
out_stall_data <= 0;
out_stall_valid <= 0;
if ( out_ep_data_avail )
pipeline_out_state <= PipelineOutState_PushData;
else begin
pipeline_out_state <= PipelineOutState_WaitPipeline;
end
end else begin
pipeline_out_state <= PipelineOutState_PushData;
end
end
end
PipelineOutState_PushData: begin
// can grab a character if either the out was accepted or the out reg is empty
if ( uart_out_ready || ~uart_out_valid_reg ) begin
// now we really have got some data and a place to shove it
uart_out_data_reg <= out_ep_data;
uart_out_valid_reg <= 1;
if ( ~out_ep_data_avail ) begin
// stop streaming, now just going to wait until the character is accepted
out_ep_data_get_reg <= 0;
pipeline_out_state <= PipelineOutState_WaitPipeline;
end
end else begin
// We're in push data so there is a character, but our pipeline has stalled
// need to save the character and wait.
out_stall_data <= out_ep_data;
out_stall_valid <= 1;
pipeline_out_state <= PipelineOutState_WaitData;
if ( ~out_ep_data_avail )
out_ep_data_get_reg <= 0;
end
end
PipelineOutState_WaitPipeline: begin
// unhand the bus (don't want to block potential incoming) - be careful, this works instantly!
out_ep_req_reg <= 0;
if ( uart_out_ready ) begin
uart_out_valid_reg <= 0;
uart_out_data_reg <= 0;
pipeline_out_state <= PipelineOutState_Idle;
end
end
endcase
end
end
// in endpoint control registers
reg in_ep_req_reg;
reg in_ep_data_done_reg;
// in pipeline / in endpoint state machine state (4 states -> 2 bits)
reg [1:0] pipeline_in_state;
localparam PipelineInState_Idle = 0;
localparam PipelineInState_WaitData = 1;
localparam PipelineInState_CycleData = 2;
localparam PipelineInState_WaitEP = 3;
// connect the pipeline register to the outgoing port
assign uart_in_ready = ( pipeline_in_state == PipelineInState_CycleData ) && in_ep_data_free;
// uart_in_valid and a buffer being ready is the request for the bus.
// It is granted automatically if available, and latched on by the SM.
// Note once requested, uart_in_valid may go on and off as data is available.
// When requested, connect the end point registers to the outgoing ports
assign in_ep_req = ( uart_in_valid && in_ep_data_free) || in_ep_req_reg;
// Confirmation that the bus was granted
wire in_granted_in_valid = in_ep_grant && uart_in_valid;
// Here are the things we use to get data sent
// ... put this word
assign in_ep_data_put = ( pipeline_in_state == PipelineInState_CycleData ) && uart_in_valid && in_ep_data_free;
// ... we're done putting - send the buffer
assign in_ep_data_done = in_ep_data_done_reg;
// ... the actual data, direct from the pipeline to the usb in buffer
assign in_ep_data = uart_in_data;
// If we have a half filled buffer, send it after a while by using a timer
// 4 bits of counter, we'll just count up until bit 3 is high... 8 clock cycles seems more than enough to wait
// to send the packet
reg [TimeoutWidth:0] in_ep_timeout;
// do PIPELINE IN, FPGA/Device OUT, Host IN
always @(posedge clk) begin
if ( reset ) begin
pipeline_in_state <= PipelineInState_Idle;
in_ep_req_reg <= 0;
in_ep_data_done_reg <= 0;
end else begin
case( pipeline_in_state )
PipelineInState_Idle: begin
in_ep_data_done_reg <= 0;
if ( in_granted_in_valid && in_ep_data_free ) begin
// got the bus, there is free space, now do the data
// confirm request bus - this will hold the request up until we're done with it
in_ep_req_reg <= 1;
pipeline_in_state <= PipelineInState_CycleData;
end
end
PipelineInState_CycleData: begin
if (uart_in_valid ) begin
if ( ~in_ep_data_free ) begin
// back to idle
pipeline_in_state <= PipelineInState_Idle;
// release the bus
in_ep_req_reg <= 0;
end
end else begin
// No valid character. Let's just pause for a second to see if any more are forthcoming.
// clear the timeout counter
in_ep_timeout <= 0;
pipeline_in_state <= PipelineInState_WaitData;
end
end
PipelineInState_WaitData: begin
in_ep_timeout <= in_ep_timeout + 1;
if ( uart_in_valid ) begin
pipeline_in_state <= PipelineInState_CycleData;
end else begin
// check for a timeout
if ( in_ep_timeout[ TimeoutWidth ] ) begin
in_ep_data_done_reg <= 1;
pipeline_in_state <= PipelineInState_WaitEP;
end
end
end
PipelineInState_WaitEP: begin
// maybe done is ignored if putting?
in_ep_data_done_reg <= 0;
// back to idle
pipeline_in_state <= PipelineInState_Idle;
// release the bus
in_ep_req_reg <= 0;
end
endcase
end
end
assign debug = { in_ep_data_free, in_ep_data_done, pipeline_in_state[ 1 ], pipeline_in_state[ 0 ] };
endmodule

View File

@ -0,0 +1,332 @@
/*
usb_uart
Luke Valenti's USB module, as adapted by Lawrie Griffiths.
This module was originally tinyfpga_bootloader.v in Luke's code.
It creates the endpoint modules and the protocol engine to run things. Whereas
the original creates a usb_spi_bridge, this one creates a usb_uart_bridge.
Instanciation template with separate pipe signals
----------------------------------------------------
usb_uart_core_np uart (
.clk_48mhz (clk_48mhz),
.reset (reset),
// pins - these must be connected properly to the outside world. See below.
.usb_p_tx(usb_p_tx),
.usb_n_tx(usb_n_tx),
.usb_p_rx(usb_p_rx),
.usb_n_rx(usb_n_rx),
.usb_tx_en(usb_tx_en),
// uart pipeline in
.uart_in_data( uart_in_data ),
.uart_in_valid( uart_in_valid ),
.uart_in_ready( uart_in_ready ),
// uart pipeline out
.uart_out_data( uart_out_data ),
.uart_out_valid( uart_out_valid ),
.uart_out_ready( uart_out_ready ),
.debug( debug )
);
----------------------------------------------------
Then, the actual physical pins need some special handling. Get some
help from the device.
----------------------------------------------------
assign usb_p_rx = usb_tx_en ? 1'b1 : usb_p_in;
assign usb_n_rx = usb_tx_en ? 1'b0 : usb_n_in;
SB_IO #(
.PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
.PULLUP(1'b 0)
)
iobuf_usbp
(
.PACKAGE_PIN(pin_usbp),
.OUTPUT_ENABLE(usb_tx_en),
.D_OUT_0(usb_p_tx),
.D_IN_0(usb_p_in)
);
SB_IO #(
.PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
.PULLUP(1'b 0)
)
iobuf_usbn
(
.PACKAGE_PIN(pin_usbn),
.OUTPUT_ENABLE(usb_tx_en),
.D_OUT_0(usb_n_tx),
.D_IN_0(usb_n_in)
);
----------------------------------------------------
It should be noted that there are no other invocations of usb stuff other than
usb_uart.v. Since it's the top, I'm going to put some doc in here.
General note: USB communications happen over endpoints. The OUT endpoints are out
with respect to the HOST, and IN endpoints are in with respect to the HOST.
Files:
usb_uart_core.v - top level module creates the end points clusters, (usb_serial_ctrl_ep,
usb_uart_bridge_ep) and the main protocol engine (usb_fs_pe - passing
in the in (3) and out (2) count, along with the actual usb signal
lines). Also, all the end point signals are connected to the protocol
engine in its invocation. The serial end point cluster and the control
end point cluster have two endpoints each - one in and one out.
usb_serial_ctrl_ep - serial control logic. Two end point interfaces are (one in one
out) passed in with their various signal lines. Contains all the
USB setup logic. Returns the configuration etc. Vendor 50 1D
Product 30 61. Two interfaces. Descriptors. Obviously the main
configuration file.
usb_uart_bridge.v - where the data action is for us. Is passed in the out endpoint
and the in endpoint, and also the (strange) UART interface signals
(uart_we, uart_re, uart_di, uart_do, uart_wait). So this translates
between endpoint talk and UART talk.
usb_fs_pe.v - full speed protocol engine - instanciates all the endpoints, making
arrays of in and out end point signals. Also is passed in are all
the actual interfaces to the end points.
Creates the in and out arbitors (usb_fs_in_arb, usb_fs_out_arb)
Creates the in protocol engine (usb_fs_in_pe), and the out protocol
engine (usb_fs_out_pe)
Creates the receiver and transmitter (usb_fs_rx, usb_fs_tx)
Creates the tx mux and the rx mux which permit the different engines
to talk.
usb_fs_in_pe.v - in protocol engine
usb_fs_out_pe.v - out protocol engine
usb_fs_rx.v - Actual rx logic
usb_fs_tx.v - Actual tx logic
edge_detect.v - rising and falling edge detectors
serial.v - width adapter (x widths to y widths)
*/
module usb_uart_core(
input clk_48mhz,
input reset,
// USB lines. Split into input vs. output and oe control signal to maintain
// highest level of compatibility with synthesis tools.
output usb_p_tx,
output usb_n_tx,
input usb_p_rx,
input usb_n_rx,
output usb_tx_en,
// uart pipeline in (into the module, out of the device, into the host)
input [7:0] uart_in_data,
input uart_in_valid,
output uart_in_ready,
// uart pipeline out (out of the host, into the device, out of the module)
output [7:0] uart_out_data,
output uart_out_valid,
input uart_out_ready,
output [11:0] debug
);
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////
//////// usb engine
////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
wire [6:0] dev_addr;
wire [7:0] out_ep_data;
wire ctrl_out_ep_req;
wire ctrl_out_ep_grant;
wire ctrl_out_ep_data_avail;
wire ctrl_out_ep_setup;
wire ctrl_out_ep_data_get;
wire ctrl_out_ep_stall;
wire ctrl_out_ep_acked;
wire ctrl_in_ep_req;
wire ctrl_in_ep_grant;
wire ctrl_in_ep_data_free;
wire ctrl_in_ep_data_put;
wire [7:0] ctrl_in_ep_data;
wire ctrl_in_ep_data_done;
wire ctrl_in_ep_stall;
wire ctrl_in_ep_acked;
wire serial_out_ep_req;
wire serial_out_ep_grant;
wire serial_out_ep_data_avail;
wire serial_out_ep_setup;
wire serial_out_ep_data_get;
wire serial_out_ep_stall;
wire serial_out_ep_acked;
wire serial_in_ep_req;
wire serial_in_ep_grant;
wire serial_in_ep_data_free;
wire serial_in_ep_data_put;
wire [7:0] serial_in_ep_data;
wire serial_in_ep_data_done;
wire serial_in_ep_stall;
wire serial_in_ep_acked;
wire sof_valid;
wire [10:0] frame_index;
reg [31:0] host_presence_timer = 0;
reg host_presence_timeout = 0;
usb_serial_ctrl_ep ctrl_ep_inst (
.clk(clk_48mhz),
.reset(reset),
.dev_addr(dev_addr),
// out endpoint interface
.out_ep_req(ctrl_out_ep_req),
.out_ep_grant(ctrl_out_ep_grant),
.out_ep_data_avail(ctrl_out_ep_data_avail),
.out_ep_setup(ctrl_out_ep_setup),
.out_ep_data_get(ctrl_out_ep_data_get),
.out_ep_data(out_ep_data),
.out_ep_stall(ctrl_out_ep_stall),
.out_ep_acked(ctrl_out_ep_acked),
// in endpoint interface
.in_ep_req(ctrl_in_ep_req),
.in_ep_grant(ctrl_in_ep_grant),
.in_ep_data_free(ctrl_in_ep_data_free),
.in_ep_data_put(ctrl_in_ep_data_put),
.in_ep_data(ctrl_in_ep_data),
.in_ep_data_done(ctrl_in_ep_data_done),
.in_ep_stall(ctrl_in_ep_stall),
.in_ep_acked(ctrl_in_ep_acked)
);
usb_uart_bridge_ep usb_uart_bridge_ep_inst (
.clk(clk_48mhz),
.reset(reset),
// out endpoint interface
.out_ep_req(serial_out_ep_req),
.out_ep_grant(serial_out_ep_grant),
.out_ep_data_avail(serial_out_ep_data_avail),
.out_ep_setup(serial_out_ep_setup),
.out_ep_data_get(serial_out_ep_data_get),
.out_ep_data(out_ep_data),
.out_ep_stall(serial_out_ep_stall),
.out_ep_acked(serial_out_ep_acked),
// in endpoint interface
.in_ep_req(serial_in_ep_req),
.in_ep_grant(serial_in_ep_grant),
.in_ep_data_free(serial_in_ep_data_free),
.in_ep_data_put(serial_in_ep_data_put),
.in_ep_data(serial_in_ep_data),
.in_ep_data_done(serial_in_ep_data_done),
.in_ep_stall(serial_in_ep_stall),
.in_ep_acked(serial_in_ep_acked),
// uart pipeline in
.uart_in_data( uart_in_data ),
.uart_in_valid( uart_in_valid ),
.uart_in_ready( uart_in_ready ),
// uart pipeline out
.uart_out_data( uart_out_data ),
.uart_out_valid( uart_out_valid ),
.uart_out_ready( uart_out_ready ),
.debug(debug[3:0])
);
wire nak_in_ep_grant;
wire nak_in_ep_data_free;
wire nak_in_ep_acked;
usb_fs_pe #(
.NUM_OUT_EPS(5'd2),
.NUM_IN_EPS(5'd3)
) usb_fs_pe_inst (
.clk(clk_48mhz),
.reset(reset),
.usb_p_tx(usb_p_tx),
.usb_n_tx(usb_n_tx),
.usb_p_rx(usb_p_rx),
.usb_n_rx(usb_n_rx),
.usb_tx_en(usb_tx_en),
.dev_addr(dev_addr),
// out endpoint interfaces
.out_ep_req({serial_out_ep_req, ctrl_out_ep_req}),
.out_ep_grant({serial_out_ep_grant, ctrl_out_ep_grant}),
.out_ep_data_avail({serial_out_ep_data_avail, ctrl_out_ep_data_avail}),
.out_ep_setup({serial_out_ep_setup, ctrl_out_ep_setup}),
.out_ep_data_get({serial_out_ep_data_get, ctrl_out_ep_data_get}),
.out_ep_data(out_ep_data),
.out_ep_stall({serial_out_ep_stall, ctrl_out_ep_stall}),
.out_ep_acked({serial_out_ep_acked, ctrl_out_ep_acked}),
// in endpoint interfaces
.in_ep_req({1'b0, serial_in_ep_req, ctrl_in_ep_req}),
.in_ep_grant({nak_in_ep_grant, serial_in_ep_grant, ctrl_in_ep_grant}),
.in_ep_data_free({nak_in_ep_data_free, serial_in_ep_data_free, ctrl_in_ep_data_free}),
.in_ep_data_put({1'b0, serial_in_ep_data_put, ctrl_in_ep_data_put}),
.in_ep_data({8'b0, serial_in_ep_data[7:0], ctrl_in_ep_data[7:0]}),
.in_ep_data_done({1'b0, serial_in_ep_data_done, ctrl_in_ep_data_done}),
.in_ep_stall({1'b0, serial_in_ep_stall, ctrl_in_ep_stall}),
.in_ep_acked({nak_in_ep_acked, serial_in_ep_acked, ctrl_in_ep_acked}),
// sof interface
.sof_valid(sof_valid),
.frame_index(frame_index),
// Debug
.debug(debug[11:4])
);
////////////////////////////////////////////////////////////////////////////////
// host presence detection
////////////////////////////////////////////////////////////////////////////////
// always @(posedge clk_48mhz) begin
// if (sof_valid) begin
// host_presence_timer <= 0;
// host_presence_timeout <= 0;
// end else begin
// host_presence_timer <= host_presence_timer + 1;
// end
// if (host_presence_timer > 48000000) begin
// host_presence_timeout <= 1;
// end
// end
endmodule

View File

@ -0,0 +1,110 @@
/*
usb_uart_i40
Simple wrapper around the usb_uart which incorporates the Pin driver logic
so this doesn't clutter the top level circuit
The layer above has to assert the Host Pull Up line
----------------------------------------------------
usb_uart_i40 u_u_i40 (
.clk_48mhz (clk_48mhz),
.reset (reset),
// pins
.pin_usb_p( pin_usb_p ),
.pin_usb_n( pin_usb_n ),
// uart pipeline in
.uart_in_data( uart_in_data ),
.uart_in_valid( uart_in_valid ),
.uart_in_ready( uart_in_ready ),
// uart pipeline out
.uart_out_data( uart_out_data ),
.uart_out_valid( uart_out_valid ),
.uart_out_ready( uart_out_ready ),
);
*/
module usb_uart (
input clk_48mhz,
input reset,
// USB pins
inout pin_usb_p,
inout pin_usb_n,
// uart pipeline in (out of the device, into the host)
input [7:0] uart_in_data,
input uart_in_valid,
output uart_in_ready,
// uart pipeline out (into the device, out of the host)
output [7:0] uart_out_data,
output uart_out_valid,
input uart_out_ready,
output [11:0] debug
);
wire usb_p_tx;
wire usb_n_tx;
wire usb_p_rx;
wire usb_n_rx;
wire usb_tx_en;
//wire [3:0] debug;
usb_uart_core uart (
.clk_48mhz (clk_48mhz),
.reset (reset),
// pins - these must be connected properly to the outside world. See below.
.usb_p_tx(usb_p_tx),
.usb_n_tx(usb_n_tx),
.usb_p_rx(usb_p_rx),
.usb_n_rx(usb_n_rx),
.usb_tx_en(usb_tx_en),
// uart pipeline in
.uart_in_data( uart_in_data ),
.uart_in_valid( uart_in_valid ),
.uart_in_ready( uart_in_ready ),
// uart pipeline out
.uart_out_data( uart_out_data ),
.uart_out_valid( uart_out_valid ),
.uart_out_ready( uart_out_ready ),
.debug( debug )
);
wire usb_p_in;
wire usb_n_in;
assign usb_p_rx = usb_tx_en ? 1'b1 : usb_p_in;
assign usb_n_rx = usb_tx_en ? 1'b0 : usb_n_in;
SB_IO #(
.PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
.PULLUP(1'b 0)
) iobuf_usbp (
.PACKAGE_PIN(pin_usb_p),
.OUTPUT_ENABLE(usb_tx_en),
.D_OUT_0(usb_p_tx),
.D_IN_0(usb_p_in)
);
SB_IO #(
.PIN_TYPE(6'b 1010_01), // PIN_OUTPUT_TRISTATE - PIN_INPUT
.PULLUP(1'b 0)
) iobuf_usbn (
.PACKAGE_PIN(pin_usb_n),
.OUTPUT_ENABLE(usb_tx_en),
.D_OUT_0(usb_n_tx),
.D_IN_0(usb_n_in)
);
endmodule

View File

@ -0,0 +1,118 @@
/*
usb_uart_x7
Simple wrapper around the usb_uart which incorporates the Pin driver logic
so this doesn't clutter the top level circuit
Make the signature generic (usb_uart) and rely on the file inclusion process (makefile)
to bring the correct architecture in
The layer above has to assert the Host Pull Up line
usb_uart u_u (
.clk_48mhz (clk_48mhz),
.reset (reset),
// pins
.pin_usb_p( pin_usb_p ),
.pin_usb_n( pin_usb_n ),
// uart pipeline in
.uart_in_data( uart_in_data ),
.uart_in_valid( uart_in_valid ),
.uart_in_ready( uart_in_ready ),
// uart pipeline out
.uart_out_data( uart_out_data ),
.uart_out_valid( uart_out_valid ),
.uart_out_ready( uart_out_ready ),
);
*/
`include "../../pipe/rtl/pipe_defs.v"
module usb_uart (
input clk_48mhz,
input reset,
// USB pins
inout pin_usb_p,
inout pin_usb_n,
// uart pipeline in (out of the device, into the host)
input [7:0] uart_in_data,
input uart_in_valid,
output uart_in_ready,
// uart pipeline out (into the device, out of the host)
output [7:0] uart_out_data,
output uart_out_valid,
input uart_out_ready,
output [11:0] debug
);
wire usb_p_tx;
wire usb_n_tx;
wire usb_p_rx;
wire usb_n_rx;
wire usb_tx_en;
//wire [3:0] debug;
usb_uart_core_np u_u_c_np (
.clk_48mhz (clk_48mhz),
.reset (reset),
// pins - these must be connected properly to the outside world. See below.
.usb_p_tx(usb_p_tx),
.usb_n_tx(usb_n_tx),
.usb_p_rx(usb_p_rx),
.usb_n_rx(usb_n_rx),
.usb_tx_en(usb_tx_en),
// uart pipeline in
.uart_in_data( uart_in_data ),
.uart_in_valid( uart_in_valid ),
.uart_in_ready( uart_in_ready ),
// uart pipeline out
.uart_out_data( uart_out_data ),
.uart_out_valid( uart_out_valid ),
.uart_out_ready( uart_out_ready ),
.debug( debug )
);
wire usb_p_in;
wire usb_n_in;
assign usb_p_rx = usb_tx_en ? 1'b1 : usb_p_in;
assign usb_n_rx = usb_tx_en ? 1'b0 : usb_n_in;
IOBUF #(
.DRIVE(16), // Specify the output drive strength
.IBUF_LOW_PWR("FALSE"), // Low Power - "TRUE", High Performance = "FALSE"
.IOSTANDARD("DEFAULT"), // Specify the I/O standard
.SLEW("FAST") // Specify the output slew rate
) iobuf_p (
.O( usb_p_in ), // Buffer output
.I( usb_p_tx ), // Buffer input
.IO( pin_usb_p ), // Buffer inout port (connect directly to top-level port)
.T( !usb_tx_en ) // 3-state enable input, high=input, low=output
);
IOBUF #(
.DRIVE(16), // Specify the output drive strength
.IBUF_LOW_PWR("FALSE"), // Low Power - "TRUE", High Performance = "FALSE"
.IOSTANDARD("DEFAULT"), // Specify the I/O standard
.SLEW("FAST") // Specify the output slew rate
) iobuf_n (
.O( usb_n_in ), // Buffer output
.I( usb_n_tx ), // Buffer input
.IO( pin_usb_n ), // Buffer inout port (connect directly to top-level port)
.T( !usb_tx_en ) // 3-state enable input, high=input, low=output
);
endmodule