################################################################################ # # Copyright 2012-2013, Sinclair R.F., Inc. # ################################################################################ from ssbccPeripheral import SSBCCperipheral from ssbccUtil import SSBCCException; class PWM_8bit(SSBCCperipheral): """ Pulse Width Modulator (PWM) with 8-bit control.\n This peripheral creates one or more PWMs. The PWM is designed so that it is allways off when the control is 0 and it is always on when the control is 0xFF.\n Usage: PERIPHERAL PWM_8bit outport=O_name \\ outsignal=o_name \\ ratemethod={clk/rate|count} \\ [invert|noinvert] \\ [instances=n] \\ [norunt]\n Where: outport=O_name specifies the symbol used by the outport instruction to write a byte to the peripheral Note: The name must start with "O_". outsignal=o_name specifies the name of the output signal Note: The name must start with "o_". ratemethod={clk/rate|count} specifies the frequency at which the PWM counter is incremented Example: ratemethod=count means to increment the PWM counter once every "count" clock cycles. invert|noinvert optional configuration command to invert or to not invert the PWM output Default: don't invert the output (i.e., a command of 0 means the output is always low) Note: "invert" should be used when pulling the external signal to ground means the device is "on" instances=n specifies the number of PWMs for the peripheral Default: The default is one PWM control and output. norunt optionally add logic to ensure "runt" pulses are not generated by incorporating new PWM commands at the start of the counting cycle Default: "runt" pulses are allowed.\n The following OUTPORT is provided by this peripheral when instances=1: O_name output the next 8-bit value to transmit or to queue for transmission\n The following OUTPORT is provided by this peripheral when instances=n is larger than 1: O_name_0, O_name_1, ..., O_name_{n-1} output the next 8-bit value to transmit on the specified PWM Note: O_name_i = ${O_name_0+i) where 0<=i swap over outport drop 1+ r> .jumpc(loop,1-) drop .return(drop) """ def __init__(self,peripheralFile,config,param_list,loc): # Use the externally provided file name for the peripheral self.peripheralFile = peripheralFile; # Get the parameters. for param_tuple in param_list: param = param_tuple[0]; param_arg = param_tuple[1]; if param == 'outport': self.AddAttr(config,param,param_arg,r'O_\w+$',loc); elif param == 'outsignal': self.AddAttr(config,param,param_arg,r'o_\w+$',loc); elif param == 'ratemethod': self.ProcessRateMethod(config,param_arg,loc); elif param == 'invert': self.AddAttr(config,param,param_arg,None,loc); elif param == 'noinvert': self.AddAttr(config,param,param_arg,None,loc); elif param == 'instances': self.AddAttr(config,param,param_arg,r'[1-9]\d*$',loc,int); elif param == 'norunt': self.AddAttr(config,param,param_arg,None,loc); else: raise SSBCCException('Unrecognized parameter at %s: %s' % (loc,param,)); # Ensure the required parameters are provided. if not hasattr(self,'instances'): self.instances = 1; # Set optional parameters. if not hasattr(self,'invert') and not hasattr(self,'noinvert'): self.noinvert = True; if not hasattr(self,'norunt'): self.norunt = False; # Ensure parameters do not conflict. if hasattr(self,'invert') and hasattr(self,'noinvert'): raise SSBCCException('Only one of "invert" or "noinvert" can be specified at %s' % loc); # Use only one of mutually exclusive configuration settings. if hasattr(self,'noinvert'): self.invert = False; # Add the I/O port, internal signals, and the INPORT and OUTPORT symbols for this peripheral. config.AddIO(self.outsignal,self.instances,'output',loc); self.ix_outport_0 = config.NOutports(); if self.instances == 1: tmpOutport = self.outport; config.AddOutport((tmpOutport,False,),loc); else: for ixOutPort in range(self.instances): tmpOutport = '%s_%d' % (self.outport,ixOutPort,); config.AddOutport((tmpOutport,False,),loc); # Add the 'clog2' function to the processor (if required). config.functions['clog2'] = True; def ProcessRateMethod(self,config,param_arg,loc): if hasattr(self,'ratemethod'): raise SSBCCException('ratemethod repeated at %s' % loc); if param_arg.find('/') < 0: if self.IsIntExpr(param_arg): self.ratemethod = str(self.ParseIntExpr(param_arg)); elif self.IsParameter(config,param_arg): self.ratemethod = param_arg; else: raise SSBCCException('ratemethod with no "/" must be an integer or a previously declared parameter at %s' % loc); else: baudarg = re.findall('([^/]+)',param_arg); if len(baudarg) == 2: if not self.IsIntExpr(baudarg[0]) and not self.IsParameter(config,baudarg[0]): raise SSBCCException('Numerator in ratemethod must be an integer or a previously declared parameter at %s' % loc); if not self.IsIntExpr(baudarg[1]) and not self.IsParameter(config,baudarg[1]): raise SSBCCException('Denominator in ratemethod must be an integer or a previously declared parameter at %s' % loc); for ix in range(2): if self.IsIntExpr(baudarg[ix]): baudarg[ix] = str(self.ParseIntExpr(baudarg[ix])); self.ratemethod = '('+baudarg[0]+'+'+baudarg[1]+'/2)/'+baudarg[1]; if not hasattr(self,'ratemethod'): raise SSBCCException('Bad ratemethod value at %s: "%s"' % (loc,param_arg,)); def GenVerilog(self,fp,config): body = self.LoadCore(self.peripheralFile,'.v'); output_on = "1'b1"; output_off = "1'b0"; if self.invert: output_on = "1'b0"; output_off = "1'b1"; norunt = "1'b0"; if self.norunt: norunt = "1'b1"; for subs in ( (r'\bL__', 'L__@NAME@__',), (r'\bgen__', 'gen__@NAME@__',), (r'\bs__', 's__@NAME@__',), (r'\bix\b', 'ix__@NAME@',), (r'@COUNT@', self.ratemethod,), (r'@INSTANCES@', str(self.instances),), (r'@IX_OUTPORT_0@', str(self.ix_outport_0),), (r'@OFF@', output_off,), (r'@ON@', output_on,), (r'@NAME@', self.outsignal,), (r'@NORUNT@', norunt,), ): body = re.sub(subs[0],subs[1],body); body = self.GenVerilogFinal(config,body); fp.write(body);