Você está na página 1de 18

1 Spartan-3E MATLAB Interface

Spartan-3E MATLAB Interface


This document provides a complete documentation of the VHDL and
Summary
MATLAB interface designed for the Spartan 3E Starter Kit available from
the Xilinx website.

[http://www.xilinx.com/products/devboards/index.htm]

Introduction This project was designed to provide both a basic demonstration of


floating point operations and provide a simple Universal Asynchronous
Receiver-Transmitter RS-232 communication protocol with MATLAB on
the Xilinx Spartan-3E FPGA platform.

A modified set of fixed and floating-point packages designed for the IEEE
1076-2006 LRM were utilized for floating point math on the board. The
vhdl-93 version of the VHDL-200X IEEE.Float_Pkg and IEEE.Fixed_Pkg
are currently from the locations listed at the bottom of this section.

The documentation for this project covers most aspects of the design and
implementation. A directory structure and implementation structure is
provided on Page 2. Pages 3 – 13 provide a reference to the RTL blocks of
the project, and Page 14 provide short documentation on all MATLAB
functions. Appendix A provides a introduction to floating-point numbers
and details the MATLAB functions created for working floating-point
numbers.

A copy of the material used in this project is available on the EWU


chapter ieee website at ieee.ewu.edu, and in the Past Teaching section of
Dr. Claudio Talarico’s Eastern webpage http://www.ewu.edu/x30360.xml.

[http://www.vhdl.org/vhdl-200x/vhdl-200x-ft/packages/files.html]
[Xilinx ISE Application Path/vhdl/src/ieee_proposed].

Last updated 5/5/2008


2 Spartan-3E MATLAB Interface

Directory The directory structure of the project is shown below:


Structure -- root
-- documentation
-- main_doc.pdf
-- matlab
-- demo.m
-- dm_to_fp32m.m
-- double_to_fp32v.m
-- fp32d_to_double.m
-- fp32m_to_dm.m
-- fp32v_to_double.m
-- sim_matrix.m
-- sim_multiplication.m
-- spartan_command.m
-- spartan_init_protocol.m
-- spartan_load_constants.m
-- spartan_read_from_memory.m
-- spartan_write_to_memory.m
-- vhdl
-- archive
-- project.zip
-- rtl
-- top.vhd
-- fixed_pkg_c.vhd
-- float_pkg_c.vhd
-- main.vhd
-- ramb16_s9_port.vhd
-- rs232_interface.vhd
-- rs232_rx.vhd
-- rs232_tx.vhd
-- testbench
-- top_tb.vhd
-- rs232_rx_tb.vhd
-- rs232_tx_tb.vhd
-- top.ucf

Implementation The HDL source structure is given below, as connected.


-- top - beh
Structure -- inst_main - rtl
-- ramb16_s9_port - struct
-- inst_rs232_interface - struct
-- rs232_rx - rtl
-- rs232_tx - rtl
-- top - ucf

Last updated 5/5/2008


3 Spartan-3E MATLAB Interface

Implementation This section covers the project HDL implementation on a block by block
basis.
Description

Top Level The top level (Figure 1) of the project is straightforward, with input and
output ports attached to the development board slide switches (ssw),
buttons (btn), and leds (led). A 50 MHz on-board clock is attached to the
(clk) input, BTN South on the board is attached to reset (rst) and finally
rxd and txd connect to the dce_rxd and dce_txd serial pins on the board,
respectively (Table 1).

Figure 1 – Top level diagram

Port Name Direction Type Range Description


clk in std_logic system clock
rst in std_logic system reset, start kit button
south
btn in std_logic_vector 2:0 starter kit buttons, 0=west,
1=north, 2=south
ssw in std_logic_vector 3:0 starter kit slider switches 3 to
0
led out std_logic_vector 7:0 starter kit led array 7 to 0
txd out std_logic dce_txd
rxd in std_logic dce_rxd
Table 1 – Port definitions

Last updated 5/5/2008


4 Spartan-3E MATLAB Interface

Implementation
Description

RS232_Interface The rs232_interface module (Figure 2) is a structural module and serves


to connect the rs232_tx and rs232_tx modules into a single entity (Table
2, Figure 4).

The rs232 unit as a whole transmits and receives 8-bit data over the serial
port asynchronously, adhering to the UART RS-232 Protocol.
Asynchronous means that data can be sent and received at the same
time.

Note: In the following descriptions the slave device refers to the starter
kit board / FPGA UART controller and the master device is defined as the
computer / MATLAB Serial Object.

Port Name Direction Type Range Description


clk in std_logic system clock
rst in std_logic system reset
wstb in std_logic transmit data flag
dsend in std_logic_vector 7:0 transmit data to master
from slave
txbusy out std_logic busy transmitting
dreceive out std_logic_vector 7:0 received data from master
to slave
rxready out std_logic data received flag
txd out std_logic dce_txd
rxd in std_logic dce_rxd
Table 2 – Port Definitions

Figure 2 – RS232_Interface structural schematic

Last updated 5/5/2008


5 Spartan-3E MATLAB Interface

Implementation
Description

Rs232_Tx The rs232_tx module is connected to the dsend[7:0] input port, the
wstb port, and the txbusy port, as well as the txd and clk ports. The
proper sequence to transmit data is to wait until txbusy has value ‘0’
and then set dsend[7:0] to the byte to be transmitted and raise wstb to
‘1’. Data will start being sent on the rising ed
edge
ge of clk, and will take
10/BAUD_RATE seconds to transmit
transmit, see Figure 3.

Figure 3 – Data Transmission, rs232_tx

Rs232_Rx The rs232_rx module is connect to the dreceive[7:0] output port, the
rxready port, and to the rxd and clk ports. The module contains a
process that checks on the positive edge of clk for a start bit from the
master. When a transmission is detected a register is loaded with the
following eight bits of sent data, and the stop bit is accounted for, and
then the rxready flag raised
raised.. The rxready flag will remain high for one
clock cycle. Outside processes with rxready in their sensitivity list can
detect when data is available and copy it from the dreceive[7:0] port.
Data is guaranteed to be available for only one clock period after
rxready is set high
high, see figure 5.

Figure 5 – Receiving data, rs232_rx

Last updated 5/5/2008


6 Spartan-3E MATLAB Interface

Figure 4 – Rs232_Interface connected RTL schematic

Constants_Pkg This package contains definitions of constants for use in the


communication protocol between MATLAB and the FPGA.

(Equ. 1.1) An additional constant, CLK_DIV, allows for adjusting the


UART baud rate.
  
 /_

Last updated 5/5/2008


7 Spartan-3E MATLAB Interface

Implementation
Description

Main This module is connected to all other blocks and is the central unit for
this project (Figure 6). The module consists of a one-hot state machine
inference using soft encoding. The states are listed in Table 3.

State Name Serial Port Command #* Description


idle internal / default 0 Waits on rs232 for control
commands from serial port.
state_echo MODE_ECHO 1 Echos single byte to serial port
state_read_memory MODE_READ_MEMORY 5 Reads an arbitrary number of
bytes out of block ram and
sends over serial port.
state_write_memory MODE_WRITE_MEMORY 6 Writes an arbitrary number of
bytes to block ram received
from serial port.
state_multiply_float MODE_MULTIPLY_FLOAT 3 Multiplies two 32-bit floating
point numbers located in
MEM_DIV1 and MEM_DIV2, and
stores in MEM_DIV3.
state_read_fp32_from_memory internal 4 Reads 32-bit floating point
number from location specified
by addrReg, stores in fpv3Reg
and returns to state loaded in
stateHoldReg.
state_write_fp32_to_memory internal 4 Writes 32-bit floating point
number to location specified by
addrReg, from fpv3Reg, and
returns to state loaded in
stateHoldReg.
state_multiply_matrix MODE_MULTIPLY_MATRIX 9 Multiplies two square floating
point matrices from addresses
starting at MEM_DIV1,
MEM_DIV2, and stores at
MEM_DIV3. See page ##.
state_test_fp_load MODE_TEST_FP 2 Tests synthesis of floating-point
library by multiplying two
constant values and displaying
bytes on leds. Use slide switches
to select byte to display.
state_delay_one internal 0 Delays one clock cycle and
returns to the state loaded in

Last updated 5/5/2008


8 Spartan-3E MATLAB Interface

stateHoldReg.
acknowledge any 1 Sends ACK byte over serial port
and returns to state loaded in
stateHoldReg.
Table 3 – State descriptions

*number of additional states, for example state_echo also has a second state it goes into: state_echo1.

Figure 6 – Main module interconnection with Rs232_Interface

This section provides additional information on states in main.vhd,


Selected
including proper initiation using the serial protocol developed.
Additional Please see Page ## for how to set up proper communication
Information between MATLAB and the Spartan Starter Kit before trying any
examples.

state_read_memory There is a MATLAB function to automatically do the example below,


but to demonstrate functionality we go through the communication
process step by step.

Last updated 5/5/2008


9 Spartan-3E MATLAB Interface

Useage example:

To read 16 consecutive bytes from the block ram of the FPGA starting
at address 1024.

1) First, break the address into a low byte and high byte. The low byte
is, obviously, 8 bits long, and the high byte is 3 bits long, due to size
limitations of the block ram.

 d”1024” = b” 0000 0100 0000 0000”


 high byte = b”0000 0100” = d”4”
 low byte = b”0000 0000” = d”0”

2) The number of bytes to retrieve is 16, which is below 255, the


decimal maximum of the low byte, so we can calculate directly a high
byte of 0 and low byte of 16, or:

 d”16” = b“0000 0000 0001 0000”


 high byte = d”0”
 low byte = d”16”

Note: The Spartan XC3S500E FPGA chip has 2048 bytes of available
block ram, and we use an addressing system of 0 to 7FF (0 to 2047
decimal).

3) In MATLAB enter the following commands:

>> addr_low_byte = 0;
>> addr_high_byte = 4;
>> count_low_byte = 0;
>> count_high_byte = 16;
>> total_count = 16;
>> fwrite(s, MODE_READ_MEMORY)
>> if (fread(s,1) == ACK)
>> fwrite(s,addr_high_byte);
>> fwrite(s,addr_low_byte);
>> fwrite(s,count_high_byte);
>> fwrite(s,count_low_byte);
>> data = fread(s, total_count);
>> end
>> data

It is not necessary to write the script exactly as above. What is


important though is the order in which a script send commands.
1. Send constant MODE_READ_MEMORY byte (h”10”)
2. Wait for acknowledgement (ACK or h”FE”)
3. Send high byte of address
4. Send low byte of address
5. Send high byte of count (bytes to retrieve)

Last updated 5/5/2008


10 Spartan-3E MATLAB Interface

6. Send low byte of count

7. Wait until data appears in serial object from MATLAB or


whatever serial program in use.

The matlab function to complete the above task is:

function [data] =
spartan_read_from_memory(s,addr,count)

(Equ. 1.2) Execution time estimation:

  _  5 _!"#$ / 


_%&'

state_write_memory This function is similar to state_read_memory. The order of


commands are:
1. Send constant MODE_WRITE_MEMORY byte (h”11”)
2. Wait for acknowledgement (ACK or h”FE”)
3. Send high byte of address
4. Send low byte of address
5. Send high byte of count (bytes being sent)
6. Send low byte of count
7. Send individual bytes that are to be written to memory,
ensuring to send “count” number of bytes.

The matlab function to complete the above task is:

function spartan_write_to_memory(s,addr,data)

where data is an integer vector, all integers are byte-long (e.g. less
than decimal 256) and it is in row form. E.g. [5,79,35,2,0,255]

(Equ. 1.3) Execution time estimation:

  _  5 _!"#$ / 


_%&'

state_multiply_float To use this function:


1. Write single floating point numbers to block ram at
MEM_DIV1 and MEM_DIV2.
2. Send constant MODE_MULTIPLY_FLOAT byte (h”13”)
3. Wait for acknowledgement (ACK or h”FE”)
4. Result is stored first four bytes of at offset MEM_DIV3

Usage example:

>> n1 = double_to_fp32v(-3.1416));
>> n2 = double_to_fp32v(7.0);

Last updated 5/5/2008


11 Spartan-3E MATLAB Interface

>> spartan_write_to_memory(s, MEM_DIV1,n1);


>> spartan_write_to_memory(s,MEM_DIV2,n2);

>> result = spartan_read_from_memory(s,MEM_DIV3,4);


>> fp32v_to_double(result)

Note: See page Appendix A for more information about the


double_to_fp32v and fp32v_to_double functions.

(Equ. 1.4) Execution time estimation:

  26 / 
_%&'

state_multiply_matrix To use this mode, floating point numbers need to correctly stored at
offsets in memory starting at MEM_DIV1 for the first matrix and
MEM_DIV2 for the second matrix. Also the resulting matrix will be
stored in MEM_DIV3, so the contents of a matrix-sized area in
MEM_DIV3 must be set to floating-point 0.

Matrices are mapped as follows:

Figure 7 – Mapping matrix into memory*

*The index numbers in Figure 7 correspond to matlab index on the


left in ( ) and VHDL indices on the right in [ ].

After storing the floating point matrices, enter the


state_multiply_matrix state to execute the routine and output the
results starting at MEM_DIV3.

Usage example.
This example is stored in demo.m in the matlab directory for
convenience.

Last updated 5/5/2008


12 Spartan-3E MATLAB Interface

>> N = 3;

>> x = randn(N,N) %random floating point matrix


>> xr = reshape(x’,1,N^2); %mapped into 1xN^2 vector
>> xfpv = dm_to_fp32m(xr); %converted into 4 byte FP
representation
>> spartan_write_to_memory(s,MEM_DIV1,xfpv); %loaded
to MEM_DIV1

>> y = randn(N,N)
>> yr = reshape(y’,1,N^2);
>> yfpv = dm_to_fp32m(yr);
>> spartan_write_to_memory(s,MEM_DIV2,yfpv); %loaded
to MEM_DIV2

>> w = zeros(N,N);
>> wr = reshape(w,1,N^2);
>> wfpv = dm_to_fp32m(wr);
>> spartan_write_to_memory(s,MEM_DIV3,wfpv) %clear
MEM_DIV3 (see note)

>> spartan_command(s,MODE_MULTIPLY_MATRIX)
>> fwrite(s,N); %write the N x N size of the
matrices

>> zfpv =
spartan_read_from_memory(s,MEM_DIV3,(N^2)*4);
>> zr = fp32m_to_dm(zfpv);
>> z = reshape(zr,N,N)'; %view the result

Note:
1) MATLAB’s reshape function maps the elements of a matrix into a
vector by column, different than the definition used in Figure 7.
Hence, if using their function, pass the transpose of matrices before
reshaping, and take the transpose of the final result, as in the given
example.
2) The contents at MEM_DIV3 must be cleared to floating-point 0
manually before calculating the matrix multiplication.

(Equ. 1.5) Matrix-Multiplication Algorithm:


1
*,,  - .*,/ 0/,,
/23

(Equ. 1.6) Execution time estimation:

  3656 /
_%&'

Last updated 5/5/2008


13 Spartan-3E MATLAB Interface

acknowledge This state is entered after anything is received over the serial port if
the state machine is in the idle state. It is used by the MATLAB
functions as a command-received verification.

state_read_fp32_from_memory Reads four bytes of memory, starting at the value of addrReg,


incrementing 3 times to obtain consecutive values, and loading each
one into register fpv3Reg.
offset + 0 -> fpv3Reg(8 downto 1)
offset + 1 -> fpv3Reg(0 downto -7)
offset + 2 -> fpv3Reg(-8 downto -15)
offset + 3 -> fpv3Reg(-16 downto -23)

The routine takes 9 clock cycles to execute. See Figure 8.

Figure 8 – State_read_fp32_from_memory timing diagram

state_write_fp32_to_memory Writes four bytes of memory, starting at the value of addrReg,


incrementing 3 times to obtain consecutive values, and writing each
position in memory with corresponding byte in fpv3Reg.
offset + 0 <- fpv3Reg(8 downto 1)
offset + 1 <- fpv3Reg(0 downto -7)
offset + 2 <- fpv3Reg(-8 downto -15)
offset + 3 <- fpv3Reg(-16 downto -23)

The routine takes 5 clock cycles to execute. See Figure 9.

Figure 9 – State_write_fp32_to_memory timing diagram

Last updated 5/5/2008


14 Spartan-3E MATLAB Interface

Interfacing with This section describes the functions written in MATLAB to


communicate with the FPGA using the rs232_interface module.
MATLAB Table 4 has functional descriptions.

Command Usage
spartan_load_constants() Loads constants used in above communication
protocol into the MATLAB workspace. Ex. Loads
ACK = hex2dec(‘FE’);
s = spartan_init_protocol() Sets up a serial communication object and opens
the connection with the correct BaudRate,
DataBits, Parity, StopBits and FlowControl
settings for communication with the FPGA.
success = spartan_command(s,command) Sends a command as defined in the constants for
both the FPGA and MATLAB, and checks for
acknowledge. Returns 1 if success, 0 if error.
data = Sends the correct commands to retrieve ‘count’
spartan_read_from_memory(s,addr,count) number of bytes from block ram starting at addr in
memory. addr between 0 and 2047.
spartan_write_to_memory(s,addr,data) Sends the correct commands and data to write
data to block ram. addr between 0 and 2047. data
a 1 x N vector with byte-sized elements, N < 2048.
d = fp32d_to_double(n) Follows the rules as specified by IEEE 754 to
convert between 32-bit floating point numbers
(specified in decimal) to double.
d = fp32v_to_double(v) Converts between 4-byte floating point number
and double. v = [byte1,byte2,byte3,byte4], where
byte1 is first byte in memory operations and most
significant byte.
dv = fp32m_to_dm(f) Converts several 4-byte floating point numbers,
arranged in a vector, end-to-end, similar to the
way they are stored in block ram on FPGA.
v = double_to_fp32v(d) Converts a short double to a 4-byte floating point
representation vector.
v = dm_to_fp32m(d) Converts several short doubles arranged in end-to-
end in a vector, into 4-byte floating point
numbers, similarly arranged.
demo.m Demonstration of writing and reading matrices to
FPGA, and multiplying two matrices on the FPGA.
matrix.m and simulation_address.m Test functions illustrating how matrices are
mapped into memory and multiplication is
performed.

Last updated 5/5/2008


15 Spartan-3E MATLAB Interface

Appendix A Calculating Floating Point Numbers

A more complex example

Bit values for the IEEE 754 32bit float -118.625

The decimal number −118.625 is encoded using the IEEE 754 system as follows:

1. The sign, the exponent, and the fraction are extracted from the original number. First, because
becaus
the number is negative, the sign bit is "1".
2. Next, the number (without the sign; i.e., unsigned, no two's complement) is converted to binary
notation, giving 1110110.101.
10110.101. The 101 after the binary point has the value 0.625 because it is the
sum of:
1. (2−1) × 1, from the first digit after the binary point
2. (2−2) × 0, from the second digit
3. (2−3) × 1, from the third digit.
3. That binary number is then normalized; that is,, the binary point is moved left, leaving only a 1 to
its left. The number of places it is moved gives the (power of two) exponent: 1110110.101
becomes 1.110110101 × 26. After this process, the first binary digit is always a 1, so it need not
be included in n the encoding. The rest is the part to the right of the binary point, which is then
padded with zeros on the right to make 23 bits in all, which becomes the significand bits in the
encoding: That is, 11011010100000000000000.
4. The exponent is 6. This is enc
encoded
oded by converting it to binary and biasing it (so the most
negative encodable exponent is 0, and all exponents are non non-negative
negative binary numbers). For the
32-bit
bit IEEE 754 format, the bias is +127 and so 6 + 127 = 133. In binary, this is encoded as
10000101.

"IEEE 754-1985." Wikipedia, The Free Encyclopedia


Encyclopedia.. 28 Apr 2008, 17:03 UTC. Wikimedia Foundation, Inc.
6 May 2008 <http://en.wikipedia.org/w/index.php?title=IEEE_754
http://en.wikipedia.org/w/index.php?title=IEEE_754-1985&oldid=208787491
1985&oldid=208787491>.

In function fp32d_to_double, special conditions are accounted for as follows:

if (exponent == 0 && fraction == 0)


d = 0;
return;
elseif (exponent == 255 && fraction ~= 0)
d = NaN;
return;
elseif (exponent == 255 && fraction == 0)
d = S*Inf;
return;
else

The sign is calculated with S = -2*b(32)


2*b(32) + 1; %0 => +1, 1 => -1

Last updated 5/5/2008


16 Spartan-3E MATLAB Interface

Exponent base is 127; %2^((maximum exponent/2)–1)


Fraction is taken from first 23 bits of binary vector data, obtained using dec2binvec function in matlab,
and padded to appropriate length.
Exponent is extracted from bits 24:31.
fraction_base = 8388608; %2^(maximum fraction size in bits)
The final answer in double is given by the equation d = S * 2 ^ (exponent - exponent_base) * (1.0 +
fraction/(fraction_base));

In function double_to_fp32v, special conditions are accounted for immediately as follows:

if (d == 0 || isnan(d) || abs(d) == Inf)


if (d == -Inf)
S = 1;
e = 255;
f = 0;
elseif (d == Inf)
S = 0;
e = 255;
f = 0;
elseif (isnan(d))
S = 1;
e = 255;
f = 255;
elseif (d == 0)
e = 0;
f = 0;
S = 0;
end
v = [dec2bin(S,1) dec2bin(e,8) dec2bin(f,23)];
else

The sign bit is calculated:

if (d<0)
S = 1;
else
S = 0;
end

The magnitude of the number is broken into an integer part and a fraction part. E.g. 118.625 has integer
part 118 and fraction part 0.625

d = abs(d);

integer = floor(d);
frac = d - integer;

The integer can immediately be converted to binary using matlab’s builtin function dec2bin(integer).

The fraction is converted using a form of base division. Divide the fraction by base 2, add the interger
part to the binary string and discard, divide remainder by 2, and so on, to a acceptable precision. Read

Last updated 5/5/2008


17 Spartan-3E MATLAB Interface

the final result start to finish.

binfrac = zeros(1,23);
for k = 1:64
binfrac(k) = (floor(frac*2));
frac = 2*frac - floor(2*frac);
end

For example 118.625 -> 1110110 integer part and 1010000000000000000 … fraction part.

Now make a number take binary part from 2:end, e.g. we always know the most significant bit of
integer part will be 1, so we don’t have to keep it. Append fraction part.

So from previous example we have [1110110.1010000000000000000]

Now we have to normalize the number, as described in the Wikipedia entry. Basically we need to move
the decimal dot right or left so there is only 1 to the left of the dot, and keep track of how many places
we move it. So 1110110.1010000000000000000 = 1.1101101010000 , or exponent equals the length of
the integer part – 1, since this is how many places we have to move the dot.

For a number like 0.00101, need to move decimal to the right, and you can see a solution below.

if (integer == 0)
exponent = -find(sbinfrac=='1',1);
f = f(-exponent+1:end);
else
exponent = length(binint) - 1;
end

Then we just combine all the parts into the proper form, keeping only 23 bits of the normalized
integer+fraction part (since the fraction can be made infinetly precise).

e = exponent + exponent_base;
v = [dec2bin(S,1) dec2bin(e,8) f(1:23)];

Finally split the binary number into 4 bytes:

v = [bin2dec(v(1:8)) bin2dec(v(9:16)) bin2dec(v(17:24)) bin2dec(v(25:32))];

Last updated 5/5/2008


18 Spartan-3E MATLAB Interface

Credits

Credit for project stimulus goes to Dr. Min-Sung Koh.

Credit for vhdl and MATLAB design goes to David Freiberger and
Tyler Jones.

Credit (last but not least) goes to Dr. Talarico for all his effort in
helping us to learn VHDL and for his helpful comments on design,
coming from his experience in the industry.

Students and Staff of Eastern Washington University

Dr. Min-Sung Koh - mkoh@mail.ewu.edu


Dr. Claudio Talarico - ctalarico@mail.ewu.edu

David Freiberger - davidfreiberger@gmail.com


Tyler Jones - tylr.jones@yahoo.com

technology.ewu.edu
ieee.ewu.edu

Tools used in this project include the Xilinx ISE Design Suite 10.1
(WebPack), which is freely available to students and researchers,
MATLAB, which is not freely available, Programmers Notepad for
editing and viewing C, VHDL, Verilog, and MATLAB files all at once
with nice syntax highlighting, and Adobe Photoshop for desiging this
report.

In addition Windows Notepad and Calculator are always on the Quick


Launch toolbar, always ready to make a quick binary to hex number
calculation or save some text temporarily.

Last but not least, Wikipedia, VHDL.org, countless forums, and


Google are to thank making this work.

Last updated 5/5/2008

Você também pode gostar