mirror of
git://projects.qi-hardware.com/nn-usb-fpga.git
synced 2024-12-12 22:03:45 +02:00
1319 lines
31 KiB
Verilog
1319 lines
31 KiB
Verilog
`timescale 1ns / 1ps
|
|
/******************************************************************************/
|
|
/* SIDSA */
|
|
/******************************************************************************/
|
|
/* HSDT100 ARM PERIPHERALS */
|
|
/* */
|
|
/* MODULE: UART */
|
|
/* */
|
|
/* FILE: UART_PC.v VERSION:3.0 DATE: 19-I-98 */
|
|
/******************************************************************************/
|
|
|
|
|
|
module UART (reset, CLK, data_in, data_out, add, nRW, CS,
|
|
RxD, TxD, nIRQ, CD, RI, DSR, CTS, DTR, RTS);
|
|
|
|
input reset; // Reset (H)
|
|
input CLK; // System clock
|
|
input [7:0] data_in; // Input Data Bus
|
|
input [2:0] add; // Address Bus
|
|
input nRW; // Read_ / Write from ARM
|
|
input CS; // UART Chip Select
|
|
|
|
input RxD; // Receiver Data Line
|
|
input CD; // Carrier Detect
|
|
input RI; // Ring Indicator
|
|
input DSR; // Data Send Ready
|
|
input CTS; // Clear To Send
|
|
|
|
output RTS; // Request To Send
|
|
output DTR; // Data Terminal Ready
|
|
output TxD; // Transmiter Data Line
|
|
output nIRQ; // Interrupt Request Output to ARM
|
|
output [7:0] data_out; // Output Data Bus
|
|
|
|
|
|
// Variables
|
|
//.............................................................
|
|
|
|
wire [7:0] dato_rx; // Dato recibido
|
|
wire [7:0] dato_tx; // Dato para transmitir
|
|
wire err_paridad; // Error de paridad (H)
|
|
wire err_frame; // Error de trama (H)
|
|
wire err_overrun; // Error de rebosamiento (H)
|
|
wire error; // Error (OR de los anteriores)
|
|
wire rx_lleno; // Dato disponible
|
|
wire tx_empty; // Transmisor vacio
|
|
wire txt_empty; // Transmisor completamente vacio
|
|
wire borrar_rdy; // Borrar dato_rdy tras leer DATO_RX
|
|
wire borrar_err; // Borrar err_over tras leer STATUS_RX
|
|
wire carga; // Senal carga
|
|
wire carga_div; // Senal carga cte_div
|
|
|
|
wire clkl; // Frecuencia de reloj dividida
|
|
wire clkls; // Reloj de muestreo sincronizado (el nivel
|
|
// alto dura un periodo de reloj)
|
|
wire RxDs; // Senal RxD sincronizada y limpia
|
|
wire sample; // Impulso de muestreo de la senal RxDs
|
|
wire samples; // Impulso de muestreo de RxDs conformado
|
|
wire load_shift;
|
|
|
|
wire carga_IER; // senal carga IER
|
|
wire carga_MCR; // senal carga MCR
|
|
wire carga_LCR; // senal carga LCR
|
|
wire carga_MSR; // senal carga MSR (para codificacion delta)
|
|
wire carga_ISR; // senal carga ISR
|
|
|
|
wire [1:0] WordLength; // CONFIGURACIONES UART
|
|
wire Stop;
|
|
wire ParityEnable;
|
|
wire Parity;
|
|
wire ParityForced;
|
|
wire Break;
|
|
wire BaudSelect;
|
|
wire modem_int;
|
|
wire [7:0] modem;
|
|
wire [3:0] ISR;
|
|
wire [7:0] LSR;
|
|
wire [7:0] LCR;
|
|
wire [3:0] IER;
|
|
//.............................................................
|
|
|
|
|
|
// The default comunication speed is 115200 (clk = 50MHz); divide the clock if you want another speed
|
|
// The Minimun Clk frequency is 50Mz
|
|
// 50000000/115200 = 434 => 16 X 27 = 432
|
|
|
|
pc_if_arm_pc if_arm1 (reset, CLK, data_in, data_out, add, nRW, CS,
|
|
borrar_rdy, borrar_err,
|
|
carga, carga_div_low, carga_div_high,
|
|
carga_IER, carga_MCR,
|
|
carga_LCR, carga_MSR, carga_ISR,
|
|
BaudSelect, dato_rx, modem, ISR, LSR, LCR);
|
|
|
|
pc_div27 div27(reset, CLK, 1'b1, clk_pres);
|
|
|
|
pc_div_ms div_ms1 (reset, CLK, clk_pres,data_in, carga_div_low, carga_div_high, clkl);
|
|
|
|
pc_pulso pulso1(reset, CLK, clkl, clkls);
|
|
|
|
pc_div16 div161(reset, CLK, clkls, clktx);
|
|
|
|
pc_ifrxd ifrxd1(reset, CLK, clkls, RxD, RxDs);
|
|
|
|
pc_muestreo muestreo1(reset, CLK, rx_lleno, clkls, RxDs, sample);
|
|
|
|
pc_pulso pulso2(reset, CLK, sample, samples);
|
|
|
|
pc_buffrx_pc buffrx1(reset, CLK, RxDs, samples, rx_lleno, dato_rx, err_paridad,
|
|
err_frame, ParityEnable, Parity, ParityForced);
|
|
|
|
pc_ctrl_rx ctrl_rx1(reset, CLK, samples, rx_lleno);
|
|
|
|
pc_dato_rdy dato_rdy1(reset, CLK, rx_lleno, borrar_rdy, borrar_err, dato_rdy,
|
|
err_overrun);
|
|
|
|
pc_pulso pulso3(reset, CLK, clktx, clktxs);
|
|
|
|
pc_bufftx bufftx1 (reset, CLK, carga, load_shift, clktxs, data_in, TxD,
|
|
ParityEnable, Parity, ParityForced);
|
|
|
|
pc_ctrl_tx_pc ctrl_tx1 (reset, CLK, carga, clktxs, load_shift, tx_empty,
|
|
txt_empty);
|
|
|
|
//pc_modem m1(reset, CLK, carga_MCR, carga_MSR, data_in, modem,
|
|
// CD, RI, DSR, CTS, DTR, RTS, modem_int);
|
|
|
|
pc_ier ier1(reset, CLK, carga_IER, data_in, dato_rdy, tx_empty, modem_int, nIRQ, IER);
|
|
|
|
pc_lcr lcr1(reset, CLK, LCR, carga_LCR, data_in,
|
|
WordLength, Stop, ParityEnable, Parity,
|
|
ParityForced, Break, BaudSelect);
|
|
|
|
pc_isr isr1(reset, CLK, carga_ISR,
|
|
err_paridad, err_frame, err_overrun,
|
|
dato_rdy, tx_empty, txt_empty, modem_int,
|
|
ISR, LSR, IER);
|
|
|
|
endmodule
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//............................................................
|
|
// BUFFER RECEIVER
|
|
//
|
|
//............................................................
|
|
|
|
|
|
module pc_buffrx_pc (reset, CLK, RxDs, samples, fin_rx, datorx,
|
|
err_paridad, err_frame,
|
|
ParityEnable, Parity, ParityForced);
|
|
|
|
input reset; // Reset (H)
|
|
input CLK; // Reloj del sistema
|
|
input RxDs; // Linea RxD limpia
|
|
input samples; // Impulso de muestreo de RxDs conformado
|
|
input fin_rx; // Indicador (L) de recepcion en curso
|
|
output [7:0] datorx; // Dato recibido
|
|
output err_paridad; // Error de paridad (H)
|
|
output err_frame; // Error en el bit de parada (H)
|
|
input ParityEnable; // Habilitacion de paridad
|
|
input Parity; // Paridad
|
|
input ParityForced; // Valor de paridad forzada.
|
|
|
|
|
|
// Variables
|
|
//.............................................................
|
|
|
|
reg [9:0] bufrx; // Registro serie-paralelo del Receptor
|
|
// bufrx[7:0]=dato, bufrx[8]=paridad
|
|
// bufrx[9]=parada
|
|
reg [7:0] datorx; // Dato recibido
|
|
reg err_paridad; // Error de paridad (H)
|
|
reg err_frame; // Error en el bit de parada (H)
|
|
wire iparity;
|
|
|
|
//.............................................................
|
|
|
|
// Si el numero de 1s es par, iparity =1
|
|
|
|
assign iparity = bufrx[8] ^ bufrx[7] ^ bufrx[6]
|
|
^ bufrx[5] ^ bufrx[4] ^ bufrx[3]
|
|
^ bufrx[2] ^ bufrx[1] ^ bufrx[0];
|
|
|
|
|
|
always @(posedge CLK or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
bufrx <= 0;
|
|
datorx <= 0;
|
|
err_paridad <= 0;
|
|
err_frame <= 0;
|
|
end
|
|
else casex ({fin_rx, samples})
|
|
2'bx1: begin
|
|
bufrx <= bufrx >> 1;
|
|
bufrx[9] <= RxDs;
|
|
end
|
|
|
|
2'b1x: begin
|
|
datorx <= bufrx[7:0];
|
|
|
|
casex ({ParityForced, Parity, ParityEnable})
|
|
3'bxx0: err_paridad <= 0; // No parity
|
|
|
|
3'b001: err_paridad <= ~iparity; // ODD parity
|
|
3'b011: err_paridad <= iparity; // EVEN parity
|
|
3'b101: err_paridad <= 1; // forced parity
|
|
3'b111: err_paridad <= 0; // forced parity
|
|
|
|
endcase
|
|
|
|
err_frame <= !bufrx[9];
|
|
end
|
|
endcase
|
|
end
|
|
|
|
endmodule
|
|
|
|
|
|
|
|
|
|
|
|
//............................................................
|
|
// BUFFER TRANSMITER
|
|
//............................................................
|
|
|
|
|
|
module pc_bufftx (reset, CLK, carga, load_shift, enable, datotx, TxD,
|
|
ParityEnable, Parity, ParityForced);
|
|
|
|
input reset; // Reset (H). Lo pone a UNOS.
|
|
input CLK; // Reloj del sistema
|
|
input carga; // Carga (H) nuevo dato
|
|
input load_shift; // Carga(H)/Desplaza(L) dato en reg P-S
|
|
input enable; // Habilitacion (H) del reg P-S
|
|
input [7:0] datotx; // Dato para transmitir
|
|
output TxD; // Salida
|
|
input ParityEnable; // Habilitacion de paridad
|
|
input Parity; // Paridad
|
|
input ParityForced; // Valor de paridad forzada.
|
|
|
|
|
|
// Variables
|
|
//.............................................................
|
|
|
|
reg [7:0] dato_tx; // Registro del dato para transmitir
|
|
reg [10:0] buftx; // Registro paralelo-serie del Transmisor
|
|
// buftx[8:1]=dato, buftx[9]=paridad
|
|
// buftx[0]=arranque, parada
|
|
wire TxD; // Salida
|
|
wire iparity; // Evaluacion de la paridad
|
|
//.............................................................
|
|
|
|
// iparity is 1 when number of ones is odd.
|
|
|
|
assign iparity = dato_tx[7] ^ dato_tx[6]
|
|
^ dato_tx[5] ^ dato_tx[4]
|
|
^ dato_tx[3] ^ dato_tx[2]
|
|
^ dato_tx[1] ^ dato_tx[0];
|
|
|
|
|
|
always @(posedge CLK or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
dato_tx <= 0;
|
|
buftx[10:0] <= 11'h7FF;
|
|
end
|
|
else casex ({load_shift, enable, carga})
|
|
3'bxx1: begin
|
|
dato_tx <= datotx;
|
|
end
|
|
|
|
3'b01x: begin
|
|
buftx[9:0] <= buftx[10:1];
|
|
buftx[10] <= 1;
|
|
end
|
|
|
|
3'b11x: begin
|
|
buftx[8:1] <= dato_tx;
|
|
buftx[0] <= 0;
|
|
|
|
casex ({ParityForced, Parity, ParityEnable})
|
|
3'bxx0: buftx[9] <= 1; // No parity
|
|
|
|
3'b001: buftx[9] <= ~iparity; // ODD parity
|
|
3'b011: buftx[9] <= iparity; // EVEN parity
|
|
3'b101: buftx[9] <= 1; // forced parity
|
|
3'b111: buftx[9] <= 0; // forced parity
|
|
|
|
endcase
|
|
|
|
end
|
|
|
|
endcase
|
|
end
|
|
|
|
assign TxD = buftx[0];
|
|
|
|
endmodule
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//............................................................
|
|
// RECEIVER CONTROL
|
|
//............................................................
|
|
|
|
module pc_ctrl_rx (reset, CLK, samples, rx_lleno);
|
|
|
|
input reset; // Reset (H)
|
|
input CLK; // Reloj del sistema
|
|
input samples; // Impulso de muestreo de RxDs conformado
|
|
output rx_lleno; // Indica (H) final de la recepcion de un caracter
|
|
|
|
// Variables
|
|
//.............................................................
|
|
|
|
reg rx_lleno; // Indica (H) final de la recepcion de un caracter
|
|
reg [3:0] cont_rx;// Contador de bits recibidos
|
|
|
|
//.............................................................
|
|
|
|
always @(posedge CLK or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
rx_lleno <= 0;
|
|
cont_rx <= 0;
|
|
end
|
|
else if (samples)
|
|
begin
|
|
cont_rx <= cont_rx + 1;
|
|
if (cont_rx==10)
|
|
begin
|
|
rx_lleno <= 1;
|
|
cont_rx <= 0;
|
|
end
|
|
else
|
|
rx_lleno <= 0;
|
|
end
|
|
else
|
|
rx_lleno <= 0;
|
|
end
|
|
|
|
endmodule
|
|
|
|
|
|
//............................................................
|
|
// TRANSMMITER CONTROL
|
|
//............................................................
|
|
|
|
module pc_ctrl_tx_pc (reset, CLK, carga, enable, load_shift,
|
|
tx_empty, txt_empty);
|
|
|
|
input reset; // Reset (H)
|
|
input CLK; // Reloj del sistema
|
|
input carga; // Carga (H) de un nuevo dato
|
|
input enable; // Habilitacion (H)
|
|
output load_shift; // Carga(H)/Desplaza(L) en reg P-S
|
|
output tx_empty; // Indica (H) TX vacio (PP)
|
|
output txt_empty; // Indica (H) TX totalmente vacio (PP y PS)
|
|
|
|
// Variables
|
|
//.............................................................
|
|
|
|
wire load_shift; // Carga(H)/Desplaza(L) en reg P-S
|
|
reg tx_empty; // Indica (H) buffer de tx vacio (PP)
|
|
wire txt_empty; // Indica (H) TX vacio (PP y PS)
|
|
reg tx_on; // Indica (H) transmision activa
|
|
reg [3:0] cont_tx; // Contador de bits transmitidos
|
|
|
|
//.............................................................
|
|
|
|
always @(posedge CLK or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
tx_empty <= 1;
|
|
tx_on <= 0;
|
|
cont_tx <= 0;
|
|
end
|
|
else begin
|
|
casex ({carga, load_shift})
|
|
2'b00: tx_empty <= tx_empty;
|
|
2'b01: tx_empty <= 1;
|
|
2'b1x: tx_empty <= 0;
|
|
endcase
|
|
|
|
|
|
if (enable)
|
|
if(tx_on) begin
|
|
cont_tx <= cont_tx + 1;
|
|
if (cont_tx==10) begin
|
|
cont_tx <= 0;
|
|
tx_on <= 0;
|
|
end
|
|
else
|
|
tx_on <= 1;
|
|
end
|
|
else if(load_shift)
|
|
tx_on <= 1;
|
|
|
|
|
|
end
|
|
|
|
end
|
|
|
|
assign load_shift = (cont_tx == 0) & enable & !tx_empty & !tx_on;
|
|
assign txt_empty = tx_empty & !tx_on;
|
|
|
|
endmodule
|
|
|
|
//............................................................
|
|
// ERROR AND READY CONTROL
|
|
//
|
|
//............................................................
|
|
|
|
module pc_dato_rdy (reset, CLK, rx_lleno, borrar_rdy, borrar_err,
|
|
dato_rdy, err_overrun);
|
|
|
|
input reset; // Reset (H)
|
|
input CLK; // Reloj del sistema
|
|
input rx_lleno; // Indica dato completo en el receptor
|
|
input borrar_rdy; // Indica lectura de DATO_RX
|
|
input borrar_err; // Indica lectura de STATUS_RX
|
|
output dato_rdy; // Indica (H) final de la recepcion de un caracter
|
|
output err_overrun; // Error de rebosamiento
|
|
|
|
// Variables
|
|
//.............................................................
|
|
|
|
reg dato_rdy;// Indica (H) final de la recepcion de un caracter
|
|
reg err_overrun; // Error de rebosamiento
|
|
|
|
//.............................................................
|
|
|
|
always @(posedge CLK or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
dato_rdy <= 0;
|
|
err_overrun <= 0;
|
|
end
|
|
else begin
|
|
if (rx_lleno)
|
|
dato_rdy <= 1;
|
|
else if (borrar_rdy)
|
|
dato_rdy <= 0;
|
|
|
|
if (rx_lleno & dato_rdy)
|
|
err_overrun <= 1;
|
|
else if(borrar_err)
|
|
err_overrun <= 0;
|
|
end
|
|
|
|
end
|
|
endmodule
|
|
|
|
|
|
//............................................................
|
|
// DIVIDER BY 27
|
|
//............................................................
|
|
|
|
module pc_div27 (reset, CLK, clk_in, clk_out);
|
|
|
|
input reset; // Reset (H)
|
|
input CLK; // Reloj del sistema
|
|
input clk_in; // Frecuencia de entrada
|
|
output clk_out; // Frecuencia de salida
|
|
|
|
// Variables
|
|
//.............................................................
|
|
|
|
reg [5:0] div27; // Registro para dividir la frecuencia de
|
|
// muestreo y obtener la de transmision
|
|
|
|
|
|
always @(posedge CLK or posedge reset)
|
|
begin
|
|
if (reset)
|
|
div27 <= 0;
|
|
else if (clk_in)
|
|
if (div27==26)
|
|
div27 <= 0;
|
|
else
|
|
div27 <= div27 + 1;
|
|
end
|
|
|
|
assign clk_out = (div27==26)?1:0;
|
|
|
|
endmodule
|
|
|
|
|
|
//............................................................
|
|
// DIVIDER BY 16
|
|
//............................................................
|
|
|
|
module pc_div16 (reset, CLK, clk_in, clk_out);
|
|
|
|
input reset; // Reset (H)
|
|
input CLK; // Reloj del sistema
|
|
input clk_in; // Frecuencia de entrada
|
|
output clk_out; // Frecuencia de salida
|
|
|
|
// Variables
|
|
//.............................................................
|
|
|
|
reg [3:0] div16; // Registro para dividir la frecuencia de
|
|
// muestreo y obtener la de transmision
|
|
|
|
|
|
always @(posedge CLK or posedge reset)
|
|
begin
|
|
if (reset)
|
|
div16 <= 0;
|
|
else if (clk_in)
|
|
if (div16==15)
|
|
div16 <= 0;
|
|
else
|
|
div16 <= div16 + 1;
|
|
end
|
|
|
|
assign clk_out = (div16==15)?1:0;
|
|
|
|
endmodule
|
|
|
|
|
|
|
|
|
|
//............................................................
|
|
// PROGRAMMABLE DIVIDER
|
|
//............................................................
|
|
|
|
module pc_div_ms (reset, CLK, clkin, cte_div, carga_div_low, carga_div_high, clk_out);
|
|
|
|
input reset; // Reset (H)
|
|
input CLK; // Reloj del sistema
|
|
input clkin; // Reloj escalado
|
|
input [7:0] cte_div;// Frecuencia de entrada
|
|
input carga_div_low; // Senal carga de la cte_div
|
|
input carga_div_high; // Senal carga de la cte_div
|
|
|
|
output clk_out;// Frecuencia de salida
|
|
|
|
// Variables
|
|
//.............................................................
|
|
|
|
reg [15:0] div; // Contador del divisor
|
|
reg [15:0] k_div; // Factor de division
|
|
reg clk_out;// Frecuencia de salida
|
|
|
|
|
|
always @(posedge CLK or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
div <= 0;
|
|
k_div <= 1;
|
|
end
|
|
else begin
|
|
if (carga_div_low)
|
|
k_div[7:0] <= cte_div;
|
|
if (carga_div_high)
|
|
k_div[15:8] <= cte_div;
|
|
if (carga_div_low | carga_div_high) div<=0;
|
|
if (div==k_div) begin
|
|
div <= 0;
|
|
clk_out <= 1;
|
|
end
|
|
else begin
|
|
if (clkin)
|
|
begin
|
|
div <= div + 1;
|
|
clk_out <= 0;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
endmodule
|
|
|
|
|
|
module pc_ier (reset, CLK, carga_IER, data_in, dato_rdy, tx_empty, modem_int, nIRQ, IER);
|
|
|
|
input reset;
|
|
input CLK;
|
|
input carga_IER;
|
|
input [7:0] data_in;
|
|
|
|
input dato_rdy;
|
|
input tx_empty;
|
|
input modem_int;
|
|
output nIRQ; // Data Terminal Ready
|
|
|
|
output [3:0] IER;
|
|
reg [3:0] IER;
|
|
|
|
assign nIRQ= ~|(IER & {modem_int, dato_rdy, tx_empty, dato_rdy});
|
|
|
|
always @(posedge CLK)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
IER<=4'b0;
|
|
end
|
|
else
|
|
|
|
if (carga_IER)
|
|
begin
|
|
IER<=data_in[3:0];
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
endmodule
|
|
|
|
|
|
|
|
//............................................................
|
|
// ARM INTERFACE
|
|
//............................................................
|
|
|
|
|
|
// ADD nRW FUNCTION
|
|
// 000 0 Rx Register.
|
|
// 000 1 TX Register. If enabled, LSB Divisor Latch.
|
|
//
|
|
// 001 0 NA
|
|
// 001 1 Interrupt Enable Register. If enabled, MSB Divisor Latch.
|
|
//
|
|
// 010 0 Interrupt Status Register.
|
|
// 010 1 FIFO Control Register (Not Implemented).
|
|
//
|
|
// 011 0 NA
|
|
// 011 1 Line Control Register
|
|
//
|
|
// 100 0 NA
|
|
// 100 1 Modem Control Register
|
|
//
|
|
//
|
|
// 101 0 Line Status Register
|
|
// 101 1 NA
|
|
//
|
|
// 110 0 Modem Status Register
|
|
// 110 1 NA
|
|
//
|
|
// 111 01 Scratch Pad Register
|
|
//
|
|
|
|
module pc_if_arm_pc (reset, CLK, data_in, data_out, add, nRW, CS,
|
|
borrar_rdy, borrar_err, carga, carga_div_low, carga_div_high,
|
|
carga_IER, carga_MCR, carga_LCR, carga_MSR, carga_ISR,
|
|
BaudSelect, dato_rx, modem, ISR, LSR, LCR);
|
|
|
|
input reset; // Reset (H)
|
|
input CLK; // Reloj del sistema
|
|
input [7:0] data_in; // Bus de datos de entrada
|
|
output [7:0] data_out; // Bus de datos de salida
|
|
input [2:0] add; // Bus de direcciones
|
|
input nRW; // senal de lectura del ARM
|
|
input CS; // senal de seleccion de la UART
|
|
input [7:0] dato_rx; // Dato recibido
|
|
output borrar_rdy; // Borrar dato_rdy tras leer DATO_RX
|
|
output borrar_err; // Borrar err_over tras leer STATUS_RX
|
|
output carga; // Senal carga
|
|
output carga_div_low; // Senal carga de la cte_div (byte bajo)
|
|
output carga_div_high; // Senal carga de la cte_div (byte alto)
|
|
output carga_IER; // senal carga IER
|
|
output carga_MCR; // senal carga MCR
|
|
output carga_LCR; // senal carga LCR
|
|
output carga_MSR; // senal carga MSR (para codificacion delta)
|
|
output carga_ISR; // senal carga de ISR
|
|
input BaudSelect; // seleccion de modo de acceso
|
|
input [7:0] modem; // modem bus
|
|
input [3:0] ISR; // Interrupt Status Register
|
|
input [7:0] LSR; // Line Status Register
|
|
input [7:0] LCR; // Line Control Register
|
|
|
|
|
|
// Variables
|
|
//.............................................................
|
|
|
|
reg [7:0] data_out; // Bus de datos de salida
|
|
reg carga; // Senal carga
|
|
reg carga_div_low; // Senal carga de la cte_div (byte bajo)
|
|
reg carga_div_high; // Senal carga de la cte_div (byte alto)
|
|
reg carga_IER; // senal carga IER
|
|
reg carga_MCR; // senal carga MCR
|
|
reg carga_LCR; // senal carga LCR
|
|
reg carga_MSR; // senal lectura del MSR (para puesta a 0)
|
|
reg carga_ISR; // senal recarga del ISR
|
|
reg borrar_rdy; // Borrar dato_rdy tras leer DATO_RX
|
|
reg borrar_err; // Borrar err_over tras leer STATUS_RX
|
|
reg [7:0] dato_tx; // Dato para transmitir
|
|
|
|
|
|
|
|
//.............................................................
|
|
|
|
|
|
|
|
always @(nRW or CS or add or dato_rx or LSR or ISR or LCR or modem or BaudSelect)
|
|
if (CS)
|
|
begin
|
|
casex ({nRW, add})
|
|
6'b0000: begin //Lectura de DATO_RX
|
|
data_out <= dato_rx;
|
|
borrar_rdy <= 1;
|
|
borrar_err <= 0;
|
|
carga <= 0;
|
|
carga_div_low <= 0;
|
|
carga_div_high <= 0;
|
|
carga_IER <= 0;
|
|
carga_MCR <= 0;
|
|
carga_LCR <= 0;
|
|
carga_MSR <= 0;
|
|
carga_ISR <= 0;
|
|
end
|
|
|
|
6'b1000: begin //Escritura Baud_Rate
|
|
if (BaudSelect)
|
|
begin
|
|
carga_div_low <= 1;
|
|
carga <= 0;
|
|
end
|
|
else //Escritura de DATO_TX
|
|
begin
|
|
carga_div_low <= 0;
|
|
carga <= 1;
|
|
end
|
|
carga_div_high <= 0;
|
|
carga_IER <= 0;
|
|
carga_MCR <= 0;
|
|
carga_LCR <= 0;
|
|
carga_MSR <= 0;
|
|
carga_ISR <= 0;
|
|
data_out <= dato_rx;
|
|
borrar_rdy <= 0;
|
|
borrar_err <= 0;
|
|
end
|
|
|
|
6'b1001: begin //Escritura Baud_Rate
|
|
if (BaudSelect)
|
|
begin
|
|
carga_div_high <= 1;
|
|
carga_IER <= 0;
|
|
end
|
|
else //Escritura de IER
|
|
begin
|
|
carga_div_high <= 0;
|
|
carga_IER <= 1;
|
|
end
|
|
carga <= 0;
|
|
carga_div_low <= 0;
|
|
carga_MCR <= 0;
|
|
carga_LCR <= 0;
|
|
carga_MSR <= 0;
|
|
carga_ISR <= 0;
|
|
data_out <= dato_rx;
|
|
borrar_rdy <= 0;
|
|
borrar_err <= 0;
|
|
end
|
|
|
|
|
|
6'b0010: begin //Lectura ISR
|
|
carga <= 0;
|
|
carga_div_low <= 0;
|
|
carga_div_high <= 0;
|
|
data_out <= ISR;
|
|
carga_IER <= 0;
|
|
carga_MCR <= 0;
|
|
carga_LCR <= 0;
|
|
carga_MSR <= 0;
|
|
carga_ISR <= 1;
|
|
borrar_rdy <= 0;
|
|
borrar_err <= 0;
|
|
end
|
|
|
|
|
|
6'b1010: begin //Escritura FCR (no implementado)
|
|
carga <= 0;
|
|
carga_div_low <= 0;
|
|
carga_div_high <= 0;
|
|
carga_IER <= 0;
|
|
carga_MCR <= 0;
|
|
carga_LCR <= 0;
|
|
carga_MSR <= 0;
|
|
carga_ISR <= 0;
|
|
data_out <= dato_rx;
|
|
borrar_rdy <= 0;
|
|
borrar_err <= 0;
|
|
end
|
|
|
|
|
|
6'b0011: begin //Lectura LCR
|
|
carga <= 0;
|
|
carga_div_low <= 0;
|
|
carga_div_high <= 0;
|
|
carga_IER <= 0;
|
|
carga_MCR <= 0;
|
|
carga_LCR <= 0;
|
|
carga_MSR <= 0;
|
|
carga_ISR <= 0;
|
|
data_out <= LCR;
|
|
borrar_rdy <= 0;
|
|
borrar_err <= 0;
|
|
end
|
|
|
|
|
|
6'b1011: begin //Escritura LCR
|
|
carga <= 0;
|
|
carga_div_low <= 0;
|
|
carga_div_high <= 0;
|
|
carga_IER <= 0;
|
|
carga_MCR <= 0;
|
|
carga_LCR <= 1;
|
|
carga_MSR <= 0;
|
|
carga_ISR <= 0;
|
|
data_out <= dato_rx;
|
|
borrar_rdy <= 0;
|
|
borrar_err <= 0;
|
|
end
|
|
|
|
|
|
6'b1100: begin //Escritura de MCR
|
|
carga <= 0;
|
|
carga_div_low <= 0;
|
|
carga_div_high <= 0;
|
|
carga_IER <= 0;
|
|
carga_MCR <= 1;
|
|
carga_LCR <= 0;
|
|
carga_MSR <= 0;
|
|
carga_ISR <= 0;
|
|
data_out <= dato_rx;
|
|
borrar_rdy <= 0;
|
|
borrar_err <= 0;
|
|
end
|
|
|
|
6'b0101: begin //Lectura del LSR
|
|
carga<=0;
|
|
carga_div_low<=0;
|
|
carga_div_high<=0;
|
|
carga_IER<=0;
|
|
carga_MCR<=0;
|
|
carga_LCR<=0;
|
|
carga_MSR<=0;
|
|
carga_ISR<=0;
|
|
data_out <= LSR;
|
|
borrar_rdy <= 0;
|
|
borrar_err <= 0;
|
|
end
|
|
|
|
|
|
6'b0110: begin //Lectura del MSR
|
|
carga<=0;
|
|
carga_div_low<=0;
|
|
carga_div_high<=0;
|
|
carga_IER<=0;
|
|
carga_MCR<=0;
|
|
carga_LCR<=0;
|
|
carga_MSR<=1;
|
|
carga_ISR<=0;
|
|
data_out <= modem;
|
|
borrar_rdy <= 0;
|
|
borrar_err <= 0;
|
|
end
|
|
/*
|
|
6'b0111: begin
|
|
carga<=0;
|
|
carga_div_low<=0;
|
|
carga_div_high<=0;
|
|
carga_IER<=0;
|
|
carga_MCR<=0;
|
|
carga_LCR<=0;
|
|
carga_ISR<=0;
|
|
data_out <= dato_rx;
|
|
borrar_rdy <= 0;
|
|
borrar_err <= 0;
|
|
end
|
|
|
|
6'b1111: begin
|
|
carga<=0;
|
|
carga_div_low<=0;
|
|
carga_div_high<=0;
|
|
carga_IER<=0;
|
|
carga_MCR<=0;
|
|
carga_LCR<=0;
|
|
carga_ISR<=0;
|
|
data_out <= dato_rx;
|
|
borrar_rdy <= 0;
|
|
borrar_err <= 0;
|
|
end
|
|
*/
|
|
|
|
default:
|
|
begin
|
|
carga<=0;
|
|
carga_div_low<=0;
|
|
carga_div_high<=0;
|
|
carga_IER<=0;
|
|
carga_MCR<=0;
|
|
carga_LCR<=0;
|
|
carga_MSR<=0;
|
|
carga_ISR<=0;
|
|
data_out <= dato_rx;
|
|
borrar_rdy <= 0;
|
|
borrar_err <= 0;
|
|
end
|
|
|
|
endcase
|
|
end
|
|
else
|
|
begin
|
|
carga<=0;
|
|
carga_div_low<=0;
|
|
carga_div_high<=0;
|
|
carga_IER<=0;
|
|
carga_MCR<=0;
|
|
carga_LCR<=0;
|
|
carga_MSR<=0;
|
|
carga_ISR<=0;
|
|
data_out <= dato_rx;
|
|
borrar_rdy <= 0;
|
|
borrar_err <= 0;
|
|
end
|
|
endmodule
|
|
|
|
|
|
|
|
//............................................................
|
|
// RxD INTERFACE
|
|
//............................................................
|
|
|
|
module pc_ifrxd (reset, CLK, clkms, RxD, RxDs);
|
|
|
|
input reset; // Reset (H)
|
|
input CLK; // Reloj del sistema
|
|
input clkms; // Reloj de muestreo sincronizado (el nivel
|
|
// alto dura un periodo de reloj)
|
|
input RxD; // Linea de recepcion de datos
|
|
output RxDs; // RxD sincronizada y limpia
|
|
|
|
// Variables
|
|
//.............................................................
|
|
|
|
reg [2:0] ifrxd; // Registro interfaz de la linea RxD
|
|
|
|
|
|
//.............................................................
|
|
|
|
always @(posedge CLK or posedge reset)
|
|
begin
|
|
if (reset)
|
|
ifrxd <= 3'b111;
|
|
else if (clkms)
|
|
begin
|
|
if ((ifrxd[0]==ifrxd[2]) & (ifrxd[0]!=ifrxd[1]))
|
|
ifrxd[2] <= ifrxd[0];
|
|
else
|
|
ifrxd[2] <= ifrxd[1];
|
|
ifrxd[1] <= ifrxd[0];
|
|
ifrxd[0] <= RxD;
|
|
end
|
|
end
|
|
|
|
assign RxDs = ifrxd[2];
|
|
|
|
endmodule
|
|
module pc_isr (reset, CLK,
|
|
carga_ISR,
|
|
err_paridad, err_frame, err_overrun,
|
|
dato_rdy, tx_empty, txt_empty, modem_int,
|
|
ISR, LSR, IER);
|
|
|
|
input reset;
|
|
input CLK;
|
|
input carga_ISR;
|
|
input err_paridad;
|
|
input err_frame;
|
|
input err_overrun;
|
|
input dato_rdy;
|
|
input tx_empty;
|
|
input txt_empty;
|
|
input modem_int;
|
|
|
|
output [3:0] ISR; // Interrupt Status Register
|
|
output [7:0] LSR; // Line Status Register
|
|
input [3:0] IER; // Interrupt Enable Register
|
|
|
|
reg [3:0] ISR;
|
|
reg [3:0] ISRt;
|
|
|
|
reg mask_error;
|
|
reg mask_dato_rdy;
|
|
reg mask_err_overrun;
|
|
reg mask_tx_empty;
|
|
reg mask_modem_int;
|
|
reg carga_ISRd;
|
|
reg aux1;
|
|
|
|
wire error, errorm, dato_rdym, err_overrunm, tx_emptym, modem_intm;
|
|
|
|
|
|
assign errorm= error & mask_error & IER[1];
|
|
assign dato_rdym= dato_rdy & mask_dato_rdy & IER[0];
|
|
assign err_overrunm= err_overrun & mask_err_overrun;
|
|
assign tx_emptym= tx_empty & mask_tx_empty & IER[1];
|
|
assign modem_intm= modem_int & mask_modem_int & IER[3];
|
|
|
|
|
|
always @(errorm or dato_rdym or tx_emptym or err_overrunm or modem_intm)
|
|
begin
|
|
if (errorm) ISRt=4'b0110;
|
|
else if (dato_rdym) ISRt=4'b0100;
|
|
//else if (err_overrunm) ISRt=4'b1100;
|
|
else if (tx_emptym) ISRt=4'b0010;
|
|
else if (modem_intm) ISRt=4'b0000;
|
|
else ISRt=4'b0001;
|
|
end
|
|
|
|
assign error = err_paridad | err_frame | err_overrun;
|
|
assign LSR = {error, txt_empty, tx_empty, 1'b0, err_frame, err_paridad, err_overrun, dato_rdy};
|
|
|
|
always @(posedge CLK)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
ISR<=4'b0001;
|
|
mask_error<=1;
|
|
mask_dato_rdy<=1;
|
|
mask_err_overrun<=1;
|
|
mask_tx_empty<=1;
|
|
mask_modem_int<=1;
|
|
carga_ISRd<=0;
|
|
aux1<=1'b0;
|
|
end
|
|
else
|
|
begin
|
|
|
|
if (mask_error)
|
|
begin
|
|
if ((ISR==4'b0110) & carga_ISRd) mask_error<=0;
|
|
end
|
|
else
|
|
if (error) mask_error<=1;
|
|
|
|
if (mask_dato_rdy)
|
|
begin
|
|
if ((ISR==4'b0100) & carga_ISRd) mask_dato_rdy<=0;
|
|
end
|
|
else
|
|
if (dato_rdy) mask_dato_rdy<=1;
|
|
|
|
if (mask_err_overrun)
|
|
begin
|
|
if ((ISR==4'b1100) & carga_ISRd) mask_err_overrun<=0;
|
|
end
|
|
else
|
|
if (err_overrun) mask_err_overrun<=1;
|
|
|
|
if (mask_tx_empty)
|
|
begin
|
|
if ((ISR==4'b0010) & carga_ISRd) mask_tx_empty<=0;
|
|
end
|
|
else
|
|
if (tx_empty) mask_tx_empty<=1;
|
|
|
|
if (mask_modem_int)
|
|
begin
|
|
if ((ISR==4'b0000) & carga_ISRd) mask_modem_int<=0;
|
|
end
|
|
else
|
|
if (modem_int) mask_modem_int<=1;
|
|
|
|
ISR<=ISRt;
|
|
aux1<=carga_ISR; //Espera a que se deseleccione el carga_ISR para modificar mascaras.
|
|
if (~carga_ISR)
|
|
begin
|
|
carga_ISRd<=aux1;
|
|
aux1<=1'b0;
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
|
|
endmodule
|
|
|
|
|
|
module pc_lcr (reset, CLK, LCR,
|
|
carga_LCR,
|
|
data_in,
|
|
WordLength, Stop, ParityEnable, Parity,
|
|
ParityForced, Break, BaudSelect);
|
|
|
|
input reset;
|
|
input CLK;
|
|
output [7:0] LCR;
|
|
input carga_LCR;
|
|
input [7:0] data_in;
|
|
|
|
output [1:0] WordLength;
|
|
output Stop;
|
|
output ParityEnable;
|
|
output Parity;
|
|
output ParityForced;
|
|
output Break;
|
|
output BaudSelect;
|
|
|
|
reg [7:0] LCR;
|
|
|
|
|
|
assign WordLength={LCR[1],LCR[0]};
|
|
assign Stop=LCR[2];
|
|
assign ParityEnable=LCR[3];
|
|
assign Parity=LCR[4];
|
|
assign ParityForced=LCR[5];
|
|
assign Break=LCR[6];
|
|
assign BaudSelect=LCR[7];
|
|
|
|
|
|
|
|
always @(posedge CLK)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
LCR<=8'b0; //Ver hoja de datos de ST16C552.
|
|
//Esta es la situacion en reset.
|
|
end
|
|
else
|
|
|
|
if (carga_LCR)
|
|
begin
|
|
LCR<=data_in;
|
|
end
|
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
endmodule
|
|
|
|
|
|
//module pc_modem(reset, CLK,
|
|
// carga_MCR, carga_MSR,
|
|
// data_in, modem,
|
|
// CD, RI, DSR, CTS, DTR, RTS, modem_int);
|
|
//
|
|
//input reset;
|
|
//input CLK;
|
|
//input carga_MCR;
|
|
//input carga_MSR;
|
|
//input [7:0] data_in;
|
|
//output [7:0] modem;
|
|
//input CD; // Carrier Detect
|
|
//input RI; // Ring Indicator
|
|
//input DSR; // Data Send Ready
|
|
//input CTS; // Clear To Send
|
|
//output RTS; // Request To Send
|
|
//output DTR; // Data Terminal Ready
|
|
//output modem_int;
|
|
//
|
|
//reg RTS;
|
|
//reg DTR;
|
|
//
|
|
//reg dCD, sCD;
|
|
//reg dRI, sRI;
|
|
//reg dDSR, sDSR;
|
|
//reg dCTS, sCTS;
|
|
//wire [7:0] modem;
|
|
//reg modem_int;
|
|
//
|
|
//
|
|
//assign modem ={~sCD, ~sRI, ~sDSR, ~sCTS,
|
|
// dCD ^ sCD, dRI ^ sRI, dDSR ^ sDSR, dCTS ^ sCTS};
|
|
//
|
|
//
|
|
//always @(posedge CLK)
|
|
//begin
|
|
// if (reset)
|
|
// begin
|
|
// dCD<=1; sCD<=1;
|
|
// dRI<=1; sRI<=1;
|
|
// dDSR<=1; sDSR<=1;
|
|
// dCTS<=1; sCTS<=1;
|
|
// DTR<=1;
|
|
// RTS<=1;
|
|
// modem_int<=0;
|
|
// end
|
|
// else
|
|
// begin
|
|
// sCD<=~CD;
|
|
// sRI<=~RI;
|
|
// sDSR<=~DSR;
|
|
// sCTS<=~CTS;
|
|
//
|
|
// modem_int<=modem_int | (|modem[3:0]);
|
|
//
|
|
// if (carga_MCR)
|
|
// begin
|
|
// RTS<=~data_in[0];
|
|
// DTR<=~data_in[1];
|
|
// end
|
|
//
|
|
// else
|
|
// if (carga_MSR)
|
|
// begin
|
|
// dCD<=~CD;
|
|
// dRI<=~RI;
|
|
// dDSR<=~DSR;
|
|
// dCTS<=~CTS;
|
|
// modem_int<=0; //Limpieza de la interrupcion
|
|
// end
|
|
//
|
|
//
|
|
// end
|
|
//
|
|
//end
|
|
//
|
|
//
|
|
//
|
|
//
|
|
//endmodule
|
|
//
|
|
|
|
//............................................................
|
|
// RxDs SAMPLER
|
|
//............................................................
|
|
|
|
module pc_muestreo (reset, CLK, rst_muestreo, clkms, RxDs, sample);
|
|
|
|
input reset; // Reset (H)
|
|
input CLK; // Reloj del sistema
|
|
input rst_muestreo; // Reset (H) del circuito de muestreo
|
|
input clkms; // Reloj de muestreo sincronizado (el nivel
|
|
// alto dura un periodo de reloj)
|
|
input RxDs; // Senal RxD sincronizada y limpia
|
|
output sample; // Impulso de muestreo de la senal RxDs
|
|
|
|
// Variables
|
|
//.............................................................
|
|
|
|
reg [3:0] cont_m; // Contador del circuito de muestreo
|
|
reg flag_rx;// Indicador de recepcion en curso
|
|
reg sample; // Impulso de muestreo de la senal RxDs
|
|
|
|
|
|
//.............................................................
|
|
|
|
always @(posedge CLK or posedge reset)
|
|
begin
|
|
if (reset)
|
|
begin
|
|
cont_m <= 4'b0000;
|
|
sample <= 0;
|
|
flag_rx <= 0;
|
|
end
|
|
else if (rst_muestreo)
|
|
begin
|
|
cont_m <= 4'b0000;
|
|
sample <= 0;
|
|
flag_rx <= 0;
|
|
end
|
|
else if (clkms)
|
|
if ( (flag_rx==0) & (RxDs==0) ) // Arranque
|
|
flag_rx <= 1; // Recepcion en curso
|
|
else if (flag_rx)
|
|
begin
|
|
cont_m <= cont_m + 1;
|
|
if (cont_m==4'b0110)
|
|
sample <= 1;
|
|
else
|
|
sample <= 0;
|
|
end
|
|
end
|
|
|
|
endmodule
|
|
|
|
|
|
|
|
//............................................................
|
|
// TIMING CONTROL
|
|
//............................................................
|
|
|
|
module pc_pulso (reset, CLK, dato_asyn, dato_syn);
|
|
|
|
input reset; // Reset (H)
|
|
input CLK; // Reloj del sistema
|
|
input dato_asyn; // Entrada de dato asincrona
|
|
output dato_syn; // Salida de dato conformada
|
|
|
|
// Variables
|
|
//.............................................................
|
|
|
|
reg dff; // Registro del sincronizador
|
|
|
|
always @(posedge CLK or posedge reset)
|
|
begin
|
|
if (reset)
|
|
dff <= 0;
|
|
else
|
|
dff <= dato_asyn;
|
|
end
|
|
|
|
assign dato_syn = !dff & dato_asyn;
|
|
|
|
endmodule |