Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in
Toggle navigation
B
Beam Positoning Monitor - Gateware
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
Wiki
Wiki
image/svg+xml
Discourse
Discourse
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Commits
Issue Boards
Open sidebar
Projects
Beam Positoning Monitor - Gateware
Commits
4eaaadf0
Commit
4eaaadf0
authored
Aug 29, 2013
by
Lucas Russo
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
hdl/modules/*/wb_rs232/*: add rs232 wishbone master
parent
0e776396
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
2809 additions
and
1 deletion
+2809
-1
Manifest.py
hdl/modules/dbe_wishbone/Manifest.py
+2
-1
Manifest.py
hdl/modules/dbe_wishbone/wb_rs232_syscon/Manifest.py
+7
-0
auto_baud.v
hdl/modules/dbe_wishbone/wb_rs232_syscon/auto_baud.v
+563
-0
rs232_syscon.pdf
hdl/modules/dbe_wishbone/wb_rs232_syscon/rs232_syscon.pdf
+0
-0
rs232_syscon.v
hdl/modules/dbe_wishbone/wb_rs232_syscon/rs232_syscon.v
+1193
-0
rs232_syscon_top.v
hdl/modules/dbe_wishbone/wb_rs232_syscon/rs232_syscon_top.v
+54
-0
rs232_syscon_top.xml
...modules/dbe_wishbone/wb_rs232_syscon/rs232_syscon_top.xml
+21
-0
serial.v
hdl/modules/dbe_wishbone/wb_rs232_syscon/serial.v
+728
-0
wb_rs232_syscon.vhd
hdl/modules/dbe_wishbone/wb_rs232_syscon/wb_rs232_syscon.vhd
+157
-0
xwb_rs232_syscon.vhd
...modules/dbe_wishbone/wb_rs232_syscon/xwb_rs232_syscon.vhd
+84
-0
No files found.
hdl/modules/dbe_wishbone/Manifest.py
View file @
4eaaadf0
...
...
@@ -6,5 +6,6 @@ modules = { "local" : [
"wb_fmc516"
,
"wb_ethmac_adapter"
,
"wb_ethmac"
,
"wb_dbe_periph"
"wb_dbe_periph"
,
"wb_rs232_syscon"
]
};
hdl/modules/dbe_wishbone/wb_rs232_syscon/Manifest.py
0 → 100644
View file @
4eaaadf0
files
=
[
"auto_baud.v"
,
"rs232_syscon.v"
,
"rs232_syscon_top.v"
,
"wb_rs232_syscon.vhd"
,
"xwb_rs232_syscon.vhd"
,
"serial.v"
]
hdl/modules/dbe_wishbone/wb_rs232_syscon/auto_baud.v
0 → 100644
View file @
4eaaadf0
//-----------------------------------------------------------------------------
// Auto Baud core
//
// This file is part of the "auto_baud" project.
// http://www.opencores.org/
//
//
// Description: See description below (which suffices for IP core
// specification document.)
//
// Copyright (C) 2002 John Clayton and OPENCORES.ORG
//
// This source file may be used and distributed without restriction provided
// that this copyright statement is not removed from the file and that any
// derivative work contains the original copyright notice and the associated
// disclaimer.
//
// This source file is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This source is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
// License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this source.
// If not, download it from http://www.opencores.org/lgpl.shtml
//
//-----------------------------------------------------------------------------
//
// Author: John Clayton
// Date : Aug. 20, 2002
// Update: Aug. 20, 2002 copied this file from rs232_syscon.v (pared down).
// Update: Sep. 4, 2002 First test of this module. The baud rate appears
// to be produced at 1/2 of the desired rate!
// Update: Sep. 5, 2002 First working results. Fixed measurement (shift had
// been left out.) Removed debug port since the unit
// appears to be working fine. It Worked for all of the
// following BAUD rates, using 49.152 MHz clock and
// CLK_FACTOR = 8 and 16 bit main counter:
// 300, 1200, 2400, 9600, 19200, 38400, 57600, 115200.
// Next step is to build the "tracking" version that
// doesn't need a reset to find a new BAUD rate...
// Update: Sep. 13, 2002 Added test data from "auto_baud_with_tracking.v"
// module tests. This module has also been tested
// at various speeds, and it works well.
//
// Description
//-----------------------------------------------------------------------------
// This is a state-machine driven core that measures transition intervals
// in a particular character arriving via rs232 transmission (i.e. PC serial
// port.) Measurements of time intervals between transitions in the received
// character are then used to generate a baud rate clock for use in serial
// communications back and forth with the device that originally transmitted
// the measured character. The clock which is generated is in reality a
// clock enable pulse, one single clock wide, occurring at a rate suitable
// for use in serial communications. (This means that it will be generated
// at 4x or 8x or 16x the actual measured baud rate of the received character.
// The multiplication factor is called "CLOCK_FACTOR_PP" and is a settable
// parameter within this module. The parameter "CLOCK_FACTOR_PP" need not
// be a power of two, but it should be a number between 2 and 16 inclusive.)
//
// The particular character which is targeted for measurement and verification
// in this module is: carriage return (CR) = 0x0d = 13.
// This particular character was chosen because it is frequently used at the
// end of a command line, as entered at a keyboard by a human user interacting
// with a command interpreter. It is anticipated that the user would press
// the "enter" key once upon initializing communications with the electronic
// device, and the resulting carriage return character would be used for
// determining BAUD rate, thus allowing the device to respond at the correct
// rate, and to carry on further communications. The electronic device using
// this "auto_baud" module adjusts its baud rate to match the baud rate of
// the received data. This works for all baud rates, within certain limits,
// and for all system clock rates, within certain limits.
//
// Received serially, the carriage return appears as the following waveform:
// ________ __ ____ _______________
// |__|d0|__|d2d3|________|stop
// start d1 d4d5d6d7
//
// The waveform is shown with an identical "high" time and "low" time for
// each bit. However, actual measurements taken using a logic analyzer
// on characters received from a PC show that the times are not equal.
// The "high" times turned out shorter, and the "low" times longer...
// Therefore, this module attempts to average out this discrepancy by
// measuring one low time and one high time.
//
// Since the transition measurements must unavoidably contain small amounts
// of error, the measurements are made during the beginning 2 bits of
// the received character, (that is, start bit and data bit zero).
// Then the measurement is immediately transformed into a baud rate clock,
// used to verify correct reception of the remaining 8 bits of the character.
// If the entire character is not received correctly using the generated
// baud rate, then the measurement is scrapped, and the unit goes into an
// idle scanning mode waiting for another character to test.
//
// This effectively filters out characters that the unit is not interested in
// receiving (anything that is not a carriage return.) There is a slight
// possibility that a group of other characters could appear by random
// chance in a configuration that resembles a carriage return closely enough
// that the unit might accept the measurement and produce a baud clock too
// low. But the probability of this happening is remote enough that the
// unit is considered highly "robust" in normal use, especially when used
// for command entry by humans. It would take a very clever user indeed, to
// enter the correct series of characters with the correct intercharacter
// timing needed to possibly "fool" the unit!
//
// (Also, the baud rate produced falls within certain limits imposed by
// the hardware of the unit, which prevents the auto_baud unit from mistaking
// a series of short glitches on the serial data line for a really
// fast CR character.)
//
// The first carriage return character received will produce a BAUD rate clock
// and the unit will indicate a "locked" condition. From that point onward,
// the unit will continue running, but it will not scan for any more
// input characters. The only way to reset the unit to its initial condition
// is through the use of the "reset_i" pin. Following reset, the unit is
// once again looking for a carriage return character to lock on to.
// Another module, called "auto_baud_with_tracking.v" handles situations where
// you might want to have the BAUD rate change dynamically.
//
//
// NOTES:
// - This module uses a counter to divide down the clk_i signal to produce the
// baud_clk_o signal. Since the frequency of baud_clk_o is nominally
// CLOCK_FACTOR_PP * rx_baud_rate, where "rx_baud_rate" is the baud rate
// of the received character, then the higher you make CLOCK_FACTOR_PP, the
// higher the generated baud_clk_o signal frequency, and hence the lower the
// resolution of the divider. Therefore, using a lower value for the
// CLOCK_FACTOR_PP will allow you to use a lower clk_i with this module.
// - To set LOG2_MAX_COUNT_PP, remember (max_count*CLOCK_FACTOR_PP)/Fclk_i
// is the maximum measurement time that can be accomodated by the circuit.
// (where Fclk_i is the frequency of clk_i, and 1/Fclk_i is the period.)
// Therefore, set LOG2_MAX_COUNT_PP so that the maximum measurement time
// is at least as long as 2x the baud interval of the slowest received
// serial data (2x because there are two bits involved in the measurement!)
// For example, for Fclk_i = 20MHz, CLOCK_FACTOR_PP = 4 and a minimum
// baud rate of 115,200, you would calculate:
//
// (max_count * CLOCK_FACTOR_PP)*1/Fclk_i >= 2/Fbaud_max
//
// Solving for the bit width of the max_count counter...
//
// LOG2_MAX_COUNT_PP >= ceil(log_base_2(max_count))
//
// >= ceil(log_base_2(2*Fclk_i/(Fbaud_max*CLOCK_FACTOR_PP)))
//
// >= ceil(log_base_2(2*20E6/(115200*4)))
//
// >= ceil(log_base_2(86.8))
//
// >= 7 bits.
//
// - In the above example, the maximum count would approach 87, which means
// that a measurement error of 1 count is about (1/87)=approx. 1.15%. This
// is an acceptable level of error for a baud rate clock. Notice that the
// lower baud rates have an even smaller error percentage (Yes!) but that
// they require a much larger measurement counter... For instance,
// to lock onto 300 baud using the same example above, would require:
//
// LOG2_MAX_COUNT_PP >= ceil(log_base_2(40000000/1200))
//
// >= ceil(log_base_2(33333.3))
//
// >= ceil(15.024678)
//
// >= 16 bits.
//
// - If the percentage error for your highest desired baud rate is greater
// than a few percent, you might want to use a higher Fclk_i or else a
// lower CLOCK_FACTOR_PP.
//
// - Using the default settings: CLK_FACTOR_PP = 8, LOG2_MAX_COUNT_PP = 16
// The following test results were obtained, using an actual session in
// hyperterm, looking for correct readable character transmission both
// directions. (Note: These tests were performed at "human interface"
// speeds. High speed or "back-to-back" character transmission might
// exhibit worse performance than these results.)
// The test results shown below were actually obtained using the more
// complex "auto_baud_with_tracking.v" module. Similar or better results
// are expected with this module.
//
// Clk_i
// Freq.
// (MHz) 110 300 1200 2400 4800 9600 19200 57600 115200
// ------ ---------------------------------------------------------------
// 98 FAIL pass pass pass pass pass pass pass pass
// 55 FAIL pass pass pass pass pass pass pass pass
// 49 pass pass pass pass pass pass pass pass pass
// 24.5 pass pass pass pass pass pass pass pass FAIL
// 12 pass pass pass pass pass pass pass pass FAIL
// 6 pass pass pass pass pass pass pass FAIL FAIL
// 3 pass pass pass pass pass FAIL FAIL FAIL FAIL
// 1.5 pass pass pass pass FAIL FAIL FAIL FAIL FAIL
//
//
//-------------------------------------------------------------------------------------
`define
LOG2_MAX_CLOCK_FACTOR 4
//
Sets the size of the CLOCK_FACTOR
// prescaler.
`define
BITS_PER_CHAR 8
//
Include parity
,
if used
,
but not
// start and stop bits...
// Note: Simply changing the template bits does not reconfigure the
// module to look for a different character (because a new measurement
// window would have to be defined for a different character...)
// The template bits are the exact bits used during verify, against
// which the incoming character is checked.
// The LSB of the character is discarded, and the stop bit is appended
// since it is the last bit used during verify.
//
// so, for N:8:1 (no parity, 8 data bits, 1 stop bit) it is:
// = {1,(character>>1)} = 9'h086
// or, with parity included it is:
// = {1,parity_bit,(character>>1)} = 9'h106
//
`define
TEMPLATE_BITS 9
'
h086
//
Carriage return
&&
termination flag
module
auto_baud
(
clk_i
,
reset_i
,
serial_dat_i
,
auto_baud_locked_o
,
baud_clk_o
)
;
// Parameters
// CLOCK_FACTOR_PP can be from [2..16] inclusive.
parameter
CLOCK_FACTOR_PP
=
8
;
// Baud clock multiplier
parameter
LOG2_MAX_COUNT_PP
=
16
;
// Bit width of measurement counter
// State encodings, provided as parameters
// for flexibility to the one instantiating the module.
// In general, the default values need not be changed.
// There is one state machines: m1.
// "default" state upon power-up and configuration is:
// "m1_idle" because that is the all zero state.
parameter
m1_idle
=
4'h0
;
// Initial state (scanning)
parameter
m1_measure_0
=
4'h1
;
// start bit (measuring)
parameter
m1_measure_1
=
4'h2
;
// debounce (measuring)
parameter
m1_measure_2
=
4'h3
;
// data bit 0 (measuring)
parameter
m1_measure_3
=
4'h4
;
// debounce (measuring)
parameter
m1_measure_4
=
4'h5
;
// measurement done (headed to verify)
parameter
m1_verify_0
=
4'h8
;
// data bit 1 (verifying)
parameter
m1_verify_1
=
4'h9
;
// data bit 2 (verifying)
parameter
m1_run
=
4'h6
;
// running
parameter
m1_verify_failed
=
4'h7
;
// resetting (headed back to idle)
// I/O declarations
input
clk_i
;
// System clock input
input
reset_i
;
// Reset signal for this module
input
serial_dat_i
;
// TTL level serial data signal
output
auto_baud_locked_o
;
// Indicates BAUD clock is being generated
output
baud_clk_o
;
// BAUD clock output (actually a clock enable)
// Internal signal declarations
wire
mid_bit_count
;
// During measurement, advances measurement counter
// (Using the mid bit time to advance the
// measurement timer accomplishes a timing "round"
// so that the timing measurement is as accurate
// as possible.)
// During verify, pulses at mid bit time are used
// to signal the state machine to check a data bit.
wire
main_count_rollover
;
// Causes main_count to roll over
wire
clock_count_rollover
;
// Causes clock_count to roll over
// (when clock_count is used as a
// clock_factor prescaler)
wire
enable_clock_count
;
// Logic that determines when clock_count
// should be counting
wire
verify_done
;
// Indicates finish of verification time
reg
idle
;
// Indicates state
reg
run
;
// Indicates state
reg
measure
;
// Indicates state
reg
clear_counters
;
// Pulses once when measurement is done.
reg
verify
;
// Indicates state
reg
character_miscompare
;
// Indicates character did not verify
reg
[
`LOG2_MAX_CLOCK_FACTOR
-
1
:
0
]
clock_count
;
// Clock_factor prescaler,
// and mid_bit counter.
reg
[
LOG2_MAX_COUNT_PP
-
1
:
0
]
main_count
;
// Main counter register
reg
[
LOG2_MAX_COUNT_PP
-
1
:
0
]
measurement
;
// Stored measurement count
reg
[
`BITS_PER_CHAR
:
0
]
target_bits
;
// Character bits to compare
// (lsb is not needed, since it is used up during measurement time,
// but the stop bit and possible parity bit are needed.)
// For the state machine
reg
[
3
:
0
]
m1_state
;
reg
[
3
:
0
]
m1_next_state
;
//--------------------------------------------------------------------------
// Instantiations
//--------------------------------------------------------------------------
//--------------------------------------------------------------------------
// Module code
//--------------------------------------------------------------------------
// This is the CLOCK_FACTOR_PP prescaler and also mid_bit_count counter
assign
enable_clock_count
=
measure
||
(
verify
&&
main_count_rollover
)
;
always
@
(
posedge
clk_i
or
posedge
reset_i
)
begin
if
(
reset_i
)
clock_count
<=
0
;
else
if
(
clear_counters
)
clock_count
<=
0
;
else
if
(
enable_clock_count
)
begin
// Must have been clk_i edge
if
(
clock_count_rollover
)
clock_count
<=
0
;
else
clock_count
<=
clock_count
+
1
;
end
end
// Counter rollover condition
assign
clock_count_rollover
=
(
clock_count
==
(
CLOCK_FACTOR_PP
-
1
))
;
// This condition signals the middle of a bit time, for use during the
// verify stage. Also, this signal is used to advance the main count,
// instead of "clock_count_rollover." This produces an effective "rounding"
// operation for the measurement (which would otherwise "truncate" any
// fraction of time contained in this counter at the instant the measurement
// is finished.
// (The "enable_clock_count" is included in order to make the pulse narrow,
// only one clock wide...)
assign
mid_bit_count
=
(
(
clock_count
==
((
CLOCK_FACTOR_PP
>>
1
)
-
1
))
&&
enable_clock_count
)
;
// This is the main counter. During measurement, it advances once for
// each CLOCK_FACTOR_PP cycles of clk_i. This accumulated measurement
// is then latched into "measurement" when the state machine determines that
// the measurement interval is finished.
// During verify and idle_run times (whenever the baud rate clock is used)
// this counter is allowed to run freely, advancing once each clk_i, but being
// reset when it reaches a total count of "measurement" clock cycles. The
// signal that reset the counter during this type of operation is the baud
// rate clock.
always
@
(
posedge
clk_i
or
posedge
reset_i
)
begin
if
(
reset_i
)
main_count
<=
0
;
else
// must have been clk_i edge
begin
// Clear main count when measurement is done
if
(
clear_counters
)
main_count
<=
0
;
// If measuring, advance once per CLOCK_FACTOR_PP clk_i pulses.
else
if
(
measure
&&
mid_bit_count
)
main_count
<=
main_count
+
1
;
// If verifying or running, check reset conditions,
// otherwise advance always.
else
if
(
verify
||
run
)
begin
if
(
main_count_rollover
)
main_count
<=
0
;
else
main_count
<=
main_count
+
1
;
end
end
end
// This is a shift register used to provide "target" character bits one at
// a time for verification as they are "received" (sampled) using the
// candidate baud clock.
always
@
(
posedge
clk_i
or
posedge
reset_i
)
begin
if
(
reset_i
)
target_bits
<=
`TEMPLATE_BITS
;
else
// must have been a clock edge
begin
if
(
~
verify
)
target_bits
<=
`TEMPLATE_BITS
;
if
(
verify
&&
mid_bit_count
)
target_bits
<=
{
0
,
(
target_bits
>>
1
)
};
end
end
// It is done when only the stop bit is left in the shift register.
assign
verify_done
=
(
(
target_bits
==
1
)
&&
verify
&&
mid_bit_count
)
;
// This is a flip-flop used to keep track of whether the verify operation
// is succeeding or not. Any target bits that do not match the received
// data at the sampling edge, will cause the verify_failed bit to go high.
// This is what the state machine looks at to determine whether it passed
// or not.
always
@
(
posedge
clk_i
or
posedge
reset_i
)
begin
if
(
reset_i
)
character_miscompare
<=
0
;
else
// Must have been a clock edge
begin
if
(
idle
)
character_miscompare
<=
0
;
if
(
verify
&&
mid_bit_count
&&
(
target_bits
[
0
]
^
serial_dat_i
))
character_miscompare
<=
1
;
end
end
// This is the measurement storage latch. The final measured time count
// from main_count is stored in this latch upon completion of the measurement
// interval. The value stored in this latch is used whenever the baud clock
// is being generated, to reset the main count (causing a "rollover").
always
@
(
posedge
clk_i
or
posedge
idle
)
begin
// Set to all ones during idle (asynchronous).
if
(
idle
)
measurement
<=
-
1
;
// Otherwise, there must have been a clk_i edge
// When the measurement is done, the counters are cleared, and the time
// interval must be stored before it is cleared away...
// This also causes a store following a failed verify state on the way back
// into idle, but the idle state clears out the false measurement anyway.
else
if
(
clear_counters
)
measurement
<=
(
main_count
>>
1
)
;
end
// This is effectively the baud clock signal
// But it is prevented from reaching the output pin during verification...
// It is only allowed out of the module during idle_run state.
assign
main_count_rollover
=
(
main_count
==
measurement
)
;
assign
baud_clk_o
=
(
main_count_rollover
&&
run
)
;
// This is state machine m1. It checks the status of the serial_dat_i line
// and coordinates the measurement of the time interval of the first two
// bits of the received character, which is the "measurement interval."
// Following the measurement interval, the state machine enters a new
// phase of bit verification. If the measured time interval is accurate
// enough to measure the remaining 8 bits of the character correctly, then
// the measurement is accepted, and the baud rate clock is driven onto
// the baud_clk_o output pin. Incidentally, the process of verification
// effectively filters out all characters which are not the desired target
// character for measurement. In this case, the target character is the
// carriage return.
// State register
always
@
(
posedge
clk_i
or
posedge
reset_i
)
begin
:
m1_state_register
if
(
reset_i
)
m1_state
<=
m1_idle
;
// asynchronous reset
else
m1_state
<=
m1_next_state
;
end
// State transition logic
always
@
(
m1_state
or
mid_bit_count
or
serial_dat_i
or
verify_done
or
character_miscompare
)
begin
:
m1_state_logic
// Default values for outputs. The individual states can override these.
idle
<=
1'b0
;
run
<=
1'b0
;
measure
<=
1'b0
;
clear_counters
<=
1'b0
;
verify
<=
1'b0
;
case
(
m1_state
)
// synthesis parallel_case
m1_idle
:
begin
idle
<=
1'b1
;
if
(
serial_dat_i
==
0
)
m1_next_state
<=
m1_measure_0
;
else
m1_next_state
<=
m1_idle
;
end
m1_measure_0
:
begin
measure
<=
1'b1
;
// Check at mid bit time, to make sure serial line is still low...
// (At this time, "mid_bit_count" is simply CLOCK_FACTOR_PP>>1 clk_i's.)
if
(
mid_bit_count
&&
~
serial_dat_i
)
m1_next_state
<=
m1_measure_1
;
// If it is not low, then it must have been a "glitch"...
else
if
(
mid_bit_count
&&
serial_dat_i
)
m1_next_state
<=
m1_idle
;
else
m1_next_state
<=
m1_measure_0
;
end
m1_measure_1
:
begin
measure
<=
1'b1
;
// Look for first data bit (high).
if
(
serial_dat_i
)
m1_next_state
<=
m1_measure_2
;
// If it is not high keep waiting...
// (Put detection of measurement overflow in here if necessary...)
else
m1_next_state
<=
m1_measure_1
;
end
m1_measure_2
:
begin
measure
<=
1'b1
;
// Check using mid bit time, to make sure serial line is still high...
// (At this time, "mid_bit_count" is simply CLOCK_FACTOR_PP>>1 clk_i's.)
if
(
mid_bit_count
&&
serial_dat_i
)
m1_next_state
<=
m1_measure_3
;
// If it is not high, then it must have been a "glitch"...
else
if
(
mid_bit_count
&&
~
serial_dat_i
)
m1_next_state
<=
m1_idle
;
else
m1_next_state
<=
m1_measure_2
;
end
m1_measure_3
:
begin
measure
<=
1'b1
;
// Look for end of measurement interval (low)
if
(
!
serial_dat_i
)
m1_next_state
<=
m1_measure_4
;
// If it is not high keep waiting...
// (Put detection of measurement overflow in here if necessary...)
else
m1_next_state
<=
m1_measure_3
;
end
// This state outputs a reset pulse, to clear counters and store the
// measurement from main_count.
m1_measure_4
:
begin
clear_counters
<=
1'b1
;
// Clears counters, stores measurement
m1_next_state
<=
m1_verify_0
;
end
m1_verify_0
:
// Wait for verify operations to finish
begin
verify
<=
1'b1
;
if
(
verify_done
)
m1_next_state
<=
m1_verify_1
;
else
m1_next_state
<=
m1_verify_0
;
end
// NOTE: This "extra" state is needed because the character_miscompare
// information is not valid until 1 cycle after verify_done is
// active.
m1_verify_1
:
// Checks for character miscompare
begin
if
(
character_miscompare
)
m1_next_state
<=
m1_verify_failed
;
else
m1_next_state
<=
m1_run
;
end
m1_verify_failed
:
// Resets counters on the way back to idle
begin
clear_counters
<=
1'b1
;
m1_next_state
<=
m1_idle
;
end
// This state is for successful verification results!
// Since this is a single measurement unit, only reset can exit this
// state.
m1_run
:
begin
run
<=
1'b1
;
m1_next_state
<=
m1_run
;
end
default
:
m1_next_state
<=
m1_idle
;
endcase
end
assign
auto_baud_locked_o
=
run
;
endmodule
//
`undef
LOG2_MAX_CLOCK_FACTOR
\ No newline at end of file
hdl/modules/dbe_wishbone/wb_rs232_syscon/rs232_syscon.pdf
0 → 100644
View file @
4eaaadf0
File added
hdl/modules/dbe_wishbone/wb_rs232_syscon/rs232_syscon.v
0 → 100644
View file @
4eaaadf0
//-------------------------------------------------------------------------------------
//
// Author: John Clayton
// Date : June 25, 2001
// Update: 6/25/01 copied this file from ps2_mouse.v (pared down).
// Update: 6/07/01 Finished initial coding efforts.
// Update: 7/19/01 First compilation. Added master_br_o and master_bg_i;
// Update: 7/25/01 Testing. Eliminated msg_active signal. Changed serial.v
// to reflect new handshaking (i.e. "load_request" is now a
// periodic pulse of tx_clk_1x from rs232_tx...)
// Update: 7/30/01 Began coding m2 state machine. Defined response codes.
// Update: 8/01/01 After some testing with m2, merged m2 into m1. Eliminated
// response codes.
// Update: 8/02/01 Tested & measured the single "combined" state machine's
// performance, and "it was found wanting." (The 49.152MHz
// clock frequency was too fast for it...) Created clk_s
// at 49.152/2 MHz, and this worked.
// Update: 8/03/01 Added counter loop to "execute" and "bus_granted" states
// so that multiple bus cycles are generated, at sequential
// addresses. However, the qty field is not cleared before
// being loaded with new characters, which causes problems.
// Update: 8/07/01 Finished debugging. The read print formatting is now
// correct, and the unit appears to operate correctly.
// Many hours were spent puzzling over how to make this work.
// Removed port "debug".
// Update: 8/24/01 Added "master_stb_i" and "master_we_i" inputs and logic.
// Update: 12/13/01 For memory_sizer.v, I lowered the frequency of clk_s down
// to 49.152/4 MHz, so I changed the CLOCK_FACTOR from 8 to 4
// on the rs232 transciever, and this worked fine.
// Update: 9/09/02 Incorporated the "autobaud_with_tracking" module so that
// the serial clock is generated automatically, no matter
// what frequency clk_i is used. The user simply needs to
// press "enter" from the terminal program to synchronize
// the baud rate generator. Changing BAUD rates on the fly
// is also permitted, simply change to a new BAUD rate in the
// terminal program and hit enter.
//
//
//
//
//
// Description
//-------------------------------------------------------------------------------------
// This is a state-machine driven rs232 serial port interface to a "Wishbone"
// type of bus. It is intended to be used as a "Wishbone system controller"
// for debugging purposes. Specifically, the unit allows the user to send
// text commands to the "rs232_syscon" unit, in order to generate read and
// write cycles on the Wishbone compatible bus. The command structure is
// quite terse and spartan in nature, this is for the sake of the logic itself.
// Because the menu-driven command structure is supported without the use of
// dedicated memory blocks (in order to maintain cross-platform portability
// as much as possible) the menus and command responses were kept as small
// as possible. In most cases, the responses from the unit to the user
// consist of a "newline" and one or two visible characters. The command
// structure consists of the following commands and responses:
//
// Command Syntax Purpose
// --------------- ---------------------------------------
// w aaaa dddd xx Write data "dddd" starting at address "aaaa"
// perform this "xx" times at sequential addresses.
// (The quantity field is optional, default is 1).
// r aaaa xx Read data starting from address "aaaa."
// Perform this "xx" times at sequential addresses.
// (The quantity field is optional, default is 1).
// i Send a reset pulse to the system. (initialize).
//
// Response from rs232_syscon Meaning
// -------------------------- ---------------------------------------
// OK Command received and performed. No errors.
// ? Command buffer full, without receiving "enter."
// C? Command not recognized.
// A? Address field syntax error.
// D? Data field syntax error.
// Q? Quantity field syntax error.
// ! No "ack_i", or else "err_i" received from bus.
// B! No "bg_i" received from master.
//
// NOTES on the operation of this unit:
//
// - The unit generates a command prompt which is "-> ".
// - Capitalization is not important.
// - Each command is terminated by the "enter" key (0x0d character).
// Commands are executed as soon as "enter" is received.
// - Trailing parameters need not be re-entered. Their values will
// remain the same as their previous settings.
// - Use of the backspace key is supported, so mistakes can be corrected.
// - The length of the command line is limited to a fixed number of
// characters, as configured by parameter.
// - Fields are separated by white space, including "tab" and/or "space"
// - All numerical fields are interpreted as hexadecimal numbers.
// Decimal is not supported.
// - Numerical field values are retained between commands. If a "r" is issued
// without any fields following it, the previous values will be used. A
// set of "quantity" reads will take place at sequential addresses.
// If a "w" is issued without any fields following it, the previous data
// value will be written "quantity" times at sequential addresses, starting
// from the next location beyond where the last command ended.
// - If the user does not wish to use "ack" functionality, simply tie the
// "ack_i" input to 1b'1, and then the ! response will never be generated.
// - The data which is read in by the "r" command is displayed using lines
// which begin with the address, followed by the data fields. The number
// of data fields displayed per line (following the address) is adjustable
// by setting a parameter. No other display format adjustments can be made.
// - There is currently only a single watchdog timer. It begins to count at
// the time a user hits "enter" to execute a command. If the bus is granted
// and the ack is received before the expiration of the timer, then the
// cycle will complete normally. Therefore, the watchdog timeout value
// needs to include time for the request and granting of the bus, in
// addition to the time needed for the actual bus cycle to complete.
//
//
// Currently, there is only a single indicator (stb_o) generated during bus
// output cycles which are generated from this unit.
// The user can easily implement decoding logic based upon adr_o and stb_o
// which would serve as multiple "stb_o" type signals for different cores
// which would be sharing the same bus.
//
// The dat_io bus supported by this module is a tri-state type of bus. The
// Wishbone spec. allows for this type of bus (see Wishbone spec. pg. 66).
// However, if separate dat_o and dat_i busses are desired, they can be added
// to the module without too much trouble. Supposedly the only difference
// between the two forms of data bus is that one of them avoids using tri-state
// at the cost of doubling the number of interconnects used to carry data back
// and forth... Some people say that tri-state should be avoided for use
// in internal busses in ASICs. Maybe they are right.
// But in FPGAs tri-state seems to work pretty well, even for internal busses.
//
// Parameters are provided to configure the width of the different command
// fields. To simplify the logic for binary to hexadecimal conversion, these
// parameters allow adjustment in units of 1 hex digit, not anything smaller.
// If your bus has 10 bits, for instance, simply set the address width to 3
// which produces 12 bits, and then just don't use the 2 msbs of address
// output.
//
// No support for the optional Wishbone "retry" (rty_i) input is provided at
// this time.
// No support for "tagn_o" bits is provided at this time, although a register
// might be added external to this module in order to implement to tag bits.
// No BLOCK or RMW cycles are supported currently, so cyc_o is equivalent to
// stb_o...
// The output busses are not tri-stated. The user may add tri-state buffers
// external to the module, using "stb_o" to enable the buffer outputs.
//
//-------------------------------------------------------------------------------------
`define
NIBBLE_SIZE 4
//
Number of bits in one nibble
// The command register has these values
`define
CMD_0 0
//
Unused command
`define
CMD_I 1
//
Initialize
(
or reset
)
`define
CMD_R 2
//
Read
`define
CMD_W 3
//
Write
module
rs232_syscon
(
clk_i
,
reset_i
,
ack_i
,
err_i
,
master_bg_i
,
master_adr_i
,
master_stb_i
,
master_we_i
,
rs232_rxd_i
,
data_in
,
data_out
,
//dat_io,
rst_o
,
master_br_o
,
stb_o
,
cyc_o
,
adr_o
,
we_o
,
rs232_txd_o
)
;
// Parameters
// The timer value can be from [0 to (2^WATCHDOG_TIMER_BITS_PP)-1] inclusive.
// RD_FIELDS_PP can be from [0 to (2^RD_FIELD_CTR_BITS_PP)-1] inclusive.
// Ensure that (2^CHAR_COUNT_BITS_PP) >= CMD_BUFFER_SIZE_PP.
// The setting of CMD_BUFFER_SIZE_PP should be large enough to hold the
// largest command, obviously.
// Ensure that (2^RD_DIGIT_COUNT_BITS_PP) is greater than or equal to the
// larger of {ADR_DIGITS_PP,DAT_DIGITS_PP}.
parameter
ADR_DIGITS_PP
=
8
;
// # of hex digits for address.
parameter
DAT_DIGITS_PP
=
8
;
// # of hex digits for data.
parameter
QTY_DIGITS_PP
=
2
;
// # of hex digits for quantity.
parameter
CMD_BUFFER_SIZE_PP
=
64
;
// # of chars in the command buffer.
parameter
CMD_PTR_BITS_PP
=
5
;
// # of Bits in command buffer ptr.
parameter
WATCHDOG_TIMER_VALUE_PP
=
65000
;
//200; // # of sys_clks before ack expected.
parameter
WATCHDOG_TIMER_BITS_PP
=
16
;
//8; // # of bits needed for timer.
parameter
RD_FIELDS_PP
=
8
;
// # of fields/line (when qty > 1).
parameter
RD_FIELD_COUNT_BITS_PP
=
4
;
// # of bits in the fields counter.
parameter
RD_DIGIT_COUNT_BITS_PP
=
4
;
// # of bits in the digits counter.
// State encodings, provided as parameters
// for flexibility to the one instantiating the module.
// In general, the default values need not be changed.
// There is one state machines: m1.
// "default" state upon power-up and configuration is:
// "m1_initial_state"
parameter
m1_initial_state
=
5'h00
;
parameter
m1_send_ok
=
5'h01
;
// Sends OK
parameter
m1_send_prompt
=
5'h02
;
// Sends "-> "
parameter
m1_check_received_char
=
5'h03
;
parameter
m1_send_crlf
=
5'h04
;
// Sends cr,lf
parameter
m1_parse_error_indicator_crlf
=
5'h05
;
// Sends cr,lf
parameter
m1_parse_error_indicator
=
5'h06
;
// Sends ?
parameter
m1_ack_error_indicator
=
5'h07
;
// Sends !
parameter
m1_bg_error_indicator
=
5'h08
;
// Sends B!
parameter
m1_cmd_error_indicator
=
5'h09
;
// Sends C?
parameter
m1_adr_error_indicator
=
5'h0a
;
// Sends A?
parameter
m1_dat_error_indicator
=
5'h0b
;
// Sends D?
parameter
m1_qty_error_indicator
=
5'h0c
;
// Sends Q?
parameter
m1_scan_command
=
5'h10
;
parameter
m1_scan_adr_whitespace
=
5'h11
;
parameter
m1_get_adr_field
=
5'h12
;
parameter
m1_scan_dat_whitespace
=
5'h13
;
parameter
m1_get_dat_field
=
5'h14
;
parameter
m1_scan_qty_whitespace
=
5'h15
;
parameter
m1_get_qty_field
=
5'h16
;
parameter
m1_start_execution
=
5'h17
;
parameter
m1_request_bus
=
5'h18
;
parameter
m1_bus_granted
=
5'h19
;
parameter
m1_execute
=
5'h1a
;
parameter
m1_rd_send_adr_sr
=
5'h1b
;
parameter
m1_rd_send_separator
=
5'h1c
;
parameter
m1_rd_send_dat_sr
=
5'h1d
;
parameter
m1_rd_send_space
=
5'h1e
;
parameter
m1_rd_send_crlf
=
5'h1f
;
// I/O declarations
input
clk_i
;
// System clock input
input
reset_i
;
// Reset signal for this module
input
ack_i
;
// Ack input from Wishbone "slaves"
input
err_i
;
// Err input from Wishbone "slaves"
input
master_bg_i
;
// Bus Grant (grants this module the bus)
// Address bus input from "normal" Wishbone
// master (i.e. from processor)
input
[
`NIBBLE_SIZE
*
ADR_DIGITS_PP
-
1
:
0
]
master_adr_i
;
input
master_stb_i
;
// bus cycle signal from "normal" bus master
input
master_we_i
;
// write enable from "normal" bus master
input
rs232_rxd_i
;
// Serial data from debug host terminal.
// Data bus (tri-state, to save interconnect)
//inout [`NIBBLE_SIZE*DAT_DIGITS_PP-1:0] dat_io;
input
[
`NIBBLE_SIZE
*
DAT_DIGITS_PP
-
1
:
0
]
data_in
;
output
[
`NIBBLE_SIZE
*
DAT_DIGITS_PP
-
1
:
0
]
data_out
;
output
rst_o
;
// Rst output to Wishbone "slaves"
output
master_br_o
;
// Bus request to normal master device.
output
stb_o
;
// Bus cycle indicator to Wishbone "slaves"
output
cyc_o
;
// Bus cycle indicator to Wishbone "slaves"
// Address bus output to Wishbone "slaves"
output
[
`NIBBLE_SIZE
*
ADR_DIGITS_PP
-
1
:
0
]
adr_o
;
output
we_o
;
// Write enable to Wishbone "slaves"
output
rs232_txd_o
;
// Serial transmit data to debug host terminal
reg
rst_o
;
reg
master_br_o
;
// Internal signal declarations
wire
watchdog_timer_done
;
// High when watchdog timer is expired
wire
rd_addr_field_done
;
// High when displayed addr field is complete
wire
rd_data_field_done
;
// High when displayed data field is complete
wire
rd_line_done
;
// High when displayed line is complete
wire
char_is_enter
;
// High when cmd_buffer[char_count] is enter.
wire
char_is_whitespace
;
// High when cmd_buffer[char_count] is whitespace.
wire
char_is_num
;
// High when cmd_buffer[char_count] is 0..9
wire
char_is_a_f
;
// High when cmd_buffer[char_count] is a..f
wire
char_is_hex
;
// High when cmd_buffer[char_count] is a hex char.
wire
char_is_r
;
// High when cmd_buffer[char_count] is r.
wire
char_is_w
;
// High when cmd_buffer[char_count] is w.
wire
char_is_i
;
// High when cmd_buffer[char_count] is i.
wire
rx_char_is_enter
;
// High when rs232_rx_char is enter.
wire
rx_char_is_backspace
;
// High when rs232_rx_char is backspace.
wire
[
4
:
0
]
msg_pointer
;
// Determines message position or address.
wire
[
3
:
0
]
hex_digit
;
// This is the digit to be stored.
reg
rs232_echo
;
// High == echo char's received.
reg
[
7
:
0
]
msg_char
;
// Selected response message character.
reg
[
4
:
0
]
msg_base
;
// Added to msg_offset to form msg_pointer.
reg
[
4
:
0
]
msg_offset
;
// Offset from start of message.
reg
reset_msg_offset
;
// High == set message offset to zero
reg
incr_msg_offset
;
// Used for output messages.
reg
cmd_i
;
// Sets command.
reg
cmd_r
;
// Sets command.
reg
cmd_w
;
// Sets command.
reg
shift_rd_adr
;
// Shifts the rd_adr_sr by one character.
reg
store_adr
;
// Allows adr_sr to store hex_digit.
reg
store_dat
;
// Allows dat_sr to store hex_digit.
reg
store_qty
;
// Allows qty_sr to store hex_digit.
reg
reset_adr
;
// Clears adr_sr
reg
reset_dat
;
// Clears dat_sr
reg
reset_qty
;
// Clears qty_sr
reg
init_qty
;
// Sets qty_sr to 1
reg
capture_dat
;
// Puts dat_io into dat_sr for later display.
// For the buses
wire
[
`NIBBLE_SIZE
*
ADR_DIGITS_PP
-
1
:
0
]
adr_ptr
;
// = adr_sr + adr_offset
reg
stb_l
;
// "local" stb signal (to distinguish from stb_o)
reg
we_l
;
// "local" we signal (to distinguish from we_o)
reg
[
`NIBBLE_SIZE
*
ADR_DIGITS_PP
-
1
:
0
]
rd_adr_sr
;
// sr for printing addresses
reg
[
`NIBBLE_SIZE
*
ADR_DIGITS_PP
-
1
:
0
]
adr_sr
;
// "nibble" shift register
reg
[
`NIBBLE_SIZE
*
DAT_DIGITS_PP
-
1
:
0
]
dat_sr
;
// "nibble" shift register
reg
[
`NIBBLE_SIZE
*
QTY_DIGITS_PP
-
1
:
0
]
qty_sr
;
// "nibble" shift register
reg
[
1
:
0
]
command
;
reg
[
`NIBBLE_SIZE
*
QTY_DIGITS_PP
-
1
:
0
]
adr_offset
;
// counts from 0 to qty_sr
reg
reset_adr_offset
;
reg
incr_adr_offset
;
// For the command buffer
reg
[
CMD_PTR_BITS_PP
-
1
:
0
]
cmd_ptr
;
// Offset from start of command.
reg
reset_cmd_ptr
;
// High == set command pointer to zero.
reg
incr_cmd_ptr
;
// Used for "write port" side of the command buffer
reg
decr_cmd_ptr
;
// Used for "write port" side of the command buffer
reg
cmd_buffer_write
;
reg
[
7
:
0
]
cmd_buffer
[
0
:
CMD_BUFFER_SIZE_PP
-
1
]
;
wire
[
7
:
0
]
cmd_char
;
wire
[
7
:
0
]
lc_cmd_char
;
// Lowercase version of cmd_char
// For the state machine
reg
[
4
:
0
]
m1_state
;
reg
[
4
:
0
]
m1_next_state
;
// For various counters
reg
reset_rd_field_count
;
reg
reset_rd_digit_count
;
reg
incr_rd_field_count
;
reg
incr_rd_digit_count
;
reg
[
RD_FIELD_COUNT_BITS_PP
-
1
:
0
]
rd_field_count
;
// "fields displayed"
reg
[
RD_DIGIT_COUNT_BITS_PP
-
1
:
0
]
rd_digit_count
;
// "digits displayed"
reg
[
WATCHDOG_TIMER_BITS_PP
-
1
:
0
]
watchdog_timer_count
;
reg
reset_watchdog
;
// For the rs232 interface
wire
serial_clk
;
wire
[
2
:
0
]
rs232_rx_error
;
wire
rs232_tx_load
;
wire
rs232_tx_load_request
;
wire
rs232_rx_data_ready
;
wire
[
7
:
0
]
rs232_rx_char
;
wire
[
7
:
0
]
rs232_tx_char
;
// Either rs232_rx_char or msg_char
//--------------------------------------------------------------------------
// Instantiations
//--------------------------------------------------------------------------
// These defines are for the rs232 interface
`define
START_BITS 1
`define
DATA_BITS 8
`define
STOP_BITS 1
`define
CLOCK_FACTOR 8
// This module generates a serial BAUD clock automatically.
// The unit synchronizes on the carriage return character, so the user
// only needs to press the "enter" key for serial communications to start
// working, no matter what BAUD rate and clk_i frequency are used!
auto_baud
#(
`CLOCK_FACTOR
,
// CLOCK_FACTOR_PP
16
// LOG2_MAX_COUNT_PP
)
clock_unit_2
(
.
clk_i
(
clk_i
)
,
.
reset_i
(
reset_i
)
,
.
serial_dat_i
(
rs232_rxd_i
)
,
.
auto_baud_locked_o
()
,
.
baud_clk_o
(
serial_clk
)
)
;
/*
auto_baud_with_tracking #(
`CLOCK_FACTOR, // CLOCK_FACTOR_PP
16 // LOG2_MAX_COUNT_PP
)
clock_unit_2
(
.clk_i(clk_i),
.reset_i(reset_i),
.serial_dat_i(rs232_rxd_i),
.auto_baud_locked_o(),
.baud_clk_o(serial_clk)
);
*/
// A transmitter, which asserts load_request at the end of the currently
// transmitted word. The tx_clk must be a "clock enable" (narrow positive
// pulse) which occurs at 16x the desired transmit rate. If load_request
// is connected directly to load, the unit will transmit continuously.
rs232tx
#(
`START_BITS
,
// start_bits
`DATA_BITS
,
// data_bits
`STOP_BITS
,
// stop_bits (add intercharacter delay...)
`CLOCK_FACTOR
// clock_factor
)
rs232_tx_block
// instance name
(
.
clk
(
clk_i
)
,
.
tx_clk
(
serial_clk
)
,
.
reset
(
reset_i
)
,
.
load
(
rs232_tx_load
)
,
.
data
(
rs232_tx_char
)
,
.
load_request
(
rs232_tx_load_request
)
,
.
txd
(
rs232_txd_o
)
)
;
// A receiver, which asserts "word_ready" to indicate a received word.
// Asserting "read_word" will cause "word_ready" to go low again if it was high.
// The character is held in the output register, during the time the next
// character is coming in.
rs232rx
#(
`START_BITS
,
// start_bits
`DATA_BITS
,
// data_bits
`STOP_BITS
,
// stop_bits
`CLOCK_FACTOR
// clock_factor
)
rs232_rx_block
// instance name
(
.
clk
(
clk_i
)
,
.
rx_clk
(
serial_clk
)
,
.
reset
(
reset_i
||
(
|
rs232_rx_error
))
,
.
rxd
(
rs232_rxd_i
)
,
.
read
(
rs232_tx_load
)
,
.
data
(
rs232_rx_char
)
,
.
data_ready
(
rs232_rx_data_ready
)
,
.
error_over_run
(
rs232_rx_error
[
0
])
,
.
error_under_run
(
rs232_rx_error
[
1
])
,
.
error_all_low
(
rs232_rx_error
[
2
])
)
;
//`undef START_BITS
//`undef DATA_BITS
//`undef STOP_BITS
//`undef CLOCK_FACTOR
//--------------------------------------------------------------------------
// Module code
//--------------------------------------------------------------------------
assign
adr_o
=
master_bg_i
?
adr_ptr
:
master_adr_i
;
assign
we_o
=
master_bg_i
?
we_l
:
master_we_i
;
assign
stb_o
=
master_bg_i
?
stb_l
:
master_stb_i
;
//assign dat_io = (master_bg_i && we_l && stb_l)?
//dat_sr:{`NIBBLE_SIZE*DAT_DIGITS_PP{1'bZ}};
assign
data_out
=
(
master_bg_i
&&
we_l
&&
stb_l
)
?
dat_sr:
{
`NIBBLE_SIZE
*
DAT_DIGITS_PP
{
1
'
bZ
}};
//assign data_in = (master_bg_i && we_l && stb_l)?
// dat_sr:{`NIBBLE_SIZE*DAT_DIGITS_PP{1'bZ}};
// Temporary
assign
cyc_o
=
stb_o
;
// Separate cyc_o is not yet supported!
// This is the adress offset counter
always
@
(
posedge
clk_i
)
begin
if
(
reset_i
||
reset_adr_offset
)
adr_offset
<=
0
;
else
if
(
incr_adr_offset
)
adr_offset
<=
adr_offset
+
1
;
end
// This forms the adress pointer which is used on the bus.
assign
adr_ptr
=
adr_sr
+
adr_offset
;
// This is the ROM for the ASCII characters to be transmitted.
always
@
(
msg_pointer
)
begin
case
(
msg_pointer
)
// synthesis parallel_case
5'b00000
:
msg_char
<=
"0"
;
// Hexadecimal characters
5'b00001
:
msg_char
<=
"1"
;
5'b00010
:
msg_char
<=
"2"
;
5'b00011
:
msg_char
<=
"3"
;
5'b00100
:
msg_char
<=
"4"
;
5'b00101
:
msg_char
<=
"5"
;
5'b00110
:
msg_char
<=
"6"
;
5'b00111
:
msg_char
<=
"7"
;
5'b01000
:
msg_char
<=
"8"
;
5'b01001
:
msg_char
<=
"9"
;
5'b01010
:
msg_char
<=
"A"
;
// Address error indication
5'b01011
:
msg_char
<=
"B"
;
5'b01100
:
msg_char
<=
"C"
;
// Command error indication
5'b01101
:
msg_char
<=
"D"
;
// Data error indication
5'b01110
:
msg_char
<=
"E"
;
5'b01111
:
msg_char
<=
"F"
;
5'b10000
:
msg_char
<=
" "
;
// Space
5'b10001
:
msg_char
<=
":"
;
// Colon
5'b10010
:
msg_char
<=
" "
;
// Space
5'b10011
:
msg_char
<=
"?"
;
// Parse error indication
5'b10100
:
msg_char
<=
"!"
;
// ack_i/err_i error indication
5'b10101
:
msg_char
<=
"O"
;
// "All is well" message
5'b10110
:
msg_char
<=
"K"
;
5'b10111
:
msg_char
<=
8'h0d
;
// Carriage return & line feed
5'b11000
:
msg_char
<=
8'h0a
;
5'b11001
:
msg_char
<=
"-"
;
// Command Prompt
5'b11010
:
msg_char
<=
">"
;
5'b11011
:
msg_char
<=
" "
;
5'b11100
:
msg_char
<=
"Q"
;
// Quantity error indication
default
:
msg_char
<=
"="
;
endcase
end
// This logic determines when to load a transmit character.
assign
rs232_tx_load
=
rs232_echo
?
(
rs232_rx_data_ready
&&
rs232_tx_load_request
)
:
rs232_tx_load_request
;
// This is the counter for incrementing, decrementing or resetting the
// message pointer.
always
@
(
posedge
clk_i
)
begin
if
(
reset_i
||
reset_msg_offset
)
msg_offset
<=
0
;
else
if
(
incr_msg_offset
)
msg_offset
<=
msg_offset
+
1
;
end
assign
msg_pointer
=
msg_offset
+
msg_base
;
// This is the mux which selects whether to echo back the characters
// received (as during the entering of a command) or to send back response
// characters.
assign
rs232_tx_char
=
(
rs232_echo
)
?
rs232_rx_char
:
msg_char
;
// These assigments are for detecting whether the received rs232 character is
// anything of special interest.
assign
rx_char_is_enter
=
(
rs232_rx_char
==
8'h0d
)
;
assign
rx_char_is_backspace
=
(
rs232_rx_char
==
8'h08
)
;
// This is state machine m1. It handles receiving the command line, including
// backspaces, and prints error/response messages. It also parses and
// executes the commands.
// State register
always
@
(
posedge
clk_i
)
begin
:
m1_state_register
if
(
reset_i
)
m1_state
<=
m1_initial_state
;
// perform reset for rest of system
else
m1_state
<=
m1_next_state
;
end
// State transition logic
always
@
(
m1_state
or
rx_char_is_enter
or
rx_char_is_backspace
or
msg_offset
or
cmd_ptr
or
rs232_tx_load
or
char_is_whitespace
or
char_is_hex
or
char_is_enter
or
char_is_i
or
char_is_r
or
char_is_w
or
command
or
master_bg_i
or
watchdog_timer_done
or
err_i
or
ack_i
or
adr_offset
or
qty_sr
or
dat_sr
or
rd_adr_sr
or
rd_field_count
or
rd_digit_count
)
begin
:
m1_state_logic
// Default values for outputs. The individual states can override these.
msg_base
<=
5'b0
;
reset_msg_offset
<=
0
;
incr_msg_offset
<=
0
;
rs232_echo
<=
0
;
rst_o
<=
0
;
we_l
<=
0
;
stb_l
<=
0
;
cmd_buffer_write
<=
0
;
reset_cmd_ptr
<=
0
;
incr_cmd_ptr
<=
0
;
decr_cmd_ptr
<=
0
;
master_br_o
<=
0
;
cmd_r
<=
0
;
cmd_w
<=
0
;
cmd_i
<=
0
;
shift_rd_adr
<=
0
;
store_adr
<=
0
;
// enables storing hex chars in adr_sr (shift)
store_dat
<=
0
;
// enables storing hex chars in dat_sr (shift)
store_qty
<=
0
;
// enables storing hex chars in qty_sr (shift)
reset_adr
<=
0
;
reset_dat
<=
0
;
reset_qty
<=
0
;
init_qty
<=
0
;
capture_dat
<=
0
;
// enables capturing bus data in dat_sr (load)
incr_adr_offset
<=
0
;
reset_adr_offset
<=
0
;
reset_watchdog
<=
0
;
incr_rd_field_count
<=
0
;
incr_rd_digit_count
<=
0
;
reset_rd_field_count
<=
0
;
reset_rd_digit_count
<=
0
;
case
(
m1_state
)
// synthesis parallel_case
m1_initial_state
:
begin
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
15
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_send_prompt
;
reset_msg_offset
<=
1
;
end
else
m1_next_state
<=
m1_initial_state
;
end
m1_send_ok
:
begin
msg_base
<=
5'b10101
;
// Address of the OK message
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
1
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_send_prompt
;
reset_msg_offset
<=
1
;
end
else
m1_next_state
<=
m1_send_ok
;
end
m1_send_prompt
:
begin
msg_base
<=
5'b10111
;
// Address of the cr,lf,prompt message
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
4
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_check_received_char
;
reset_cmd_ptr
<=
1
;
end
else
m1_next_state
<=
m1_send_prompt
;
end
// This state always leads to activating the parser...
m1_send_crlf
:
begin
msg_base
<=
5'b10111
;
// Address of the cr/lf message
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
1
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_scan_command
;
reset_cmd_ptr
<=
1
;
end
else
m1_next_state
<=
m1_send_crlf
;
end
m1_check_received_char
:
begin
rs232_echo
<=
1
;
// Allow echoing of characters
if
(
rx_char_is_backspace
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_check_received_char
;
decr_cmd_ptr
<=
1
;
// This effectively eliminates the last char
end
else
if
(
rx_char_is_enter
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_send_crlf
;
cmd_buffer_write
<=
1
;
// Store the enter as "marker" for parsing
reset_msg_offset
<=
1
;
end
else
if
(
rs232_tx_load
&&
(
cmd_ptr
==
CMD_BUFFER_SIZE_PP
-
1
))
begin
m1_next_state
<=
m1_parse_error_indicator_crlf
;
reset_msg_offset
<=
1
;
reset_cmd_ptr
<=
1
;
end
else
if
(
rs232_tx_load
)
begin
incr_cmd_ptr
<=
1
;
cmd_buffer_write
<=
1
;
m1_next_state
<=
m1_check_received_char
;
end
else
m1_next_state
<=
m1_check_received_char
;
end
m1_bg_error_indicator
:
begin
msg_base
<=
5'b01011
;
// Address of the B character
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
0
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_ack_error_indicator
;
reset_msg_offset
<=
1
;
end
else
m1_next_state
<=
m1_bg_error_indicator
;
end
m1_ack_error_indicator
:
begin
msg_base
<=
5'b10100
;
// Address of the ! error message
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
0
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_send_prompt
;
reset_msg_offset
<=
1
;
end
else
m1_next_state
<=
m1_ack_error_indicator
;
end
// This state is used when the line is too long...
m1_parse_error_indicator_crlf
:
begin
msg_base
<=
5'b10111
;
// Address of the cr,lf message.
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
1
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_parse_error_indicator
;
reset_msg_offset
<=
1
;
end
else
m1_next_state
<=
m1_parse_error_indicator_crlf
;
end
m1_parse_error_indicator
:
begin
msg_base
<=
5'b10011
;
// Address of the ? message.
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
0
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_send_prompt
;
reset_msg_offset
<=
1
;
end
else
m1_next_state
<=
m1_parse_error_indicator
;
end
m1_cmd_error_indicator
:
begin
msg_base
<=
5'b01100
;
// Address of 'C'
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
0
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_parse_error_indicator
;
reset_msg_offset
<=
1
;
end
else
m1_next_state
<=
m1_cmd_error_indicator
;
end
m1_adr_error_indicator
:
begin
msg_base
<=
5'b01010
;
// Address of 'A'
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
0
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_parse_error_indicator
;
reset_msg_offset
<=
1
;
end
else
m1_next_state
<=
m1_adr_error_indicator
;
end
m1_dat_error_indicator
:
begin
msg_base
<=
5'b01101
;
// Address of 'D'
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
0
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_parse_error_indicator
;
reset_msg_offset
<=
1
;
end
else
m1_next_state
<=
m1_dat_error_indicator
;
end
m1_qty_error_indicator
:
begin
msg_base
<=
5'b11100
;
// Address of 'Q'
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
0
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_parse_error_indicator
;
reset_msg_offset
<=
1
;
end
else
m1_next_state
<=
m1_qty_error_indicator
;
end
// The following states are for parsing and executing the command.
// This state takes care of leading whitespace before the command
m1_scan_command
:
begin
rs232_echo
<=
1
;
// Don't send message characters
reset_msg_offset
<=
1
;
// This one reset should cover all of the
// parse/exec. states. With rs232_echo
// on, and no receive characters arrive,
// then the msg_offset will remain reset.
// This means the watchdog timer can take
// a long time, if need be, during exec.
// (NOTE: It might be better to disable
// the echoing of rx chars during these
// states.)
init_qty
<=
1
;
// Set qty = 1 by default. That can be
// overridden later, if the command has
// a different qty field.
if
(
char_is_whitespace
)
begin
m1_next_state
<=
m1_scan_command
;
incr_cmd_ptr
<=
1
;
end
else
if
(
char_is_r
)
begin
m1_next_state
<=
m1_scan_adr_whitespace
;
incr_cmd_ptr
<=
1
;
cmd_r
<=
1
;
end
else
if
(
char_is_w
)
begin
m1_next_state
<=
m1_scan_adr_whitespace
;
incr_cmd_ptr
<=
1
;
cmd_w
<=
1
;
end
else
if
(
char_is_i
)
begin
m1_next_state
<=
m1_start_execution
;
cmd_i
<=
1
;
end
else
m1_next_state
<=
m1_cmd_error_indicator
;
end
// The only way to determine the end of a valid field is to find
// whitespace. Therefore, char_is_whitespace must be used as an exit
// condition from the "get_xxx_field" states. So, this state is used to
// scan through any leading whitespace prior to it.
m1_scan_adr_whitespace
:
begin
rs232_echo
<=
1
;
// Don't send message characters
if
(
char_is_whitespace
)
begin
m1_next_state
<=
m1_scan_adr_whitespace
;
incr_cmd_ptr
<=
1
;
end
else
if
(
char_is_enter
)
m1_next_state
<=
m1_start_execution
;
else
begin
m1_next_state
<=
m1_get_adr_field
;
reset_adr
<=
1
;
end
end
m1_get_adr_field
:
begin
rs232_echo
<=
1
;
// Don't send message characters
if
(
char_is_hex
)
begin
m1_next_state
<=
m1_get_adr_field
;
store_adr
<=
1
;
incr_cmd_ptr
<=
1
;
end
else
if
(
char_is_whitespace
)
begin
// Normal exit
m1_next_state
<=
m1_scan_dat_whitespace
;
end
else
if
(
char_is_enter
)
m1_next_state
<=
m1_start_execution
;
else
m1_next_state
<=
m1_adr_error_indicator
;
end
m1_scan_dat_whitespace
:
begin
rs232_echo
<=
1
;
// Don't send message characters
// There is no DAT field for reads, so skip it.
if
(
command
==
`CMD_R
)
m1_next_state
<=
m1_scan_qty_whitespace
;
else
if
(
char_is_whitespace
)
begin
m1_next_state
<=
m1_scan_dat_whitespace
;
incr_cmd_ptr
<=
1
;
end
else
if
(
char_is_enter
)
m1_next_state
<=
m1_start_execution
;
else
begin
m1_next_state
<=
m1_get_dat_field
;
reset_dat
<=
1
;
end
end
m1_get_dat_field
:
begin
rs232_echo
<=
1
;
// Don't send message characters
if
(
char_is_hex
)
begin
m1_next_state
<=
m1_get_dat_field
;
store_dat
<=
1
;
incr_cmd_ptr
<=
1
;
end
else
if
(
char_is_whitespace
)
begin
// Normal exit
m1_next_state
<=
m1_scan_qty_whitespace
;
end
else
if
(
char_is_enter
)
m1_next_state
<=
m1_start_execution
;
else
m1_next_state
<=
m1_dat_error_indicator
;
end
m1_scan_qty_whitespace
:
begin
rs232_echo
<=
1
;
// Don't send message characters
if
(
char_is_whitespace
)
begin
m1_next_state
<=
m1_scan_qty_whitespace
;
incr_cmd_ptr
<=
1
;
end
else
if
(
char_is_enter
)
m1_next_state
<=
m1_start_execution
;
else
begin
m1_next_state
<=
m1_get_qty_field
;
reset_qty
<=
1
;
end
end
m1_get_qty_field
:
begin
rs232_echo
<=
1
;
// Don't send message characters
if
(
char_is_hex
)
begin
m1_next_state
<=
m1_get_qty_field
;
store_qty
<=
1
;
incr_cmd_ptr
<=
1
;
end
else
if
(
char_is_whitespace
||
char_is_enter
)
begin
// Normal exit
m1_next_state
<=
m1_start_execution
;
end
else
m1_next_state
<=
m1_qty_error_indicator
;
end
// This state seeks to obtain master_bg_i, which grants the bus to
// rs232_syscon.
m1_start_execution
:
begin
rs232_echo
<=
1
;
// Don't send message characters
reset_watchdog
<=
1
;
// Reset the timer.
reset_adr_offset
<=
1
;
// Reset the address offset.
reset_rd_field_count
<=
1
;
// Reset the rd_field_count.
m1_next_state
<=
m1_request_bus
;
end
m1_request_bus
:
begin
rs232_echo
<=
1
;
// Don't send message characters
master_br_o
<=
1
;
// Request the bus.
if
(
master_bg_i
)
m1_next_state
<=
m1_bus_granted
;
else
if
(
watchdog_timer_done
)
begin
m1_next_state
<=
m1_bg_error_indicator
;
end
else
m1_next_state
<=
m1_request_bus
;
end
m1_bus_granted
:
begin
rs232_echo
<=
1
;
// Don't send message characters
master_br_o
<=
1
;
// Keep holding the bus
reset_watchdog
<=
1
;
// Reset the timer.
if
(
adr_offset
!=
qty_sr
)
m1_next_state
<=
m1_execute
;
else
m1_next_state
<=
m1_send_ok
;
end
// This single state does reset/write/read depending upon the value
// contained in "command"!
m1_execute
:
begin
rs232_echo
<=
1
;
// Don't send message characters
master_br_o
<=
1
;
// Keep holding the bus
stb_l
<=
1'b1
;
// Show that a bus cycle is happening
case
(
command
)
// Assert the appropriate signals
`CMD_I
:
rst_o
<=
1
;
`CMD_R
:
capture_dat
<=
ack_i
;
`CMD_W
:
we_l
<=
1
;
default:
;
endcase
if
(
watchdog_timer_done
||
err_i
)
begin
m1_next_state
<=
m1_ack_error_indicator
;
end
else
if
(
ack_i
&&
(
command
==
`CMD_R
)
&&
(
rd_field_count
==
0
)
)
begin
m1_next_state
<=
m1_rd_send_adr_sr
;
// Leads to a new address line.
reset_rd_digit_count
<=
1
;
incr_adr_offset
<=
1
;
// move to the next address
end
else
if
(
ack_i
&&
(
command
==
`CMD_R
))
begin
m1_next_state
<=
m1_rd_send_dat_sr
;
// Leads to a new data field.
reset_rd_digit_count
<=
1
;
reset_msg_offset
<=
1
;
incr_adr_offset
<=
1
;
// move to the next address
end
else
if
(
ack_i
)
begin
m1_next_state
<=
m1_bus_granted
;
// continue to the next cycle
incr_adr_offset
<=
1
;
// move to the next address
end
else
m1_next_state
<=
m1_execute
;
end
m1_rd_send_adr_sr
:
begin
msg_base
<=
{
1'b0
,
rd_adr_sr
[
`NIBBLE_SIZE
*
ADR_DIGITS_PP
-
1
:
`NIBBLE_SIZE
*
(
ADR_DIGITS_PP
-
1
)]
};
if
((
rd_digit_count
==
ADR_DIGITS_PP
-
1
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_rd_send_separator
;
reset_msg_offset
<=
1
;
end
else
if
(
rs232_tx_load
)
begin
shift_rd_adr
<=
1
;
incr_rd_digit_count
<=
1
;
m1_next_state
<=
m1_rd_send_adr_sr
;
end
else
m1_next_state
<=
m1_rd_send_adr_sr
;
end
m1_rd_send_separator
:
begin
msg_base
<=
5'b10000
;
// Address of the separator message
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
2
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_rd_send_dat_sr
;
reset_rd_digit_count
<=
1
;
reset_msg_offset
<=
1
;
end
else
m1_next_state
<=
m1_rd_send_separator
;
end
m1_rd_send_dat_sr
:
begin
msg_base
<=
{
1'b0
,
dat_sr
[
`NIBBLE_SIZE
*
DAT_DIGITS_PP
-
1
:
`NIBBLE_SIZE
*
(
DAT_DIGITS_PP
-
1
)]
};
if
(
(
rd_digit_count
==
DAT_DIGITS_PP
-
1
)
&&
(
rd_field_count
==
RD_FIELDS_PP
-
1
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_rd_send_crlf
;
reset_rd_field_count
<=
1
;
end
else
if
((
rd_digit_count
==
DAT_DIGITS_PP
-
1
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_rd_send_space
;
incr_rd_field_count
<=
1
;
end
else
if
(
rs232_tx_load
)
begin
store_dat
<=
1
;
incr_rd_digit_count
<=
1
;
m1_next_state
<=
m1_rd_send_dat_sr
;
end
else
m1_next_state
<=
m1_rd_send_dat_sr
;
end
m1_rd_send_space
:
begin
msg_base
<=
5'b10000
;
// Address of the space
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
0
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_bus_granted
;
reset_msg_offset
<=
1
;
end
else
m1_next_state
<=
m1_rd_send_space
;
end
m1_rd_send_crlf
:
begin
msg_base
<=
5'b10111
;
// Address of the cr/lf message
incr_msg_offset
<=
rs232_tx_load
;
if
((
msg_offset
==
1
)
&&
rs232_tx_load
)
begin
m1_next_state
<=
m1_bus_granted
;
reset_msg_offset
<=
1
;
end
else
m1_next_state
<=
m1_rd_send_crlf
;
end
default
:
m1_next_state
<=
m1_initial_state
;
endcase
end
// This is the counter for incrementing or loading the cmd_ptr
always
@
(
posedge
clk_i
)
begin
if
(
reset_i
||
reset_cmd_ptr
)
cmd_ptr
<=
0
;
else
if
(
decr_cmd_ptr
)
cmd_ptr
<=
cmd_ptr
-
1
;
else
if
(
incr_cmd_ptr
)
cmd_ptr
<=
cmd_ptr
+
1
;
end
// This is the command buffer writing section
always
@
(
posedge
clk_i
)
begin
if
(
rs232_echo
&&
cmd_buffer_write
)
cmd_buffer
[
cmd_ptr
]
<=
rs232_rx_char
;
end
// This is the command buffer reading section
assign
cmd_char
=
cmd_buffer
[
cmd_ptr
]
;
assign
lc_cmd_char
=
(
cmd_buffer
[
cmd_ptr
]
|
8'h20
)
;
// lowercase
// These assigments are for detecting whether the cmd_char is
// anything of special interest.
assign
char_is_enter
=
(
cmd_char
==
8'h0d
)
;
// enter
assign
char_is_whitespace
=
(
(
cmd_char
==
" "
)
// space
||
(
cmd_char
==
8'h09
)
// tab
)
;
assign
char_is_num
=
((
cmd_char
>=
8'h30
)
&&
(
cmd_char
<=
8'h39
))
;
assign
char_is_a_f
=
((
lc_cmd_char
>=
8'h61
)
&&
(
lc_cmd_char
<=
8'h66
))
;
assign
char_is_hex
=
(
char_is_num
||
char_is_a_f
)
;
assign
char_is_r
=
(
lc_cmd_char
==
"r"
)
;
assign
char_is_w
=
(
lc_cmd_char
==
"w"
)
;
assign
char_is_i
=
(
lc_cmd_char
==
"i"
)
;
assign
hex_digit
=
char_is_num
?
cmd_char
[
3
:
0
]
:
(
cmd_char
[
3
:
0
]
+
9
)
;
// This is the command register. It stores the type of command to execute.
// This is so that the state machine can parse address, data and qty
// into "generic" storage locations, and then when it executes the command,
// it refers back to this register in order to determine what type of
// operation to perform.
always
@
(
posedge
clk_i
)
begin
if
(
reset_i
)
command
<=
`CMD_0
;
else
if
(
cmd_i
)
command
<=
`CMD_I
;
else
if
(
cmd_r
)
command
<=
`CMD_R
;
else
if
(
cmd_w
)
command
<=
`CMD_W
;
end
// This is the "nibble" shift register for the address which is sent character
// by character to the user. It is loaded each time the adr_offset is
// incremented, in order to save the previous address for use in printing
// to the user.
always
@
(
posedge
clk_i
)
begin
if
(
reset_i
||
reset_adr
)
rd_adr_sr
<=
0
;
else
if
(
incr_adr_offset
)
rd_adr_sr
<=
adr_ptr
;
else
if
(
shift_rd_adr
)
begin
rd_adr_sr
[
`NIBBLE_SIZE
*
ADR_DIGITS_PP
-
1
:
`NIBBLE_SIZE
]
<=
rd_adr_sr
[
`NIBBLE_SIZE
*
(
ADR_DIGITS_PP
-
1
)
-
1
:
0
]
;
rd_adr_sr
[
`NIBBLE_SIZE
-
1
:
0
]
<=
{
`NIBBLE_SIZE
{
1'b0
}};
end
end
// These are the "nibble" shift registers. They handle loading the
// hexadecimal digits from the command line.
always
@
(
posedge
clk_i
)
begin
if
(
reset_i
||
reset_adr
)
adr_sr
<=
0
;
else
if
(
store_adr
)
begin
adr_sr
[
`NIBBLE_SIZE
*
ADR_DIGITS_PP
-
1
:
`NIBBLE_SIZE
]
<=
adr_sr
[
`NIBBLE_SIZE
*
(
ADR_DIGITS_PP
-
1
)
-
1
:
0
]
;
adr_sr
[
`NIBBLE_SIZE
-
1
:
0
]
<=
hex_digit
;
end
end
always
@
(
posedge
clk_i
)
begin
if
(
reset_i
||
reset_dat
)
dat_sr
<=
0
;
else
if
(
capture_dat
)
dat_sr
<=
data_in
;
//else if (capture_dat) dat_sr <= data_out;
else
if
(
store_dat
)
begin
dat_sr
[
`NIBBLE_SIZE
*
DAT_DIGITS_PP
-
1
:
`NIBBLE_SIZE
]
<=
dat_sr
[
`NIBBLE_SIZE
*
(
DAT_DIGITS_PP
-
1
)
-
1
:
0
]
;
dat_sr
[
`NIBBLE_SIZE
-
1
:
0
]
<=
hex_digit
;
end
end
always
@
(
posedge
clk_i
)
begin
if
(
reset_i
||
reset_qty
)
qty_sr
<=
0
;
else
if
(
init_qty
)
qty_sr
<=
1
;
else
if
(
store_qty
)
begin
qty_sr
[
`NIBBLE_SIZE
*
QTY_DIGITS_PP
-
1
:
`NIBBLE_SIZE
]
<=
qty_sr
[
`NIBBLE_SIZE
*
(
QTY_DIGITS_PP
-
1
)
-
1
:
0
]
;
qty_sr
[
`NIBBLE_SIZE
-
1
:
0
]
<=
hex_digit
;
end
end
// This is the rd_digit_count counter. It is used for counting digits
// displayed of both the adr_sr and dat_sr, so it must be able to count up
// to the extent of the larger of the two...
always
@
(
posedge
clk_i
)
begin
if
(
reset_i
||
reset_rd_digit_count
)
rd_digit_count
<=
0
;
else
if
(
incr_rd_digit_count
)
rd_digit_count
<=
rd_digit_count
+
1
;
end
// This is the rd_field_count counter. It is used for counting dat_sr fields
// displayed per line.
always
@
(
posedge
clk_i
)
begin
if
(
reset_i
||
reset_rd_field_count
)
rd_field_count
<=
0
;
else
if
(
incr_rd_field_count
)
rd_field_count
<=
rd_field_count
+
1
;
end
// This is the watchdog timer counter
// The watchdog timer is always "enabled" to operate.
always
@
(
posedge
clk_i
)
begin
if
(
reset_i
||
reset_watchdog
)
watchdog_timer_count
<=
0
;
else
if
(
~
watchdog_timer_done
)
watchdog_timer_count
<=
watchdog_timer_count
+
1
;
end
assign
watchdog_timer_done
=
(
watchdog_timer_count
==
WATCHDOG_TIMER_VALUE_PP
)
;
endmodule
hdl/modules/dbe_wishbone/wb_rs232_syscon/rs232_syscon_top.v
0 → 100644
View file @
4eaaadf0
module
rs232_syscon_top_1_0
(
input
clk_i
,
input
reset_i
,
input
ack_i
,
input
err_i
,
input
rs232_rxd_i
,
input
[
31
:
0
]
data_in
,
output
[
31
:
0
]
data_out
,
output
rst_o
,
output
stb_o
,
output
cyc_o
,
output
[
31
:
0
]
adr_o
,
output
we_o
,
output
rs232_txd_o
,
output
[
3
:
0
]
sel_o
)
;
wire
syscon_master
;
assign
sel_o
[
3
]
=
stb_o
;
assign
sel_o
[
2
]
=
stb_o
;
assign
sel_o
[
1
]
=
stb_o
;
assign
sel_o
[
0
]
=
stb_o
;
// Auto-baud
// dat_io -> data_in i data_out
// Magistrala
// Adres: 16 bit
// Dane: 32 bit
rs232_syscon
i_rs232_syscon
(
.
clk_i
(
clk_i
)
,
.
reset_i
(
reset_i
)
,
.
ack_i
(
ack_i
)
,
.
err_i
(
err_i
)
,
.
master_bg_i
(
syscon_master
)
,
.
master_adr_i
()
,
.
master_stb_i
()
,
.
master_we_i
()
,
.
rs232_rxd_i
(
rs232_rxd_i
)
,
//.rs232_rxd_i(),
.
data_in
(
data_in
)
,
.
data_out
(
data_out
)
,
//.dat_io(data),
.
rst_o
(
rst_o
)
,
.
master_br_o
(
syscon_master
)
,
.
stb_o
(
stb_o
)
,
.
cyc_o
(
cyc_o
)
,
.
adr_o
(
adr_o
)
,
.
we_o
(
we_o
)
,
//.rs232_txd_o()
.
rs232_txd_o
(
rs232_txd_o
)
)
;
endmodule
hdl/modules/dbe_wishbone/wb_rs232_syscon/rs232_syscon_top.xml
0 → 100644
View file @
4eaaadf0
<?xml version="1.0" encoding="utf-8"?>
<wb_driver
nazwa=
"rs232_syscon_top"
wersja=
"1.0"
>
<interface>
<line
nazwa=
"rs232_rxd_i"
typ=
"input"
/>
<line
nazwa=
"rs232_txd_o"
typ=
"output"
/>
</interface>
<wb_interface>
<line
nazwa=
"clk_i"
wb_name=
"wb_clk"
/>
<line
nazwa=
"reset_i"
wb_name=
"reset"
/>
<line
nazwa=
"rst_o"
wb_name=
"wb_rst"
/>
<line
nazwa=
"cyc_o"
wb_name=
"wb_cyc"
/>
<line
nazwa=
"adr_o"
wb_name=
"wb_adr"
/>
<line
nazwa=
"data_in"
wb_name=
"wb_data_out"
/>
<line
nazwa=
"we_o"
wb_name=
"wb_we"
/>
<line
nazwa=
"stb_o"
wb_name=
"wb_stb"
/>
<line
nazwa=
"data_out"
wb_name=
"wb_data_in"
/>
<line
nazwa=
"ack_i"
wb_name=
"wb_ack"
/>
<line
nazwa=
"err_i"
wb_name=
"wb_err"
/>
<line
nazwa=
"sel_o"
wb_name=
"wb_sel"
/>
</wb_interface>
</wb_driver>
hdl/modules/dbe_wishbone/wb_rs232_syscon/serial.v
0 → 100644
View file @
4eaaadf0
//-----------------------------------------------------------------------------
// module: serial.vhd
// This file contains modules for serial I/O.
//
// OVERVIEW of contents: The clock generators are
// configured to provide clocks at 16x the desired transmit
// BAUD rates for RS232 serial I/O. This is done so that
// the rs232rx module can easily share the clock generation
// circuitry of the rs232tx block.
// The clock_gen_select module has a BAUD rate selection
// input field of three bits. This field allows the appropriate
// "clock_factor" clock rate to be produced once and used on many
// transmitters and receivers.
// Alternatively, there is a "clock_gen" block which uses parameters
// to specify the desired values for the DDS and prescaler divide factor.
//
// Author: John Clayton
// Date : Nov. 7, 2000
// Update: Nov. 7, 2000 Created this file, with RS232tx block only
// The rs232tx block has no double buffering.
// Update: Nov. 9, 2000 Separated clock generator circuitry into "clock_gen"
// Update: Nov. 29, 2000 Added rs232rx block
// Update: Nov. 30, 2000 Moved contents of "async_tx" and "async_rx" from
// blocks.vhd to this file.
// Update: May 7, 2001 Translated this file from VHDL to verilog, using
// "xhdl"
// Update: May 8, 2001 Since the output of xhdl was rather "spotty", I have
// fixed errors and filled in the "holes" in the code.
// In addition, I have tried to wean this file from
// its previous use and dependency upon "blocks.v"
// (also translated from VHDL, but consisting of rather
// trivial modules.)
// Update: May 8, 2001 Converted to synchronous resets on all flip-flops.
// Update: May 16, 2001 Re-worked the state machines for rs232rx and rs232tx.
// Update: July 25, 2001 Changed the polarity of q[] in rs232_tx, so that its
// output will be the desired (high) level upon initial
// FPGA configuration, even before or without a reset!
// Update: Jan. 30, 2002 Corrected the formula in STEP 1: Find the ratio.
// (Thanks to Shehryar Shaheen at the University of
// Limerick for pointing out the error.)
// Update: June 28, 2002 Fixed "clock_gen" so that it uses the dds_clk.
//
//----------------------------------------
//
// FORMULATING BAUD RATE SETTINGS
//
//
// This ROM contains BAUD rate selection parameters for
// use with the clock_gen_select block.
// The BAUD clocks which are generated are positive pulses,
// (used as clock enables,) and may be used as general clock enables
// if desired.
// Configuring the clock_gen begins with a "Fclk" MHz basic clock.
// To this is applied a prescaler (with value of dds_prescale_value,)
// followed by a Direct Digital Synthesizer (DDS) frequency
// generator. The DDS has an accumulator that is "dds_bits" bits wide.
// The user should know that there is some "jitter" introduced by the
// DDS, and that the amount of jitter varies depending upon the desired
// output frequency. By increasing "dds_bits" the jitter can be made
// very small. Also, the jitter tends to be smaller for small values of
// "dds_phase_increment"
//
// The following settings apply for these table values:
// rate_select BAUD rate (16x this is generated)
//----------------------------------------
// 000 9600
// 001 19200
// 010 38400
// 011 57600
// 100 115200
// (other values are available)
//
//
//
// In order to generate the parameters for a new clock
// frequency, first find the basic Fclk for your board.
// (Fclk=49.152 MHz in this example.)
// Next, choose the lowest desired BAUD rate.
// (lowest_rate=9600 in this example.)
//
// STEP 1 : Find the ratio
//-------------------------
// First, pick a "clock_factor" for the operation of the rs232 units.
// (16 is traditional, although this hardware supports odd values as
// well. For instance, you could pick a clock_factor of 7, if this
// allows you to generate BAUD rates more exactly from your particular
// Fclk. Try to pick the highest clock_factor that you practically can
// since higher numbers allow the receiver to sample in the middle of
// the received bit more exactly... Also, don't go over 16 unless you
// widen out the counters in the design!)
// So, for this example, let clock_factor=16.
//
// Now, find Fclk/(clock_factor*lowest_rate) = 320 (in this example).
// If this ratio is NOT an integer, then be aware that the
// BAUD rates which you will be able to produce will not be
// exact. For asynchronous communications, the clock frequency need not
// be exact. (As mentioned in "Brute Force DDS method" below.)
// If you cannot make clocks close enough to the BAUD rates you desire,
// then you can try a different "clock_factor" setting.
// Or, alternately, you could just use the "Brute Force DDS method."
// (See below)
//
// Or, if all else fails: get a different clock oscillator!
// If the ratio is an integer, or close to it, then proceed to step 2.
//
// Brute Force DDS method (Still step 1):
//-----------------------
// Simply increase the size of the DDS (increase "dds_bits",)
// and set the prescaler to Ndiv=1 (to pass the clock directly
// to the DDS). Then choose your DDS phase increment values (STEP 3)
// so that you can produce rates which are as close as possible
// to "clock_factor" times the desired BAUD rates. It might not be exact,
// but it is as close as possible. If "dds_bits" is sufficiently large,
// then the resulting BAUD rate clocks can be _extremely_ close to the
// correct frequencies. The Baud rate clocks actually do not need
// to be perfect, they can vary by perhaps 3 or 4 percent from their
// exact frequencies, with an increased risk of bit-errors which result,
// of course.
//
// The formula is: dds_freq_int = (2^dds_bits)*(desired_frequency)/Fclk.
//
// STEP 2 : Find the prescaler value
//----------------------------------
// If the ratio mentioned in STEP 1 is an integer, then divide that integer
// into its prime factors. The product of all of the prime factors which
// are not equal to 2 is a good place to start for the prescaler_value.
// If this yields too low of a clock frequency going into the DDS, then
// revert to the "Brute force DDS approach" mentioned above, or else get
// a more suitable clock oscillator!
//
// For this example: 320 = 2*2*2*2*2*2*5. So the prescaler Ndiv = 5.
//
// If you are lucky and the prime factors are all equal to 2, then you have
// chosen an Fclk which is very agreeable to producing the BAUD clocks. You
// can probably set Ndiv=1, which disables the prescaler from operating.
//
//
// STEP 3 : Calculate DDS phase increment values
//----------------------------------------------
// Use the following formula:
// dds_freq_int = (2^dds_bits)*(desired_frequency)/Fclk_dds.
// The resulting values should be used with the DDS, and the values will be
// be "dds_bits-1" wide unsigned quantities.
// Remember that you can change the prescaler Ndiv value to get different
// Fclk_dds values.
//
//=========================================================================
//-----------------------------------------
// This component is a generic clock generator. Simply connect the appropriate
// inputs, and the desired frequency will be the result. Output consists of a
// stream of narrow pulses which are one clock wide. The sizes of DDS and
// prescaler counters are adjustable by parameters.
module
clock_gen
(
clk
,
reset
,
frequency
,
clk_out
)
;
parameter
DDS_PRESCALE_NDIV_PP
=
5
;
// Prescale divide factor
parameter
DDS_PRESCALE_BITS_PP
=
3
;
parameter
DDS_BITS_PP
=
6
;
input
clk
;
input
reset
;
input
[
DDS_BITS_PP
-
2
:
0
]
frequency
;
output
clk_out
;
// Local signals
wire
pulse
;
wire
dds_clk
;
// Simple renaming for readability
wire
[
DDS_BITS_PP
-
2
:
0
]
dds_phase_increment
=
frequency
;
reg
delayed_pulse
;
reg
[
DDS_PRESCALE_BITS_PP
-
1
:
0
]
dds_prescale_count
;
reg
[
DDS_BITS_PP
-
1
:
0
]
dds_phase
;
// This is the DDS prescaler part. It has a variable divide value.
// The divide factor is "dds_prescale_ndiv".
always
@
(
posedge
clk
)
begin
if
(
reset
)
dds_prescale_count
<=
0
;
else
if
(
dds_prescale_count
==
(
DDS_PRESCALE_NDIV_PP
-
1
))
dds_prescale_count
<=
0
;
else
dds_prescale_count
<=
dds_prescale_count
+
1
;
end
assign
dds_clk
=
(
dds_prescale_count
==
(
DDS_PRESCALE_NDIV_PP
-
1
))
;
// "dds_prescale_count" above could be compared to zero instead, to save
// on logic?...
// This is the DDS phase accumulator part
always
@
(
posedge
clk
)
begin
if
(
reset
)
dds_phase
<=
0
;
else
if
(
dds_clk
)
dds_phase
<=
dds_phase
+
dds_phase_increment
;
end
assign
pulse
=
dds_phase
[
DDS_BITS_PP
-
1
]
;
// Simple renaming for readability
// This is "rising edge detector" part
always
@
(
posedge
clk
)
begin
delayed_pulse
<=
pulse
;
end
assign
clk_out
=
(
pulse
&&
~
delayed_pulse
)
;
// Choose the rising edge
endmodule
//-----------------------------------------
// This component is a clock generator with parameters selected by an
// index into a lookup table. There are eight possible settings.
// Recalculate the settings for your own needs as described in
// "FORMULATING BAUD RATE SETTINGS" above. You will need to change
// the bit width of the DDS registers, according to the `defines.
`define
DDS_BITS 6
`define
DDS_PRESCALE_BITS 3
module
clock_gen_select
(
clk
,
reset
,
rate_select
,
clk_out
)
;
input
clk
;
input
reset
;
input
[
2
:
0
]
rate_select
;
output
clk_out
;
// Local signals
wire
pulse
;
wire
dds_clk
;
reg
delayed_pulse
;
reg
[
`DDS_PRESCALE_BITS
-
1
:
0
]
dds_prescale_count
;
reg
[
`DDS_PRESCALE_BITS
-
1
:
0
]
dds_prescale_ndiv
;
reg
[
`DDS_BITS
-
1
:
0
]
dds_phase
;
reg
[
`DDS_BITS
-
2
:
0
]
dds_phase_increment
;
// This part sets up the "dds_phase_increment" and "dds_prescale_ndiv" values
always
@
(
rate_select
)
begin
case
(
rate_select
)
3'b000
:
begin
dds_phase_increment
<=
1
;
// 9600
dds_prescale_ndiv
<=
5
;
end
3'b001
:
begin
dds_phase_increment
<=
2
;
// 19200
dds_prescale_ndiv
<=
5
;
end
3'b010
:
begin
dds_phase_increment
<=
4
;
// 38400
dds_prescale_ndiv
<=
5
;
end
3'b011
:
begin
dds_phase_increment
<=
6
;
// 57600
dds_prescale_ndiv
<=
5
;
end
3'b100
:
begin
dds_phase_increment
<=
12
;
// 115200
dds_prescale_ndiv
<=
5
;
end
3'b101
:
begin
dds_phase_increment
<=
12
;
// 115200
dds_prescale_ndiv
<=
5
;
end
3'b110
:
begin
dds_phase_increment
<=
12
;
// 115200
dds_prescale_ndiv
<=
5
;
end
3'b111
:
begin
dds_phase_increment
<=
12
;
// 115200
dds_prescale_ndiv
<=
5
;
end
default
:
begin
dds_phase_increment
<=
12
;
// 115200
dds_prescale_ndiv
<=
5
;
end
endcase
end
// This is the DDS prescaler part. It has a variable divide value.
// The divide factor is "dds_prescale_ndiv" + 1.
always
@
(
posedge
clk
)
begin
if
(
reset
)
dds_prescale_count
<=
0
;
else
if
(
dds_prescale_count
==
(
dds_prescale_ndiv
-
1
))
dds_prescale_count
<=
0
;
else
dds_prescale_count
<=
dds_prescale_count
+
1
;
end
assign
dds_clk
=
(
dds_prescale_count
==
(
dds_prescale_ndiv
-
1
))
;
// "dds_prescale_count" above could be compared to zero?...
// This is the DDS phase accumulator part
always
@
(
posedge
clk
)
begin
if
(
reset
)
dds_phase
<=
0
;
else
if
(
dds_clk
)
dds_phase
<=
dds_phase
+
dds_phase_increment
;
end
assign
pulse
=
dds_phase
[
`DDS_BITS
-
1
]
;
// Simple renaming for readability
// This is "rising edge detector" part
always
@
(
posedge
clk
)
begin
delayed_pulse
<=
pulse
;
end
assign
clk_out
=
(
pulse
&&
~
delayed_pulse
)
;
// Choose the rising edge
endmodule
//`undef DDS_BITS
//`undef DDS_PRESCALE_BITS
//-----------------------------------------
// This block takes care of receiving an RS232 input word,
// from the "rxd" line in a serial fashion.
// The user is responsible for providing appropriate CLK
// and clock enable (CE) to achieve the desired Baudot interval
// (NOTE: the state machine operates at "CLOCK_FACTOR_PP" times the
// desired BAUD rate. Set it to anything between 2 and 16,
// inclusive. Values higher than 16 will not "buy" much for you,
// and the state machine might not work well for values less than
// four either, because of the difficulty in sampling rxd at the
// "middle" of the bit time. However, it may be useful to adjust
// the clock_factor around in order to generate good BAUD clocks
// from odd Fclk frequencies on your board.)
// Each time the "word_ready" line drives high the unit has put
// a newly received data word into its output buffer, and is possibly
// already in the process of receiving the next one.
// Note that support is not provided for 1.5 stop bits, only integral
// numbers of stop bits are allowed. However, a selection >2 for
// number of stop bits will still work (it will simply receive
// and count additional stop bits before reporting "word_ready"
module
rs232rx
(
clk
,
rx_clk
,
reset
,
rxd
,
read
,
data
,
data_ready
,
error_over_run
,
error_under_run
,
error_all_low
)
;
// Parameter declarations
parameter
START_BITS_PP
=
1
;
parameter
DATA_BITS_PP
=
8
;
parameter
STOP_BITS_PP
=
1
;
parameter
CLOCK_FACTOR_PP
=
16
;
// State encodings, provided as parameters
// for flexibility to the one instantiating the module
parameter
m1_idle
=
0
;
parameter
m1_start
=
1
;
parameter
m1_shift
=
3
;
parameter
m1_over_run
=
2
;
parameter
m1_under_run
=
4
;
parameter
m1_all_low
=
5
;
parameter
m1_extra_1
=
6
;
parameter
m1_extra_2
=
7
;
parameter
m2_data_ready_flag
=
1
;
parameter
m2_data_ready_ack
=
0
;
// I/O declarations
input
clk
;
input
rx_clk
;
input
reset
;
input
rxd
;
input
read
;
output
[
DATA_BITS_PP
-
1
:
0
]
data
;
output
data_ready
;
output
error_over_run
;
output
error_under_run
;
output
error_all_low
;
reg
[
DATA_BITS_PP
-
1
:
0
]
data
;
reg
data_ready
;
reg
error_over_run
;
reg
error_under_run
;
reg
error_all_low
;
// Local signal declarations
`define
TOTAL_BITS START_BITS_PP
+
DATA_BITS_PP
+
STOP_BITS_PP
wire
word_xfer_l
;
wire
mid_bit_l
;
wire
start_bit_l
;
wire
stop_bit_l
;
wire
all_low_l
;
reg
[
3
:
0
]
intrabit_count_l
;
reg
[
`TOTAL_BITS
-
1
:
0
]
q
;
reg
shifter_preset
;
reg
[
2
:
0
]
m1_state
;
reg
[
2
:
0
]
m1_next_state
;
reg
m2_state
;
reg
m2_next_state
;
// State register
always
@
(
posedge
clk
)
begin
:
m1_state_register
if
(
reset
)
m1_state
<=
m1_idle
;
else
m1_state
<=
m1_next_state
;
end
always
@
(
m1_state
or
reset
or
rxd
or
mid_bit_l
or
all_low_l
or
start_bit_l
or
stop_bit_l
)
begin
:
m1_state_logic
// Output signals are low unless set high in a state condition.
shifter_preset
<=
0
;
error_over_run
<=
0
;
error_under_run
<=
0
;
error_all_low
<=
0
;
case
(
m1_state
)
m1_idle
:
begin
shifter_preset
<=
1'b1
;
if
(
~
rxd
)
m1_next_state
<=
m1_start
;
else
m1_next_state
<=
m1_idle
;
end
m1_start
:
begin
if
(
~
rxd
&&
mid_bit_l
)
m1_next_state
<=
m1_shift
;
else
if
(
rxd
&&
mid_bit_l
)
m1_next_state
<=
m1_under_run
;
else
m1_next_state
<=
m1_start
;
end
m1_shift
:
begin
if
(
all_low_l
)
m1_next_state
<=
m1_all_low
;
else
if
(
~
start_bit_l
&&
~
stop_bit_l
)
m1_next_state
<=
m1_over_run
;
else
if
(
~
start_bit_l
&&
stop_bit_l
)
m1_next_state
<=
m1_idle
;
else
m1_next_state
<=
m1_shift
;
end
m1_over_run
:
begin
error_over_run
<=
1
;
shifter_preset
<=
1'b1
;
if
(
reset
)
m1_next_state
<=
m1_idle
;
else
m1_next_state
<=
m1_over_run
;
end
m1_under_run
:
begin
error_under_run
<=
1
;
shifter_preset
<=
1'b1
;
if
(
reset
)
m1_next_state
<=
m1_idle
;
else
m1_next_state
<=
m1_under_run
;
end
m1_all_low
:
begin
error_all_low
<=
1
;
shifter_preset
<=
1'b1
;
if
(
reset
)
m1_next_state
<=
m1_idle
;
else
m1_next_state
<=
m1_all_low
;
end
default
:
m1_next_state
<=
m1_idle
;
endcase
end
assign
word_xfer_l
=
((
m1_state
==
m1_shift
)
&&
~
start_bit_l
&&
stop_bit_l
)
;
// State register
always
@
(
posedge
clk
)
begin
:
m2_state_register
if
(
reset
)
m2_state
<=
m2_data_ready_ack
;
else
m2_state
<=
m2_next_state
;
end
// State transition logic
always
@
(
m2_state
or
word_xfer_l
or
read
)
begin
:
m2_state_logic
case
(
m2_state
)
m2_data_ready_ack:
begin
data_ready
<=
1'b0
;
if
(
word_xfer_l
)
m2_next_state
<=
m2_data_ready_flag
;
else
m2_next_state
<=
m2_data_ready_ack
;
end
m2_data_ready_flag:
begin
data_ready
<=
1'b1
;
if
(
read
)
m2_next_state
<=
m2_data_ready_ack
;
else
m2_next_state
<=
m2_data_ready_flag
;
end
default
:
m2_next_state
<=
m2_data_ready_ack
;
endcase
end
// This counts within a bit-time.
always
@
(
posedge
clk
)
begin
if
(
shifter_preset
)
intrabit_count_l
<=
0
;
else
if
(
rx_clk
)
begin
if
(
intrabit_count_l
==
(
CLOCK_FACTOR_PP
-
1
))
intrabit_count_l
<=
0
;
else
intrabit_count_l
<=
intrabit_count_l
+
1
;
end
end
// This signal gets one "rx_clk" at the middle of the bit time.
assign
mid_bit_l
=
((
intrabit_count_l
==
(
CLOCK_FACTOR_PP
/
2
))
&&
rx_clk
)
;
// This is the shift register
always
@
(
posedge
clk
)
begin
:
rxd_shifter
if
(
shifter_preset
)
q
<=
-
1
;
// Set to all ones.
else
if
(
mid_bit_l
)
q
<=
{
rxd
,
q
[
`TOTAL_BITS
-
1
:
1
]
};
end
// Note: The definitions of "start_bit_l" and "stop_bit_l" could
// well be updated to include _all_ of the start and stop bits.
assign
start_bit_l
=
q
[
0
]
;
assign
stop_bit_l
=
q
[
`TOTAL_BITS
-
1
]
;
assign
all_low_l
=
~
(
|
q
)
;
// Bit-wise or of the entire shift register
// This is the output buffer
always
@
(
posedge
clk
)
begin
:
rxd_output
if
(
reset
)
data
<=
0
;
else
if
(
word_xfer_l
)
data
<=
q
[
START_BITS_PP
+
DATA_BITS_PP
-
1
:
START_BITS_PP
]
;
end
endmodule
//`undef TOTAL_BITS
//-----------------------------------------
// This block takes care of framing up an RS232 output word,
// and sending it out the "txd" line in a serial fashion.
// The user is responsible for providing appropriate clk
// and clock enable (tx_clk) to achieve the desired Baudot interval
// (a new bit is transmitted each (tx_clk/clock_factor) pulses)
// (NOTE: the state machine operates at "clock_factor" times the
// desired BAUD rate. Set it to anything between 2 and 16,
// inclusive. It may be useful to adjust the clock_factor in order to
// generate good BAUD clocks from odd Fclk frequencies on your board.)
// A load operation is requested by bringing the "load" line high. However,
// the load will only be accepted when load_request is also high (which
// just happens to coincide with tx_clk_1x inside of the state machine...)
// Therefore, the "load_request" line may be used as a bus acknowledgement.
// (load_request = "ack_o" in Wishbone terminology -- but it only lasts for
// one single clk cycle, so be careful how you use it!)
//
// If the "load_request" line is tied to "load," the unit will send
// data characters continuously, with no gaps in between transmissions.
//
// Note that support is not provided for 1.5 stop bits, only integral
// numbers of stop bits are allowed. A selection of more than 2 for
// number of stop bits will still work fine, it will simply introduce
// a delay between characters being transmitted, although the length
// of the transmitter shift register will also grow to include one
// stage for each stop bit requested...
module
rs232tx
(
clk
,
tx_clk
,
reset
,
load
,
data
,
load_request
,
txd
)
;
parameter
START_BITS_PP
=
1
;
parameter
DATA_BITS_PP
=
8
;
parameter
STOP_BITS_PP
=
1
;
parameter
CLOCK_FACTOR_PP
=
16
;
parameter
TX_BIT_COUNT_BITS_PP
=
4
;
// = ceil(log(total_bits)/log(2)));
// State encodings, provided as parameters
// for flexibility to the one instantiating the module
parameter
m1_idle
=
0
;
parameter
m1_waiting
=
1
;
parameter
m1_sending
=
3
;
parameter
m1_sending_last_bit
=
2
;
// I/O declarations
input
clk
;
input
tx_clk
;
input
reset
;
input
load
;
input
[
DATA_BITS_PP
-
1
:
0
]
data
;
output
load_request
;
output
txd
;
reg
load_request
;
// local signals
`define
TOTAL_BITS START_BITS_PP
+
DATA_BITS_PP
+
STOP_BITS_PP
reg
[
`TOTAL_BITS
-
1
:
0
]
q
;
// Actual tx shifter
reg
[
TX_BIT_COUNT_BITS_PP
-
1
:
0
]
tx_bit_count_l
;
reg
[
3
:
0
]
prescaler_count_l
;
reg
[
1
:
0
]
m1_state
;
reg
[
1
:
0
]
m1_next_state
;
wire
[
`TOTAL_BITS
-
1
:
0
]
tx_word
=
{{
STOP_BITS_PP
{
1'b1
}},
data
,
{
START_BITS_PP
{
1'b0
}}};
wire
begin_last_bit
;
wire
start_sending
;
wire
tx_clk_1x
;
// This is a prescaler to produce the actual transmit clock.
always
@
(
posedge
clk
)
begin
if
(
reset
)
prescaler_count_l
<=
0
;
else
if
(
tx_clk
)
begin
if
(
prescaler_count_l
==
(
CLOCK_FACTOR_PP
-
1
))
prescaler_count_l
<=
0
;
else
prescaler_count_l
<=
prescaler_count_l
+
1
;
end
end
assign
tx_clk_1x
=
((
prescaler_count_l
==
(
CLOCK_FACTOR_PP
-
1
)
)
&&
tx_clk
)
;
// This is the transmitted bit counter
always
@
(
posedge
clk
)
begin
if
(
start_sending
)
tx_bit_count_l
<=
0
;
else
if
(
tx_clk_1x
)
begin
if
(
tx_bit_count_l
==
(
`TOTAL_BITS
-
2
))
tx_bit_count_l
<=
0
;
else
tx_bit_count_l
<=
tx_bit_count_l
+
1
;
end
end
assign
begin_last_bit
=
((
tx_bit_count_l
==
(
`TOTAL_BITS
-
2
)
)
&&
tx_clk_1x
)
;
assign
start_sending
=
(
tx_clk_1x
&&
load
)
;
// This state machine handles sending out the transmit data
// State register.
always
@
(
posedge
clk
)
begin
:
state_register
if
(
reset
)
m1_state
<=
m1_idle
;
else
m1_state
<=
m1_next_state
;
end
// State transition logic
always
@
(
m1_state
or
tx_clk_1x
or
load
or
begin_last_bit
)
begin
:
state_logic
// Signal is low unless changed in a state condition.
load_request
<=
0
;
case
(
m1_state
)
m1_idle
:
begin
load_request
<=
tx_clk_1x
;
if
(
tx_clk_1x
&&
load
)
m1_next_state
<=
m1_sending
;
else
m1_next_state
<=
m1_idle
;
end
m1_sending
:
begin
if
(
begin_last_bit
)
m1_next_state
<=
m1_sending_last_bit
;
else
m1_next_state
<=
m1_sending
;
end
m1_sending_last_bit
:
begin
load_request
<=
tx_clk_1x
;
if
(
load
&
tx_clk_1x
)
m1_next_state
<=
m1_sending
;
else
if
(
tx_clk_1x
)
m1_next_state
<=
m1_idle
;
else
m1_next_state
<=
m1_sending_last_bit
;
end
default
:
begin
m1_next_state
<=
m1_idle
;
end
endcase
end
// This is the transmit shifter
always
@
(
posedge
clk
)
begin
:
txd_shifter
if
(
reset
)
q
<=
0
;
// set output to all ones
else
if
(
start_sending
)
q
<=
~
tx_word
;
else
if
(
tx_clk_1x
)
q
<=
{
1'b0
,
q
[
`TOTAL_BITS
-
1
:
1
]
};
end
assign
txd
=
~
q
[
0
]
;
endmodule
hdl/modules/dbe_wishbone/wb_rs232_syscon/wb_rs232_syscon.vhd
0 → 100644
View file @
4eaaadf0
------------------------------------------------------------------------------
-- Title : Wishbone Ethernet MAC Wrapper
------------------------------------------------------------------------------
-- Author : Lucas Maziero Russo
-- Company : CNPEM LNLS-DIG
-- Created : 2013-26-08
-- Platform : FPGA-generic
-------------------------------------------------------------------------------
-- Description: Wishbone Wrapper for RS232 Master
-------------------------------------------------------------------------------
-- Copyright (c) 2012 CNPEM
-- Licensed under GNU Lesser General Public License (LGPL) v3.0
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2013-26-08 1.0 lucas.russo Created
-------------------------------------------------------------------------------
library
ieee
;
use
ieee
.
std_logic_1164
.
all
;
library
work
;
use
work
.
wishbone_pkg
.
all
;
use
work
.
dbe_wishbone_pkg
.
all
;
entity
wb_rs232_syscon
is
generic
(
g_ma_interface_mode
:
t_wishbone_interface_mode
:
=
PIPELINED
;
g_ma_address_granularity
:
t_wishbone_address_granularity
:
=
BYTE
);
port
(
-- WISHBONE common
wb_clk_i
:
in
std_logic
;
wb_rstn_i
:
in
std_logic
;
-- External ports
rs232_rxd_i
:
in
std_logic
;
rs232_txd_o
:
out
std_logic
;
-- Reset to FPGA logic
rstn_o
:
out
std_logic
;
-- WISHBONE master
m_wb_adr_o
:
out
std_logic_vector
(
31
downto
0
);
m_wb_sel_o
:
out
std_logic_vector
(
3
downto
0
);
m_wb_we_o
:
out
std_logic
;
m_wb_dat_o
:
out
std_logic_vector
(
31
downto
0
);
m_wb_dat_i
:
in
std_logic_vector
(
31
downto
0
);
m_wb_cyc_o
:
out
std_logic
;
m_wb_stb_o
:
out
std_logic
;
m_wb_ack_i
:
in
std_logic
;
m_wb_err_i
:
in
std_logic
;
m_wb_stall_i
:
in
std_logic
;
m_wb_rty_i
:
in
std_logic
);
end
wb_rs232_syscon
;
architecture
rtl
of
wb_rs232_syscon
is
signal
rst
:
std_logic
;
signal
rst_out
:
std_logic
;
signal
m_wb_adr_out
:
std_logic_vector
(
31
downto
0
);
signal
m_wb_sel_out
:
std_logic_vector
(
3
downto
0
);
signal
m_wb_we_out
:
std_logic
;
signal
m_wb_dat_out
:
std_logic_vector
(
31
downto
0
);
signal
m_wb_dat_in
:
std_logic_vector
(
31
downto
0
);
signal
m_wb_cyc_out
:
std_logic
;
signal
m_wb_stb_out
:
std_logic
;
signal
m_wb_ack_in
:
std_logic
;
signal
m_wb_err_in
:
std_logic
;
signal
m_wb_stall_in
:
std_logic
;
signal
m_wb_rty_in
:
std_logic
;
component
rs232_syscon_top_1_0
port
(
clk_i
:
in
std_logic
;
reset_i
:
in
std_logic
;
ack_i
:
in
std_logic
;
err_i
:
in
std_logic
;
rs232_rxd_i
:
in
std_logic
;
data_in
:
in
std_logic_vector
(
31
downto
0
);
data_out
:
out
std_logic_vector
(
31
downto
0
);
rst_o
:
out
std_logic
;
stb_o
:
out
std_logic
;
cyc_o
:
out
std_logic
;
adr_o
:
out
std_logic_vector
(
31
downto
0
);
we_o
:
out
std_logic
;
rs232_txd_o
:
out
std_logic
;
sel_o
:
out
std_logic_vector
(
3
downto
0
)
);
end
component
;
begin
rst
<=
not
wb_rstn_i
;
-- ETHMAC master interface is byte addressed, classic wishbone
cmp_ma_iface_slave_adapter
:
wb_slave_adapter
generic
map
(
g_master_use_struct
=>
false
,
g_master_mode
=>
g_ma_interface_mode
,
g_master_granularity
=>
g_ma_address_granularity
,
g_slave_use_struct
=>
false
,
g_slave_mode
=>
CLASSIC
,
g_slave_granularity
=>
BYTE
)
port
map
(
clk_sys_i
=>
wb_clk_i
,
rst_n_i
=>
wb_rstn_i
,
sl_adr_i
=>
m_wb_adr_out
,
sl_dat_i
=>
m_wb_dat_out
,
sl_sel_i
=>
m_wb_sel_out
,
sl_cyc_i
=>
m_wb_cyc_out
,
sl_stb_i
=>
m_wb_stb_out
,
sl_we_i
=>
m_wb_we_out
,
sl_dat_o
=>
m_wb_dat_in
,
sl_ack_o
=>
m_wb_ack_in
,
sl_stall_o
=>
open
,
sl_int_o
=>
open
,
sl_rty_o
=>
open
,
sl_err_o
=>
m_wb_err_in
,
ma_adr_o
=>
m_wb_adr_o
,
ma_dat_o
=>
m_wb_dat_o
,
ma_sel_o
=>
m_wb_sel_o
,
ma_cyc_o
=>
m_wb_cyc_o
,
ma_stb_o
=>
m_wb_stb_o
,
ma_we_o
=>
m_wb_we_o
,
ma_dat_i
=>
m_wb_dat_i
,
ma_ack_i
=>
m_wb_ack_i
,
ma_stall_i
=>
m_wb_stall_i
,
ma_rty_i
=>
m_wb_rty_i
,
ma_err_i
=>
m_wb_err_i
);
cmp_rs232_syscon_top_1_0
:
rs232_syscon_top_1_0
port
map
(
clk_i
=>
wb_clk_i
,
reset_i
=>
rst
,
ack_i
=>
m_wb_ack_in
,
err_i
=>
m_wb_err_in
,
rs232_rxd_i
=>
rs232_rxd_i
,
data_in
=>
m_wb_dat_in
,
data_out
=>
m_wb_dat_out
,
rst_o
=>
rst_out
,
stb_o
=>
m_wb_stb_out
,
cyc_o
=>
m_wb_cyc_out
,
adr_o
=>
m_wb_adr_out
,
we_o
=>
m_wb_we_out
,
rs232_txd_o
=>
rs232_txd_o
,
sel_o
=>
m_wb_sel_out
);
rstn_o
<=
not
rst_out
;
end
rtl
;
hdl/modules/dbe_wishbone/wb_rs232_syscon/xwb_rs232_syscon.vhd
0 → 100644
View file @
4eaaadf0
------------------------------------------------------------------------------
-- Title : Wishbone Ethernet MAC Wrapper
------------------------------------------------------------------------------
-- Author : Lucas Maziero Russo
-- Company : CNPEM LNLS-DIG
-- Created : 2013-26-08
-- Platform : FPGA-generic
-------------------------------------------------------------------------------
-- Description: Wishbone Wrapper for RS232 Master
-------------------------------------------------------------------------------
-- Copyright (c) 2012 CNPEM
-- Licensed under GNU Lesser General Public License (LGPL) v3.0
-------------------------------------------------------------------------------
-- Revisions :
-- Date Version Author Description
-- 2013-26-08 1.0 lucas.russo Created
-------------------------------------------------------------------------------
library
ieee
;
use
ieee
.
std_logic_1164
.
all
;
library
work
;
use
work
.
wishbone_pkg
.
all
;
use
work
.
dbe_wishbone_pkg
.
all
;
entity
xwb_rs232_syscon
is
generic
(
g_ma_interface_mode
:
t_wishbone_interface_mode
:
=
PIPELINED
;
g_ma_address_granularity
:
t_wishbone_address_granularity
:
=
BYTE
);
port
(
-- WISHBONE common
wb_clk_i
:
in
std_logic
;
wb_rstn_i
:
in
std_logic
;
-- External ports
rs232_rxd_i
:
in
std_logic
;
rs232_txd_o
:
out
std_logic
;
-- Reset to FPGA logic
rstn_o
:
out
std_logic
;
-- WISHBONE master
wb_master_i
:
in
t_wishbone_master_in
;
wb_master_o
:
out
t_wishbone_master_out
);
end
xwb_rs232_syscon
;
architecture
rtl
of
xwb_rs232_syscon
is
begin
cmp_wb_rs232_syscon
:
wb_rs232_syscon
generic
map
(
g_ma_interface_mode
=>
g_ma_interface_mode
,
g_ma_address_granularity
=>
g_ma_address_granularity
)
port
map
(
-- WISHBONE common
wb_clk_i
=>
wb_clk_i
,
wb_rstn_i
=>
wb_rstn_i
,
-- External ports
rs232_rxd_i
=>
rs232_rxd_i
,
rs232_txd_o
=>
rs232_txd_o
,
-- Reset to FPGA logic
rstn_o
=>
rstn_o
,
-- WISHBONE master
m_wb_adr_o
=>
wb_master_o
.
adr
,
m_wb_sel_o
=>
wb_master_o
.
sel
,
m_wb_we_o
=>
wb_master_o
.
we
,
m_wb_dat_o
=>
wb_master_o
.
dat
,
m_wb_dat_i
=>
wb_master_i
.
dat
,
m_wb_cyc_o
=>
wb_master_o
.
cyc
,
m_wb_stb_o
=>
wb_master_o
.
stb
,
m_wb_ack_i
=>
wb_master_i
.
ack
,
m_wb_err_i
=>
wb_master_i
.
err
,
m_wb_stall_i
=>
wb_master_i
.
stall
,
m_wb_rty_i
=>
wb_master_i
.
rty
);
end
rtl
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment