def PWM(clk_i, d_i, pwm_o, CLK_FREC, PWM_FREC) : n = len(d_i) CUENTA_DIVISOR = int(round(CLK_FREC / ( PWM_FREC * 2**n ))) cuenta_div = Signal(intbv(0, 0, CUENTA_DIVISOR + 1)) cuenta_pwm = Signal(intbv(0)[n:]) dato = Signal(intbv(0)[n:]) rst_pwm = Signal(Lo) ce_pwm = Signal(Lo) contador_div = CB_R(clk_i = clk_i, # "Divisor de frecuencia" rst_i = ce_pwm, q_o = cuenta_div) @always(cuenta_div) def gen_ce_pwm() : if cuenta_div == CUENTA_DIVISOR - 1 : ce_pwm.next = Hi else : ce_pwm.next = Lo contador_pwm = CB_RE(clk_i = clk_i, rst_i = rst_pwm, ce_i = ce_pwm, q_o = cuenta_pwm) reg_dato = FD_E(clk_i = clk_i, ce_i = rst_pwm, d_i = d_i, q_o = dato) @always(cuenta_pwm, ce_pwm) def gen_rst_pwm() : if ce_pwm and cuenta_pwm == 2**n - 1 : rst_pwm.next = Hi else : rst_pwm.next = Lo @always(cuenta_pwm, dato) def gen_pwm_o() : if cuenta_pwm < dato : pwm_o.next = Hi else : pwm_o.next = Lo return instances()
def Monoestable(clk_i, rst_i, a_i, q_o, FREC_CLK=27e6, TIEMPO=240e-9): """Este modulo genera una senal que dura un tiempo determinado cuando es disparada por a_i :Parametros: - `clk_i` : entrada de clock - `rst_i` : senal de reset - `a_i` : senal de disparo - `q_o` : salida triguereada Funcionamiento:: _ _ _ _ _ _ _ _ _ _ _ _ clk_i | |_| |_| |_| |_| |_| | ... | |_| |_| |_| |_| |_| | __ a_i ______| |_______________ ... _______________________ _______________ ... __________ q_o _________| |______________ :Nota: a_i debe estar sincronica con el clk """ CUENTA_MAX = int(round(TIEMPO * FREC_CLK)) cuenta = Signal(intbv(0, 0, CUENTA_MAX + 1)) ena = Signal(Lo) flanco = Signal(Lo) e = enum("ESP_FLANCO", "CUENTA") estado = Signal(e.ESP_FLANCO) cont_1 = CB_RE(clk_i=clk_i, rst_i=flanco, ce_i=ena, q_o=cuenta) flanco_1 = detecta_flanco_subida(clk_i=clk_i, a_i=a_i, flanco_o=flanco) @always(clk_i.posedge) def FSM(): if rst_i: estado.next = e.ESP_FLANCO else: if estado == e.ESP_FLANCO: if flanco: estado.next = e.CUENTA ena.next = Hi q_o.next = Hi elif estado == e.CUENTA: if cuenta == CUENTA_MAX - 1: ena.next = Lo q_o.next = Lo estado.next = e.ESP_FLANCO return instances()
def conversion_half_precision(clk_i, x_i, signo_x_i, bits_entero, ini_i, fl_x_o, done_o): """Conversor a punto flotante half-precision:: signo_x : 0 = +, 1 = - x : bn --- b16 b15 b14 . b13 b12 b11 b10 b9 b8 b7 b6 b5 b4 b3 b2 b1 b0 |______________| | bits_entero fl_x : S | Exp + 15 | mantisa | | | cant_bits 1 5 10 x = (-1)^S * 2^Exp * 1.mantisa :Nota: la parte fraccionaria de x_i debe tener 14 bits, ya que el valor minimo positivo que se puede representar en half precision es 2**-14 y como el maximo es 65504, la parte entera de x_i puede tener hasta 16 bits (Tener en cuenta que esta implementacion solo convierte los numeros normalizados y el cero, si x_i > 65504, el conversor no funciona) """ n = len(x_i) m = len(fl_x_o) # 16 para half precision fl_x = Signal(intbv(0)[m:]) # Flotante Half Precision x_q = Signal(intbv(0)[n:]) pos = Signal(intbv(0, 0, n + 1)) # Pos del primer 1 de x_i exp = Signal(intbv(0)[5:]) mantisa = Signal(intbv(0)[10:]) k = 15 + bits_entero - 1 # exponente real = bits_entero - 1 - pos # exponente desplazado por norma = 15 + exponente real = k - pos fin_contador = Signal( Lo) # fin_contador indica que x_i es cero => expo = 0 encontrado = Signal( Lo ) # Indica que se encontro la pos en x_i que tiene el 1 de mayor peso fin_busqueda = Signal( Lo ) # Indica que se encontro la pos en x_i que tiene el 1 de mayor peso o x_i es cero cargar = Signal(Lo) # Carga x_i en el shift register despl_y_contar = Signal( Lo ) # Desplaza a la izquierda x y cuenta la pos para saber donde esta el 1 de mayor peso en x latch = Signal(Lo) # Antes de levantar la bandera de done, "latcheo" fl_x # Datapath reg = SR_LE_PiPo_Izq( clk_i=clk_i, load_i=cargar, d_i=x_i, ce_i=despl_y_contar, q_o=x_q) # Desplazo x a la izquierda para encontrar el 1 de mayor peso @always_comb def extrae_mantisa(): mantisa.next = x_q[ n - 1:n - 11] # La mantisa son los 10 bits despues del 1 de mayor peso @always_comb def conexion_encontrado(): encontrado.next = x_q[n - 1] @always_comb def fin_busq(): fin_busqueda.next = fin_contador | encontrado contador = CB_RE( clk_i=clk_i, rst_i=cargar, ce_i=despl_y_contar, q_o=pos ) # Contador para conocer la pos del 1 de mayor peso de x_i y luego calcular el exponente @always(pos) def fin_cont(): if pos == n: fin_contador.next = Hi else: fin_contador.next = Lo @always_comb def restador(): exp.next = k - pos @always_comb def conex_fl(): fl_x.next = concat(signo_x_i, exp, mantisa) reg_fl = FD_E(clk_i=clk_i, ce_i=latch, d_i=fl_x, q_o=fl_x_o) ######## Unidad de control del conversor e = enum("ESPERA_INICIO", "BUSQUEDA", "FIN") estado = Signal(e.ESPERA_INICIO) @always(clk_i.posedge) def FSM_estados(): "Logica de cambio de estados" ############################## if estado == e.ESPERA_INICIO: if ini_i: estado.next = e.BUSQUEDA ############################## elif estado == e.BUSQUEDA: if fin_busqueda: estado.next = e.FIN ############################## elif estado == e.FIN: estado.next = e.ESPERA_INICIO else: estado.next = e.ESPERA_INICIO @always(estado, ini_i, fin_busqueda) def FSM_salidas(): "Logica de salida" ############################## if estado == e.ESPERA_INICIO: done_o.next = Hi latch.next = Lo despl_y_contar.next = Lo if ini_i: cargar.next = Hi else: cargar.next = Lo ############################## elif estado == e.BUSQUEDA: done_o.next = Lo cargar.next = Lo if fin_busqueda: despl_y_contar.next = Lo latch.next = Hi else: despl_y_contar.next = Hi latch.next = Lo ############################# elif estado == e.FIN: done_o.next = Lo latch.next = Lo despl_y_contar.next = Lo cargar.next = Lo else: done_o.next = Lo latch.next = Lo despl_y_contar.next = Lo cargar.next = Lo return instances()
def FIFO(clk_i, ce_i, d_i, q_o, k): """Estrucutra FIFO de k etapas y n bits de datos con clock enable :: ________________________ ____| |____ ____| d_i q_o |____ | | ----|> clk_i | | | ----| ce_i | |________________________| :Parametros: - `clk_i` : entrada de clock - `ce_i` : clock enable - `d_i` : data in (n bits) - `q_o` : data out (n bits) - `k` : longitud de la cola """ # Descripcion estructural # n = len(d_i) addr_max = k - 1 rst_cont = Signal(Lo) w_addr = Signal(intbv(0, 0, k)) # Puntero de llenado de la cola (Puerto A) r_addr = Signal(intbv(1, 0, k)) # Puntero de vaciado o lectura (Puerto B) p = len(w_addr) if n == 1: ram = [Signal(Lo) for i in range(2**p)] else: ram = [Signal(intbv(0)[n:]) for i in range(2**p)] ############################################### gen_w_addr = CB_RE(clk_i=clk_i, rst_i=rst_cont, ce_i=ce_i, q_o=w_addr) # Puntero de llenado @always(w_addr, ce_i) def gen_r_addr(): if w_addr == addr_max: rst_cont.next = ce_i r_addr.next = 0 else: rst_cont.next = Lo r_addr.next = w_addr + 1 # El puntero de vaciado esta uno por delante del de llenado @always(clk_i.posedge) def RAM_access(): if ce_i: ram[int(w_addr)].next = d_i q_o.next = ram[int(r_addr)] return instances()
def genera_coord_PAL(clk27_i, vs_i, hs_i, odd_even_i, pix_ce_o, pixel_x_o, pixel_y_o, video_activo_o, ini_frame_o): """Este modulo genera las coordenadas (x,y) del pixel activo actual de un sistema PAL (720x576i). :: x *---> | ------------------------- y v |(0,0) | | | | | | Zona activa | | de video | | | | | | (719,575)| ------------------------- :Parametros: - `clk27_i` -- entrada de clock de pixel x2 ( 27Mhz ) - `vs_i` -- entrada de sincronismo vertical - `hs_i` -- entrada de sincronismo horizontal - `odd_even_i` -- entrada de campo odd/even - `pix_ce_o` -- salida de pixel clock enable - `pixel_x_o` -- salida de la coordenada x del pixel activo actual [0 .. 720] - `pixel_y_o` -- salida de la coordenada y del pixel activo actual [0 .. 576] - `video_activo_o` -- salida que determina la ventana temporal del video activo - `ini_frame_o` -- inicio del frame """ # Info del Horiz PIXELS_x_LINEA = 864 # Cantidad de pixels de una linea de video PIXELS_x_LINEA_ACTIVA = 720 # Cantidad de pixels activos de una linea de video PIXELS_x_SYNC_H = 64 # Cantidad de pixels del pulso de sinc h. PIXELS_x_BP = 68 # Cantidad de pixels de back porch INICIO_X = PIXELS_x_SYNC_H + PIXELS_x_BP - 6 # Comienzo del pixel activo en la linea (Nota el -6 es por atraso en el tracker analogico) # Info del Vert TOTAL_LINEAS = 625 # Total de lineas del PAL LINEAS_ACTIVAS = 576 # Cantidad de lineas activas de video LINEA_INI_VIDEO_ACTIVO_ODD = 21 # Linea de comienzo del video activo en el campo impar LINEA_FIN_VIDEO_ACTIVO_ODD = 308 # Linea de finalizacion del video activo en el campo impar LINEA_INI_VIDEO_ACTIVO_EVEN = 334 # Linea de comienzo del video activo en el campo par LINEA_FIN_VIDEO_ACTIVO_EVEN = 621 # Linea de finalizacion del video activo en el campo par # Senales y registros ini_hs = Signal(Lo) # Pulso de inicio de sincronismo horizontal ini_vs = Signal(Lo) # Inicio de sincronismo vertical pix_ce = Signal(Lo) # Clock enable para contar pixels barrido_x = Signal(intbv( 0, 0, PIXELS_x_LINEA)) # Registros para llevar la posicion del barrido nro_linea = Signal(intbv(0, 0, TOTAL_LINEAS)) # ini_odd = Signal(Lo) # Pulso de inicio de campo impar rst_aux = Signal(Lo) rst_n_lineas = Signal(Lo) # Reset del contador de lineas video_activo_x = Signal(Lo) video_activo_y = Signal(Lo) ######################################################################################################## # # Horizontal # ========== # _____________ __________________________________ # hs |_____________________________ *** # _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ # clk @ 27MHz _| |_| |_| |_| |_| |_| |_| |_| |_| |_| |_| *** _| |_| |_| |_| |_| |_| |_| |_| |_| # ___ # ini_hs _____________| |_________________________ *** __________________________________ # ___ ___ ___ ___ ___ _ ___ ___ ___ ___ # pix_ce |___| |___| |___| |___| |___| |_ *** |___| |___| |___| |___| | # # barrido_x ] 862 ] 863 ] 0 ] 1 ] 2 ] *** ] 131 ] 132 ] 133 ] 134 ] # ________________________ # video_activo_x ___________________________________________ *** _________| # # pixel_x 0 [ 0 ] 1 ] 2 ] # gen_ini_hs = detecta_flanco_bajada(clk_i=clk27_i, a_i=hs_i, flanco_o=ini_hs) gen_pix_ena = FT_R(clk_i=clk27_i, rst_i=ini_hs, t_i=Signal(Hi), q_o=pix_ce) # Divide x2 la frec de clock gen_barrido_x = CB_RE( clk_i=clk27_i, rst_i=ini_hs, ce_i=pix_ce, q_o=barrido_x ) # Cuenta los "pixels" (tanto activos como los de blanking) # en una linea de video, comenzando desde el flanco de bajada de hs @always_comb def gen_video_activo_x(): if INICIO_X <= barrido_x and barrido_x < INICIO_X + PIXELS_x_LINEA_ACTIVA: # Comparador para determinar la ventana temporal de la linea activa video_activo_x.next = Hi else: video_activo_x.next = Lo ######################################################################################################################## # # Vertical # ======== # ___ _ _ _ _ _ ______ ______ ______ ______ ______ ____________ _ # mix_sync |____| |____| |____| |____| |____| |_| |_| |_| |_| |_| |_| |_| # ___ ___________ ___________ _____________ _______________ _______________ ____________ _ # hs_i |_| |_| |_| |_| |_| |_| |_| # ________ ____________________________________________________ # vs_i |________________________________________| # _____________________________________________________________________________________________ # odd_even_i ________| # # nro_linea ] 624 ] 0 ] 1 ] 2 ] 3 ] 4 ] # gen_ini_vs = detecta_flanco_bajada(clk_i=clk27_i, a_i=vs_i, flanco_o=ini_vs) @always_comb def gen_ini_odd( ): # Genera un pulso al comienzo del campo impar para resetear el contador de lineas ini_odd.next = ini_vs & odd_even_i gen_rst_n_linea = FJK(clk_i=clk27_i, j_i=ini_odd, k_i=ini_hs, q_o=rst_aux) @always_comb def gen_rst_vert(): rst_n_lineas.next = rst_aux & ini_hs # un pulsito al comienzo del primer hs dentro del vs del campo impar gen_nro_linea = CB_RE( clk_i=clk27_i, rst_i=rst_n_lineas, ce_i=ini_hs, q_o=nro_linea ) # Cuenta las lineas de video desde el comienzo del campo impar @always_comb def gen_video_activo_y(): if (LINEA_INI_VIDEO_ACTIVO_EVEN <= nro_linea and nro_linea <= LINEA_FIN_VIDEO_ACTIVO_EVEN) or ( LINEA_INI_VIDEO_ACTIVO_ODD <= nro_linea and nro_linea <= LINEA_FIN_VIDEO_ACTIVO_ODD): video_activo_y.next = Hi else: video_activo_y.next = Lo @always_comb def gen_video_activo(): video_activo_o.next = video_activo_x & video_activo_y # Parte util de la senal de video @always(barrido_x, video_activo_x) def gen_pixel_x(): if video_activo_x: pixel_x_o.next = barrido_x - INICIO_X else: pixel_x_o.next = 0 @always(nro_linea, video_activo_y, odd_even_i) def gen_pixel_y(): if video_activo_y: if odd_even_i: pixel_y_o.next = ( nro_linea - LINEA_INI_VIDEO_ACTIVO_ODD ) * 2 # el "* 2" es debido al barrido entrelazado y el campo impar tiene la primer linea else: pixel_y_o.next = (nro_linea - LINEA_INI_VIDEO_ACTIVO_EVEN) * 2 + 1 else: pixel_y_o.next = 0 @always_comb def conex_pix_ce_o(): pix_ce_o.next = pix_ce @always_comb def gen_ini_frame(): ini_frame_o.next = odd_even_i and ini_vs return instances()
def VGA_control(clk50_i, hs_o, vs_o, video_activo_o, pix_address_o, RGB_data_i, red_o, green_o, blue_o): """Modulo que genera las senales de sincronismo de un sistema VGA (800x600 @ 72Hz) :Parametros: - `clk50_i` -- Entrada de clock de pixel @ 50Mhz - `hs_o` -- Sincronismo horizontal - `vs_o` -- Sincronismo vertical - `video_activo_o` -- Salida que determina la ventana temporal del video activo (nBlank) - `pix_address_o` -- Direccion del proximo pixel a leer - `RGB_data_i` -- Valor del pixel leido desde la memoria - `red_o` -- Salida de rojo - `green_o` -- Salida de verde - `blue_o` -- Salida de azul """ ###################################### # Parametros del Horizontal (en pixels) H_FRONT = 56 H_SYNC = 120 H_BACK = 64 H_ACT = 800 H_BLANK = H_FRONT + H_SYNC + H_BACK H_TOTAL = H_FRONT + H_SYNC + H_BACK + H_ACT ###################################### # Parametros del Vertical (en lineas) V_FRONT = 37 V_SYNC = 6 V_BACK = 23 V_ACT = 600 V_BLANK = V_FRONT + V_SYNC + V_BACK V_TOTAL = V_FRONT + V_SYNC + V_BACK + V_ACT ################### # Senales y registros h_cont = Signal(intbv( 0, 0, H_TOTAL)) # registros para llevar la pos. del barrido v_cont = Signal(intbv(0, 0, V_TOTAL)) rst_h = Signal(Lo) # Reset del contador horizontal y clock ena del vert rst_v = Signal(Lo) # Reset del vertical #################################################### # contador_H = CB_R(clk_i=clk50_i, rst_i=rst_h, q_o=h_cont) # Cuenta pix horiz contador_V = CB_RE(clk_i=clk50_i, rst_i=rst_v, ce_i=rst_h, q_o=v_cont) # Cuenta lineas @always_comb def gen_rst(): if h_cont == H_TOTAL - 1: rst_h.next = Hi else: rst_h.next = Lo if v_cont == (V_TOTAL - 1) and rst_h == Hi: rst_v.next = Hi else: rst_v.next = Lo # @always_comb # def gen_sync() : # if <h_cont return instances()
def ITU_656_deco(clk27_i, data_i, pixel_x_o, pixel_y_o, pix_ena_o, video_activo_o, Y_o, Cb_o, Cr_o, ini_frame_o): """Decodifica la norma ITU-656 (PAL), obteniendo las coordenadas del pixel actual y su valor de YCbCr :Parametros: - `clk27_i` -- entrada de clock de 27Mhz - `data_i` -- entrada de datos en norma itu 656 (PAL) - `pix_ena_o` -- salida de pixel enable - `pixel_x_o` -- salida de la coordenada x del pixel activo actual [0 .. 720] - `pixel_y_o` -- salida de la coordenada y del pixel activo actual [0 .. 576] - `video_activo_o` -- salida que determina la ventana temporal del video activo - `Y_o` -- valor de luma del pixel actual (unsigned) - `Cb_o` -- valor de croma del pixel actual (signed) - `Cr_o` -- valor de croma del pixel actual (signed) - `ini_frame_o` -- salida de inicio del cuadro (inicio del campo impar) """ # Info del Horiz PIXELS_x_LINEA = 864 # Cantidad de pixels de una linea de video PAL PIXELS_x_LINEA_ACTIVA = 720 # Cantidad de pixels activos de una linea de video # Info del Vert TOTAL_LINEAS = 625 # Total de lineas del PAL LINEAS_ACTIVAS = 576 # Cantidad de lineas activas de video PAL LINEA_INI_VIDEO_ACTIVO_ODD = 22 # Linea de comienzo del video activo en el campo impar LINEA_FIN_VIDEO_ACTIVO_ODD = 309 # Linea de finalizacion del video activo en el campo impar LINEA_INI_VIDEO_ACTIVO_EVEN = 335 # Linea de comienzo del video activo en el campo par LINEA_FIN_VIDEO_ACTIVO_EVEN = 622 # Linea de finalizacion del video activo en el campo par n = len(data_i) ################################# ### Senales y registros data_q1 = Signal( intbv(0)[n:] ) # Registros para la ventana de deteccion de los codigos de sincronismo data_q2 = Signal(intbv(0)[n:]) data_q3 = Signal(intbv(0)[n:]) sav = Signal(Lo) # Deteccion del start active video SAV sav_q1 = Signal(Lo) sav_q2 = Signal(Lo) eav = Signal(Lo) # Deteccion del end active video n_f = Signal(Lo) # Bit de Frame v = Signal(Lo) # Bit de Vertical Y = Signal(intbv(0)[n:]) Cb = Signal(intbv(0)[n:]) Cb_q = Signal(intbv(0)[n:]) ena_Y = Signal(Lo) # Para muestrear la informacion de luma ena_x = Signal(Lo) # Para contar la coordenada x ena_Y_2 = Signal(Lo) # Aux para generar ena_Cb ena_Cb = Signal(Lo) # Para muestrear la informacion de croma blue ena_Cb_q = Signal(Lo) # Aux para generar ena_Cr ena_Cr = Signal(Lo) # Para muestrear la informacion de croma red pos_x = Signal(intbv(0, 0, PIXELS_x_LINEA)) nro_linea = Signal(intbv(0, 0, TOTAL_LINEAS)) rst_x = Signal(Lo) # Reset del contador horizontal rst_y = Signal(Lo) # Reset del contador de lineas odd_even = Signal(Lo) # 1 Impar (Trama 1), 0 Par (Trama 2) video_activo_x = Signal(Lo) video_activo_y = Signal(Lo) ena_aux = Signal(Lo) ini_frame = Signal(Lo) ena_ini_frame = Signal(Lo) rst_ini_frame = Signal(Lo) cuenta_ini_frame = Signal(intbv(0, 0, 15 + 1)) ################################# ### Datapath ######################################################################################### ### Descripcion del codigo SAV de referencia para la temporizacion de la senal de video # # ____ ____ ____ ____ ____ ____ ____ # clk27_i ____| |____| |____| |____| |____| |____| |____| | # # data_i | FF | 00 | 00 | XY | Cb | Y0 | # # H Blank | SAV | Video activo # # # Descripcion de los bits del byte XY del SAV : # ------------------------------------------- # # XY[6] = F : 0 durante la trama (campo ) 1 # 1 durante la trama 2 # # XY[5] = V : 0 fuera de la supresion vertical # 1 durante la supresion vertical # # XY[4] = H : 0 en SAV (Start Active Video) # 1 en EAV (End Active Video) # # Ventana de 4 bytes para la deteccion del codigo de ref. para la temp reg_1 = FD(clk_i=clk27_i, d_i=data_i, q_o=data_q1) reg_2 = FD(clk_i=clk27_i, d_i=data_q1, q_o=data_q2) reg_3 = FD(clk_i=clk27_i, d_i=data_q2, q_o=data_q3) @always_comb def detec_cod_ref(): if data_q3 == 0xFF and data_q2 == 0 and data_q1 == 0: sav.next = not data_i[4] eav.next = data_i[4] n_f.next = not data_i[6] v.next = not data_i[5] else: v.next = Lo n_f.next = Lo sav.next = Lo eav.next = Lo ########################################################################################################## # # # data_i | XY | Cb0 | Y0 | Cr | Y1 | Cb1 | Y2 | Cr1 | Y3 | # # _ ____ ____ ____ ____ ____ ____ ____ ____ ____ # clk27_i |____| |____| |____| |____| |____| |____| |____| |____| |____| | # # ____ # sav _| |____________________________________________________________________________________ # # _________ _________ ________ ________ # ena_Y * * * |_________| |_________| |__________| |_________| |_____ # # # Y * * * * * * | Y0 | Y1 | Y2 | Y3 # # _________ __________ _____ # ena_Cb ______| |_____________________________| |___________________________| # # # Cb * * * | Cb0 | Cb1 # # _________ _________ # ena_Cr __________________________| |_____________________________| |______________ # # # Cr * * * | Cr0 | Cr1 # # # Nota : La frecuencia de ena_Y es la mitad de clk27_i y la frec de ena_Cx es la mitad de ena_Y # gen_ena_Y = FT_R( clk_i=clk27_i, rst_i=sav, t_i=Signal(Hi), q_o=ena_Y ) # Divide por 2 la frec de clk comenzando en bajo luego de sav reg_Y = FD_E(clk_i=clk27_i, ce_i=ena_Y, d_i=data_i, q_o=Y) # Registro la luma gen_ena_Y_2 = FT_S( clk_i=clk27_i, set_i=sav, t_i=ena_Y, q_o=ena_Y_2 ) # Divide por 2 la frec de ena_Y comenzando en alto luego de sav @always_comb def gen_ena_Cb(): ena_Cb.next = ena_Y_2 and (not ena_Y) # Arma ena_Cb reg_Cb = FD_E(clk_i=clk27_i, ce_i=ena_Cb, d_i=data_i, q_o=Cb) # Registro la croma gen_ena_Cb_q = FD(clk_i=clk27_i, d_i=ena_Cb, q_o=ena_Cb_q) gen_ena_Cr = FD( clk_i=clk27_i, d_i=ena_Cb_q, q_o=ena_Cr) # Demora la senal ena_Cb 2 clocks para generar ena_Cr reg_Cr = FD_E(clk_i=clk27_i, ce_i=ena_Cr, d_i=data_i, q_o=Cr_o) # Registro la croma # Ahora para acomodar temporalmente Y, Cb, Cr aplico el delay necesario a cada una # Cr : sin delay # Y : 1 clk de delay # Cb : 2 clk de delay out_Y = FD(clk_i=clk27_i, d_i=Y, q_o=Y_o) q_Cb = FD(clk_i=clk27_i, d_i=Cb, q_o=Cb_q) out_Cb = FD(clk_i=clk27_i, d_i=Cb_q, q_o=Cb_o) ####################################################################### ### Generacion de las coordenadas del pixel actual # # _ ____ ____ ____ ____ ____ ____ ____ ____ ____ # clk27_i |____| |____| |____| |____| |____| |____| |____| |____| |____| | # # ____ # sav _| |____________________________________________________________________________________ # # _________ _________ ________ ________ # ena_Y * * * |_________| |_________| |__________| |_________| |_____ # # # Y * * * * * * | Y0 | Y1 | Y2 | Y3 # # _________ _________ ________ ____ # ena_x |_________| |_________| |__________| |_________| # # # Y_o * * * | Y0 | Y1 | Y2 # # _________ # rst_x ________________________| |______________________________________________________ # # pixel_x 862 | 863 | 0 | 1 | 2 gen_sav_q1 = FD(clk_i=clk27_i, d_i=sav, q_o=sav_q1) gen_sav_q2 = FD(clk_i=clk27_i, d_i=sav_q1, q_o=sav_q2) gen_rst_x = FD(clk_i=clk27_i, d_i=sav_q2, q_o=rst_x) gen_ena_x = FD(clk_i=clk27_i, d_i=ena_Y, q_o=ena_x) gen_pos_x = CB_RE(clk_i=clk27_i, rst_i=rst_x, ce_i=ena_x, q_o=pos_x) # Contador para la coordenada X #################################################################################### # # data_i | FF | 00 | 00 | XY | Cb | Y0 | # # | EAV | H Blank # ____ ____ ____ ____ ____ ____ ____ # clk27_i ___| |____| |____| |____| |____| |____| |____| | # _________________________ # odd_even ___________________________________________| # ____ # eav ______________________________________| |_________________________ # ____ # n_f ______________________________________| |_________________________ # ____ # rst_y ______________________________________| |_________________________ gen_odd_even = FD_E(clk_i=clk27_i, ce_i=eav, d_i=n_f, q_o=odd_even) @always_comb def gen_rst_y(): rst_y.next = not odd_even and eav and n_f gen_nro_linea = CB_RE(clk_i=clk27_i, rst_i=rst_y, ce_i=eav, q_o=nro_linea) gen_video_activo_y = FD_E(clk_i=clk27_i, ce_i=eav, d_i=v, q_o=video_activo_y) @always(pos_x) def gen_video_activo_x(): if pos_x < PIXELS_x_LINEA_ACTIVA: video_activo_x.next = Hi else: video_activo_x.next = Lo @always(pos_x, video_activo_x) def gen_pixel_x(): if video_activo_x: pixel_x_o.next = pos_x else: pixel_x_o.next = 0 @always(clk27_i.posedge) def gen_pixel_y(): if video_activo_y: if odd_even: pixel_y_o.next = ( nro_linea - LINEA_INI_VIDEO_ACTIVO_ODD ) * 2 # el "* 2" es debido al barrido entrelazado y el campo impar tiene la primer linea else: pixel_y_o.next = ( nro_linea - LINEA_INI_VIDEO_ACTIVO_EVEN ) * 2 + 1 # el + 1 es porque el campo par tiene la segunda linea else: pixel_y_o.next = 0 @always_comb def gen_pix_ena(): pix_ena_o.next = ena_x @always_comb def gen_video_activo(): video_activo_o.next = video_activo_x and video_activo_y ###################################################################################### ### Generacion de ini_frame gen_ena_aux = FJK(clk_i=clk27_i, j_i=rst_y, k_i=ini_frame, q_o=ena_aux) @always_comb def gen_ena_ini_frame(): ena_ini_frame.next = ena_x and ena_aux @always_comb def gen_rst_ini_frame(): rst_ini_frame.next = rst_y or ini_frame cont_ini_frame = CB_RE(clk_i=clk27_i, rst_i=rst_ini_frame, ce_i=ena_ini_frame, q_o=cuenta_ini_frame) @always(cuenta_ini_frame) def gen_ini_frame(): if cuenta_ini_frame == 15: # pixels despues del ultimo activo cae el sincronismo ini_frame.next = Hi else: ini_frame.next = Lo @always_comb def conex_ini_frame(): ini_frame_o.next = ini_frame return instances()
def UART_TX(clk_i, rst_i, ini_tx_i, dato_i, tx_o, fin_tx_o, CLK_FREC_Hz, BAUDIOS): """Modulo transmisor de : 8 bits de datos, sin paridad y 1 bit de stop Unidad de control .. graphviz:: digraph { node [ color=lightblue2, style=filled ]; ESPERA_INI -> ESPERA_INI ; ESPERA_INI -> TRANSM [ label = "ini" ]; TRANSM -> FIN; FIN -> ESPERA_INI; } """ TICKS_BIT = int(round(CLK_FREC_Hz / BAUDIOS)) # Duracion de un bit en ciclos de reloj TICKS_BIT_CMP = TICKS_BIT - 1 # Para que la comparacion n la convierta a "resize(signed.." SIZE_PAQ = len(dato_i) + 2 # Tamano del paquete a enviar SIZE_PAQ_CMP = SIZE_PAQ - 1 # Para que la comparacion n la convierta a "resize(signed.." dato_paq = Signal(intbv(0)[SIZE_PAQ:]) # El dato empaquetado bits_enviados = Signal(intbv(0, 0, SIZE_PAQ + 1)) # Cantidad de bits enviados ticks = Signal(intbv(0, 0, TICKS_BIT + 1)) tx = Signal(Lo) e = enum("ESPERA_INI", "TRANSIMITIR", "FIN") estado = Signal(e.ESPERA_INI) # Senales de control rst = Signal(Hi) carga_dato = Signal(Lo) envia_bit = Signal(Lo) fin_envio = Signal(Lo) idle = Signal(Hi) contar_bits = Signal(Lo) rst_ticks = Signal(Lo) fin_ticks = Signal(Lo) # Datapath @always_comb def paquete( ): # Arma el paquete con los bits de start, los datos y el stop dato_paq.next = concat(Hi, dato_i, Lo) tx_reg = SR_LE_PiSo_Der(clk_i=clk_i, load_i=carga_dato, d_i=dato_paq, ce_i=envia_bit, q_o=tx) # Shift register para enviar el paquete @always_comb def conex_salida(): tx_o.next = tx | idle # Cuando no se envia nada, la linea permanece en alto (estado idle) contador_bits = CB_RE(clk_i=clk_i, rst_i=rst, ce_i=contar_bits, q_o=bits_enviados) # Cuenta los bits enviados @always(bits_enviados) def comp_fin_envio( ): # Comparador que determina cuando se enviaron todos los bits if bits_enviados == SIZE_PAQ_CMP: fin_envio.next = Hi else: fin_envio.next = Lo contador_ticks = CB_R( clk_i=clk_i, rst_i=rst_ticks, q_o=ticks) # Cuenta ciclos de reloj para saber la duracion de un bit @always(ticks) def comp_ticks(): if ticks == TICKS_BIT_CMP: fin_ticks.next = Hi else: fin_ticks.next = Lo # Unidad de control @always(clk_i.posedge) def FSM_estados(): """Logica del estado siguiente""" if rst_i: estado.next = e.ESPERA_INI else: ########################### if estado == e.ESPERA_INI: if ini_tx_i: estado.next = e.TRANSIMITIR ########################### elif estado == e.TRANSIMITIR: if fin_envio and fin_ticks: estado.next = e.FIN ########################### elif estado == e.FIN: estado.next = e.ESPERA_INI else: estado.next = e.ESPERA_INI @always(estado, ini_tx_i, fin_envio, fin_ticks) def FSM_salidas(): """Logica combinacional de salida""" ########################### if estado == e.ESPERA_INI: fin_tx_o.next = Lo idle.next = Hi contar_bits.next = Lo rst.next = Hi rst_ticks.next = Hi envia_bit.next = Lo if ini_tx_i: carga_dato.next = Hi else: carga_dato.next = Lo ########################### elif estado == e.TRANSIMITIR: fin_tx_o.next = Lo carga_dato.next = Lo idle.next = Lo rst.next = Lo if fin_ticks: envia_bit.next = Hi contar_bits.next = Hi rst_ticks.next = Hi else: envia_bit.next = Lo contar_bits.next = Lo rst_ticks.next = Lo ########################### elif estado == e.FIN: fin_tx_o.next = Hi carga_dato.next = Lo idle.next = Hi contar_bits.next = Lo rst.next = Lo rst_ticks.next = Lo envia_bit.next = Lo else: fin_tx_o.next = Lo carga_dato.next = Lo idle.next = Hi contar_bits.next = Lo rst.next = Hi rst_ticks.next = Lo envia_bit.next = Lo return instances()
def UART_RX(clk_i, rst_i, rx_i, dato_o, fin_rx_o, CLK_FREC_Hz, BAUDIOS): """Modulo receptor de : 8 bits de datos, sin paridad y 1 bit de stop Unidad de control .. graphviz:: digraph { node [ color=lightblue2, style=filled ]; ESPERA_START -> ESPERA_START ; ESPERA_START -> VERIF_START [ label = "RX == 0" ]; VERIF_START -> RECIBIR [ label = "medio_bit == 0" ]; VERIF_START -> ESPERA_START RECIBIR -> VERIF_STOP [ label = "leyo 8bits" ]; VERIF_STOP -> FIN [label = "medio_bit == 1" ]; FIN -> ESPERA_START; } """ TICKS_BIT = int(round(CLK_FREC_Hz / BAUDIOS)) # Duracion de un bit en ciclos de reloj TICKS_MEDIO_BIT = int(round(CLK_FREC_Hz / BAUDIOS / 2)) # Duracion de medio bit en ciclos de reloj TICKS_BIT_CMP = TICKS_BIT - 1 TICKS_MEDIO_BIT_CMP = TICKS_MEDIO_BIT - 1 n = len(dato_o) SIZE_DATO_CMP = n - 1 rx = Signal(Lo) dato_leido = Signal(intbv(0)[n:]) bits_leidos = Signal(intbv(0, 0, n + 1)) # Cantidad de bits leidos ticks = Signal(intbv(0, 0, TICKS_BIT + 1)) e = enum("ESPERA_START", "VERIF_START", "RECIBIR", "VERIF_STOP", "FIN") estado = Signal(e.ESPERA_START) # Senales de control rst = Signal(Lo) rst_ticks = Signal(Lo) lee_bit = Signal(Lo) contar_bits = Signal(Lo) fin_ticks = Signal(Lo) ticks_medio_bit = Signal(Lo) rst_ticks = Signal(Lo) fin_recepcion = Signal(Lo) dato_ok = Signal(Lo) reg_in = FD(clk_i=clk_i, d_i=rx_i, q_o=rx) # Para tener la entrada sincronizada rx_reg = SR_RE_SiPo_Der(clk_i=clk_i, rst_i=rst, ce_i=lee_bit, sr_i=rx, q_o=dato_leido) reg_out = FD_E(clk_i=clk_i, ce_i=dato_ok, d_i=dato_leido, q_o=dato_o) contador_bits = CB_RE(clk_i=clk_i, rst_i=rst, ce_i=contar_bits, q_o=bits_leidos) # Cuenta los bits leidos @always(bits_leidos) def comp_fin_recepcion(): if bits_leidos == SIZE_DATO_CMP: fin_recepcion.next = Hi else: fin_recepcion.next = Lo contador_ticks = CB_R( clk_i=clk_i, rst_i=rst_ticks, q_o=ticks) # Cuenta ciclos de reloj para saber la duracion de un bit @always(ticks) def comp_ticks(): if ticks == TICKS_BIT_CMP: fin_ticks.next = Hi else: fin_ticks.next = Lo if ticks == TICKS_MEDIO_BIT_CMP: ticks_medio_bit.next = Hi else: ticks_medio_bit.next = Lo # Unidad de control del modulo RX @always(clk_i.posedge) def FSM_estados(): """Logica de cambio de estados""" if rst_i: estado.next = e.ESPERA_START else: ############################# if estado == e.ESPERA_START: if not rx: # Cuando la linea de Rx baja empieza el proceso estado.next = e.VERIF_START ############################# elif estado == e.VERIF_START: if ticks_medio_bit: # Me paro en la mitad del bit de start para chequear que no haya sido un falso start if not rx: estado.next = e.RECIBIR # Start Bit OK else: estado.next = e.ESPERA_START # Falso Start Bit ############################# elif estado == e.RECIBIR: if fin_recepcion and fin_ticks: estado.next = e.VERIF_STOP ############################# elif estado == e.VERIF_STOP: if fin_ticks: if rx: # Bit de stop OK estado.next = e.FIN else: estado.next = e.ESPERA_START # Error en el bit de stop, vuelve e empezar ############################# elif estado == e.FIN: estado.next = e.ESPERA_START else: estado.next = e.ESPERA_START @always(estado, ticks_medio_bit, fin_ticks, rx) def FSM_salidas(): """Logica combinacional de salida""" ############################# if estado == e.ESPERA_START: contar_bits.next = Lo rst.next = Hi rst_ticks.next = Hi lee_bit.next = Lo fin_rx_o.next = Lo dato_ok.next = Lo ############################# elif estado == e.VERIF_START: dato_ok.next = Lo fin_rx_o.next = Lo contar_bits.next = Lo rst.next = Lo lee_bit.next = Lo if ticks_medio_bit: rst_ticks.next = Hi else: rst_ticks.next = Lo ############################# elif estado == e.RECIBIR: dato_ok.next = Lo fin_rx_o.next = Lo rst.next = Lo if fin_ticks: lee_bit.next = Hi contar_bits.next = Hi rst_ticks.next = Hi else: rst_ticks.next = Lo lee_bit.next = Lo contar_bits.next = Lo ############################# elif estado == e.VERIF_STOP: dato_ok.next = Lo fin_rx_o.next = Lo contar_bits.next = Lo rst.next = Lo lee_bit.next = Lo if fin_ticks: rst_ticks.next = Hi if rx: dato_ok.next = Hi else: dato_ok.next = Lo else: rst_ticks.next = Lo dato_ok.next = Lo ############################# elif estado == e.FIN: dato_ok.next = Lo contar_bits.next = Lo rst.next = Hi rst_ticks.next = Hi lee_bit.next = Lo fin_rx_o.next = Hi else: dato_ok.next = Lo contar_bits.next = Lo rst.next = Hi rst_ticks.next = Hi lee_bit.next = Lo fin_rx_o.next = Lo return instances()