Просмотр исходного кода

Testiug UART

Imported UART from opencore library and tested using physical FPGA
Min 6 лет назад
Родитель
Сommit
765071d73f
7 измененных файлов с 396 добавлено и 57 удалено
  1. 11 6
      UCL_project_y3.qsf
  2. 0 39
      memory/rom_test.mem
  3. 42 0
      src/blocks/clk_div.sv
  4. 77 0
      src/blocks/uart.md
  5. 217 0
      src/blocks/uart.v
  6. 7 3
      src/cpu.sv
  7. 42 9
      src/io_unit.sv

+ 11 - 6
UCL_project_y3.qsf

@@ -76,6 +76,17 @@ set_global_assignment -name EDA_TEST_BENCH_MODULE_NAME testbench_1 -section_id t
 set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
 set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
 set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
 set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
 set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
 set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
+set_global_assignment -name EDA_TEST_BENCH_FILE src/blocks/reg_file_tb.sv -section_id testbench_1
+set_global_assignment -name EDA_TEST_BENCH_FILE src/blocks/memory.sv -section_id testbench_1
+set_global_assignment -name EDA_TEST_BENCH_FILE src/blocks/alu.sv -section_id testbench_1
+set_global_assignment -name EDA_TEST_BENCH_FILE src/datapath.sv -section_id testbench_1
+set_global_assignment -name EDA_TEST_BENCH_FILE src/cpu.sv -section_id testbench_1
+set_global_assignment -name EDA_TEST_BENCH_FILE src/controller.sv -section_id testbench_1
+set_location_assignment PIN_R8 -to clk
+set_location_assignment PIN_D3 -to rx
+set_location_assignment PIN_C3 -to tx
+set_global_assignment -name SYSTEMVERILOG_FILE src/blocks/clk_div.sv
+set_global_assignment -name VERILOG_FILE src/blocks/uart.v
 set_global_assignment -name MIF_FILE memory/rom_test.mem
 set_global_assignment -name MIF_FILE memory/rom_test.mem
 set_global_assignment -name SYSTEMVERILOG_FILE src/datapath.sv
 set_global_assignment -name SYSTEMVERILOG_FILE src/datapath.sv
 set_global_assignment -name SYSTEMVERILOG_FILE src/blocks/instr_mem.sv
 set_global_assignment -name SYSTEMVERILOG_FILE src/blocks/instr_mem.sv
@@ -86,10 +97,4 @@ set_global_assignment -name SYSTEMVERILOG_FILE src/blocks/alu.sv
 set_global_assignment -name SYSTEMVERILOG_FILE src/io_unit.sv
 set_global_assignment -name SYSTEMVERILOG_FILE src/io_unit.sv
 set_global_assignment -name SYSTEMVERILOG_FILE src/general.sv
 set_global_assignment -name SYSTEMVERILOG_FILE src/general.sv
 set_global_assignment -name SYSTEMVERILOG_FILE src/controller.sv
 set_global_assignment -name SYSTEMVERILOG_FILE src/controller.sv
-set_global_assignment -name EDA_TEST_BENCH_FILE src/blocks/reg_file_tb.sv -section_id testbench_1
-set_global_assignment -name EDA_TEST_BENCH_FILE src/blocks/memory.sv -section_id testbench_1
-set_global_assignment -name EDA_TEST_BENCH_FILE src/blocks/alu.sv -section_id testbench_1
-set_global_assignment -name EDA_TEST_BENCH_FILE src/datapath.sv -section_id testbench_1
-set_global_assignment -name EDA_TEST_BENCH_FILE src/cpu.sv -section_id testbench_1
-set_global_assignment -name EDA_TEST_BENCH_FILE src/controller.sv -section_id testbench_1
 set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
 set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

+ 0 - 39
memory/rom_test.mem

@@ -1,39 +0,0 @@
-00 // NOP
-20 // ADDI regA = FA
-FA // imm
-24 // ADDI regB = 01
-01 // imm
-31 // SUB regA = regA - regB
-83 // SW mem[regC] = regA 
-60 // ~regA
-73 // LW regA = mem[regC]
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-00
-

+ 42 - 0
src/blocks/clk_div.sv

@@ -0,0 +1,42 @@
+//
+// Copied from http://referencedesigner.com/tutorials/verilogexamples/verilog_ex_04.php
+//
+
+
+module clk_div 
+#( 
+parameter WIDTH = 3, // Width of the register required
+parameter N = 6// We will divide by 12 for example in this case
+)
+(clk,reset, clk_out);
+ 
+input clk;
+input reset;
+output clk_out;
+ 
+reg [WIDTH-1:0] r_reg;
+wire [WIDTH-1:0] r_nxt;
+reg clk_track;
+ 
+always @(posedge clk or posedge reset)
+ 
+begin
+  if (reset)
+     begin
+        r_reg <= 0;
+	clk_track <= 1'b0;
+     end
+ 
+  else if (r_nxt == N)
+ 	   begin
+	     r_reg <= 0;
+	     clk_track <= ~clk_track;
+	   end
+ 
+  else 
+      r_reg <= r_nxt;
+end
+ 
+ assign r_nxt = r_reg+1;   	      
+ assign clk_out = clk_track;
+endmodule

Разница между файлами не показана из-за своего большого размера
+ 77 - 0
src/blocks/uart.md


+ 217 - 0
src/blocks/uart.v

@@ -0,0 +1,217 @@
+`timescale 1ns / 1ps
+// Documented Verilog UART
+// Copyright (C) 2010 Timothy Goddard (tim@goddard.net.nz)
+// Distributed under the MIT licence.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+// 
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+// 
+// Accessed from:
+// https://opencores.org/projects/osdvu
+//
+
+module uart(
+    input clk, // The master clock for this module
+    input rst, // Synchronous reset.
+    input rx, // Incoming serial line
+    output tx, // Outgoing serial line
+    input transmit, // Signal to transmit
+    input [7:0] tx_byte, // Byte to transmit
+    output received, // Indicated that a byte has been received.
+    output [7:0] rx_byte, // Byte received
+    output is_receiving, // Low when receive line is idle.
+    output is_transmitting, // Low when transmit line is idle.
+    output recv_error // Indicates error in receiving packet.
+    );
+ 
+parameter CLOCK_DIVIDE = 1302; // clock rate (50Mhz) / (baud rate (9600) * 4)
+ 
+// States for the receiving state machine.
+// These are just constants, not parameters to override.
+parameter RX_IDLE = 0;
+parameter RX_CHECK_START = 1;
+parameter RX_READ_BITS = 2;
+parameter RX_CHECK_STOP = 3;
+parameter RX_DELAY_RESTART = 4;
+parameter RX_ERROR = 5;
+parameter RX_RECEIVED = 6;
+ 
+// States for the transmitting state machine.
+// Constants - do not override.
+parameter TX_IDLE = 0;
+parameter TX_SENDING = 1;
+parameter TX_DELAY_RESTART = 2;
+ 
+reg [10:0] rx_clk_divider = CLOCK_DIVIDE;
+reg [10:0] tx_clk_divider = CLOCK_DIVIDE;
+ 
+reg [2:0] recv_state = RX_IDLE;
+reg [5:0] rx_countdown;
+reg [3:0] rx_bits_remaining;
+reg [7:0] rx_data;
+ 
+reg tx_out = 1'b1;
+reg [1:0] tx_state = TX_IDLE;
+reg [5:0] tx_countdown;
+reg [3:0] tx_bits_remaining;
+reg [7:0] tx_data;
+ 
+assign received = recv_state == RX_RECEIVED;
+assign recv_error = recv_state == RX_ERROR;
+assign is_receiving = recv_state != RX_IDLE;
+assign rx_byte = rx_data;
+ 
+assign tx = tx_out;
+assign is_transmitting = tx_state != TX_IDLE;
+ 
+always @(posedge clk) begin
+	if (rst) begin
+		recv_state = RX_IDLE;
+		tx_state = TX_IDLE;
+	end
+ 
+	// The clk_divider counter counts down from
+	// the CLOCK_DIVIDE constant. Whenever it
+	// reaches 0, 1/16 of the bit period has elapsed.
+   // Countdown timers for the receiving and transmitting
+	// state machines are decremented.
+	rx_clk_divider = rx_clk_divider - 1;
+	if (!rx_clk_divider) begin
+		rx_clk_divider = CLOCK_DIVIDE;
+		rx_countdown = rx_countdown - 1;
+	end
+	tx_clk_divider = tx_clk_divider - 1;
+	if (!tx_clk_divider) begin
+		tx_clk_divider = CLOCK_DIVIDE;
+		tx_countdown = tx_countdown - 1;
+	end
+ 
+	// Receive state machine
+	case (recv_state)
+		RX_IDLE: begin
+			// A low pulse on the receive line indicates the
+			// start of data.
+			if (!rx) begin
+				// Wait half the period - should resume in the
+				// middle of this first pulse.
+				rx_clk_divider = CLOCK_DIVIDE;
+				rx_countdown = 2;
+				recv_state = RX_CHECK_START;
+			end
+		end
+		RX_CHECK_START: begin
+			if (!rx_countdown) begin
+				// Check the pulse is still there
+				if (!rx) begin
+					// Pulse still there - good
+					// Wait the bit period to resume half-way
+					// through the first bit.
+					rx_countdown = 4;
+					rx_bits_remaining = 8;
+					recv_state = RX_READ_BITS;
+				end else begin
+					// Pulse lasted less than half the period -
+					// not a valid transmission.
+					recv_state = RX_ERROR;
+				end
+			end
+		end
+		RX_READ_BITS: begin
+			if (!rx_countdown) begin
+				// Should be half-way through a bit pulse here.
+				// Read this bit in, wait for the next if we
+				// have more to get.
+				rx_data = {rx, rx_data[7:1]};
+				rx_countdown = 4;
+				rx_bits_remaining = rx_bits_remaining - 1;
+				recv_state = rx_bits_remaining ? RX_READ_BITS : RX_CHECK_STOP;
+			end
+		end
+		RX_CHECK_STOP: begin
+			if (!rx_countdown) begin
+				// Should resume half-way through the stop bit
+				// This should be high - if not, reject the
+				// transmission and signal an error.
+				recv_state = rx ? RX_RECEIVED : RX_ERROR;
+			end
+		end
+		RX_DELAY_RESTART: begin
+			// Waits a set number of cycles before accepting
+			// another transmission.
+			recv_state = rx_countdown ? RX_DELAY_RESTART : RX_IDLE;
+		end
+		RX_ERROR: begin
+			// There was an error receiving.
+			// Raises the recv_error flag for one clock
+			// cycle while in this state and then waits
+			// 2 bit periods before accepting another
+			// transmission.
+			rx_countdown = 8;
+			recv_state = RX_DELAY_RESTART;
+		end
+		RX_RECEIVED: begin
+			// Successfully received a byte.
+			// Raises the received flag for one clock
+			// cycle while in this state.
+			recv_state = RX_IDLE;
+		end
+	endcase
+ 
+	// Transmit state machine
+	case (tx_state)
+		TX_IDLE: begin
+			if (transmit) begin
+				// If the transmit flag is raised in the idle
+				// state, start transmitting the current content
+				// of the tx_byte input.
+				tx_data = tx_byte;
+				// Send the initial, low pulse of 1 bit period
+				// to signal the start, followed by the data
+				tx_clk_divider = CLOCK_DIVIDE;
+				tx_countdown = 4;
+				tx_out = 0;
+				tx_bits_remaining = 8;
+				tx_state = TX_SENDING;
+			end
+		end
+		TX_SENDING: begin
+			if (!tx_countdown) begin
+				if (tx_bits_remaining) begin
+					tx_bits_remaining = tx_bits_remaining - 1;
+					tx_out = tx_data[0];
+					tx_data = {1'b0, tx_data[7:1]};
+					tx_countdown = 4;
+					tx_state = TX_SENDING;
+				end else begin
+					// Set delay to send out 2 stop bits.
+					tx_out = 1;
+					tx_countdown = 8;
+					tx_state = TX_DELAY_RESTART;
+				end
+			end
+		end
+		TX_DELAY_RESTART: begin
+			// Wait until tx_countdown reaches the end before
+			// we send another transmission. This covers the
+			// "stop bit" delay.
+			tx_state = tx_countdown ? TX_DELAY_RESTART : TX_IDLE;
+		end
+	endcase
+end
+ 
+endmodule

+ 7 - 3
src/cpu.sv

@@ -1,3 +1,4 @@
+`timescale 1ns / 1ps
 import project_pkg::*;
 import project_pkg::*;
 
 
 module cpu(clk, rst, instr, imm, pc, mem_addr, mem_wr_en, mem_wr_data, mem_rd_data);
 module cpu(clk, rst, instr, imm, pc, mem_addr, mem_wr_en, mem_wr_data, mem_rd_data);
@@ -26,9 +27,12 @@ module cpu_tb;
 	// Instruction memory
 	// Instruction memory
 	instr_mem #("/home/min/devel/fpga/ucl_project_y3/memory/test.mem") IMEM(pc, instr, imm);
 	instr_mem #("/home/min/devel/fpga/ucl_project_y3/memory/test.mem") IMEM(pc, instr, imm);
 	// System memory
 	// System memory
-	memory RAM(clk, mem_wr, mem_addr, mem_data, mem_rd_data);	 word outvalue;
-	always_ff@(negedge mem_wr)
-			if(mem_addr == 8'hFF) outvalue <= mem_data;
+	memory RAM(clk, mem_wr, mem_addr, mem_data, mem_rd_data);
+	word outvalue;
+	always_ff@(posedge clk) begin
+			if(mem_wr & mem_addr == 8'hFF) outvalue <= mem_data;
+			else outvalue <= 0; 
+	end
 
 
 	initial begin
 	initial begin
 		clk = 0;
 		clk = 0;

+ 42 - 9
src/io_unit.sv

@@ -1,18 +1,51 @@
 import project_pkg::word;
 import project_pkg::word;
 
 
-module io_unit(switches, keys, leds);
-	input  logic [3:0]switches;
-	input  logic [1:0]keys;
-	output logic [7:0]leds;
+module io_unit(
+	input  logic clk, rx,
+	input  logic [3:0]switches,
+	input  logic [1:0]keys,
+	output logic tx,
+	output logic [7:0]leds
+	);
 	
 	
-	assign rst = keys[0];
-	assign clk = keys[1];
+	logic transmit, received, is_receiving, is_transmitting, recv_error;
+	logic [7:0] tx_byte, rx_byte;
+	assign leds[0] = received;
+	assign leds[1] = is_receiving;
+	assign leds[2] = is_transmitting;
+	//assign leds[3] = recv_error;
+	//assign leds[6] = rx;
+	//assign leds[7] = tx;
+	logic clk_slow;
+
+	clk_div clk_div12(clk, rst, clk_slow);	
+	assign rst = ~keys[0];
+	//assign transmit = keys[1];
+	//assign tx_byte = rx_byte;
+
+	uart uart0(clk, rst, rx, tx, transmit, tx_byte, received, rx_byte, is_receiving, is_transmitting, );
+
+	//assign clk = keys[1];
 	logic mem_wr;
 	logic mem_wr;
-	word pc, instr, imm, mem_addr, mem_data, mem_rd_data;	
-	cpu CPU(clk, rst, instr, imm, pc, mem_addr, mem_wr, mem_data, mem_rd_data);
+	word pc, instr, imm, mem_addr, mem_data, mem_rd_data;
+	word ext_rd_data, rd_data;
+	cpu CPU(clk_slow, rst, instr, imm, pc, mem_addr, mem_wr, mem_data, rd_data);
 	// Instruction memory
 	// Instruction memory
 	instr_mem #("/home/min/devel/fpga/ucl_project_y3/memory/test.mem") IMEM(pc, instr, imm);
 	instr_mem #("/home/min/devel/fpga/ucl_project_y3/memory/test.mem") IMEM(pc, instr, imm);
 	// System memory
 	// System memory
-	memory RAM(clk, mem_wr, mem_addr, mem_data, mem_rd_data);	
+	memory RAM(clk, mem_wr, mem_addr, mem_data, mem_rd_data);
+	
+	assign ext_rd_data = '{0,0,0,0, 0,0,0,is_transmitting};
+	assign rd_data = (mem_addr == 8'hFF) ? ext_rd_data : mem_rd_data;
+
+	always_ff@(posedge clk_slow) begin
+			if(mem_wr & mem_addr == 8'hFF) begin
+				tx_byte <= mem_data;
+				transmit <= 1; 
+			end
+			else begin
+				transmit <= 0; 
+			end
+	end
 
 
 endmodule
 endmodule