Copyright 2012, Sinclair, R.F., Inc.

Table of Contents

Introduction
Command
9x8 Cores
Creating new Peripherals
Reccomendations

Introduction

Within the processor configuration command, the PERIPHERAL configuration is used to incorporate peripherals such as UARTs, TBD into the micro controller core.

This document describes the general format of the peripheral configuration command, lists peripherals for the 9x8 core, and documents how to add additional peripherals to the computer compiler.

Command

TODO

9x8 Cores

TODO

Creating new Peripherals

New peripherals are created using a Python class with the following member functions:

__init__(self,config,param_list):

Where:
This function should store instantiation specific information in self.

Inputs from the FPGA fabric to the micro controller module are added by appending a tuple describing the input. The tuple consists of the following:
  1. signal name
  2. signal width
  3. signal type: the string 'input'
For example, to add an 8-bit input named "i_new_input", use the following statement:

  config['ios'].append(('i_new_input',8,'input',));

Outputs from the micro controller to the FPGA fabric are added using the signal type 'output'. For example, to add an 8-bit output named "o_new_output", use the following statement:

  config['ios'].append(('o_new_output',8,'output',));

Similarly, to add a 16-bit tri-state input/output signal, use the followiing statement:

  config['ios'].append(('io_new_signal',16,'inout',));

To add a signal or a composite signal output from the micro controller core to the peripheral two actions are required. These can be done in either order, but it may make more sense to maintainers or subsequent users to do them in the following order:

  1. Add the output port to the micro controller core:

    This consists of adding a tuple to config['outports']. The first element of this tuple is the name of the outport. The subsequent elements of this tuple are tuples describing the signal(s) associated with the outport. These tuples have the following ordered format:

    1. signal name
    2. signal width
    3. signal type: 'data' or 'strobe'
      Note: Signal type 'data' is used to relay single or multiple bit data from the micro controller core to the peripheral. Signal type 'strobe' generates a single bit strobe during the clock cycle immediately following the outport instruction.

  2. Add these same signals to config['signals'], one at a time using tuples with the following ordered format:

    1. signal name
    2. signal width
For example, to add two outputs from the micro controller core to a multiplier, use the following:

  config['outports'].append(('O_MULT_A',
                            ('s_mult_a',8,'data'),
                           ));
  config['outports'].append(('O_MULT_B',
                            ('s_mult_b',8,'data'),
                           ));
  config['signals'].append(('s_mult_a',8,));
  config['signals'].append(('s_mult_b',8,));


As a second example, to add an output from the micro controller core to the input side of an 8-bit FIFO, use the following. Here, the signal s_fifo_data will be the data to write to the FIFO and s_fifo_wr will be a strobe that is set high during the clock cycle immediately following the outport instruction.

  config['outports'].append(('O_FIFO',
                            ('s_fifo_data',8,'data'),
                            ('s_fifo_wr',1,'strobe'),
                           ));
  config['signals'].append(('s_fifo_data',8,));
  config['signals'].append(('s_fifo_wr',1,));


Adding a signal or a composite signal from the peripheral to the micro controller core requires two similar actions:
  1. Add the input port to the micro controller core:

    This consists of adding a tuple to config['inports']. The first element of this tuple is the name of the inport. The subsequent elements of this tuple are tuples describing the signal(s) associated with the inport. These tuples have the following ordered format:

    1. signal name
    2. signal width
    3. signal type: 'data', 'set-reset', or 'strobe' Note: Signal type 'data' is used to relay single or multiple bit data from the peripheral to the micro controller core. Signal type 'set-reset' latches the associated input bit until the signal is read, at which time it is cleared. Signal type 'strobe' generates a single bit strobe during the clock cycle immediately following the inport instruction.
      Note: The 'set-reset' signal type is provided as a signal type for the INPORT command and may not be as useful for peripherals since the peripheral can include the associated logic required for the latch.

  2. Add these same signals to config['signals'], one at a time using tuples with the following ordered format:

    1. signal name
    2. signal width
For example, to add two inport ports for the MSB and LSB from an 8 by 8 multipler, use the following:

  config['inports'].append(('I_MULT_MSB',
                           ('s_mult_msb',8,'data'),
                          ));
  config['inports'].append(('I_MULT_LSB',
                           ('s_mult_lsb',8,'data'),
                          ));
  config['signals'].append(('s_mult_msb',8,));
  config['signals'].append(('s_mult_lsb',8,));


As a second example, to add an input port from a FIFO in the peripheral to the micro controlller core, use the following:

  config['inports'].append(('I_FIFO',
                           ('s_fifo_data',8,'data'),
                           ('s_fifo_ack',1,'strobe'),
                          ));
  config['signals'].append(('s_fifo_data',8,));
  config['signals'].append(('s_fifo_ack',1,));


As a third example, to add an input port for two status bits from a FIFO in the peripheral to the micro controlller core, use the following:

  config['inports'].append(('I_FIFO_STATUS',
                           ('s_fifo_full',1,'data'),
                           ('s_fifo_empty',1,'data'),
                          ));
  config['signals'].append(('s_fifo_full',1,));
  config['signals'].append(('s_fifo_empty',1,));


GenAssembly(self,config):

This is an optional function to generate an assembly file associated with the peripheral.
TODO

GenHDL(self,fp,config):

This function examines config['hdl'] to determine the HDL language for generating the FPGA logic for the peripheral. The logic is written to the file handle fp.

Rather than capture all HDL languages in this function, the following type of structure is recommended:

  GenHDL(self,fp,config):
    if config['hdl'] == 'Verilog':
      self.GenVerilog(fp,config);
    elif config['hdl'] == 'VHDL':
      self.GenVHDL(fp,config);
    else:
      raise Exception('HDL "%s" not implemented' % config['hdl']);


For example, to generate the logic for an unsigned 8 by 8 multiplier using the previous inport, outport, and signal assignments, the Verilog code could be generated using:

  GenVerilog(self,fp,config):
    fp.write('initial s_mult_msb = 8\'d0;\n');
    fp.write('initial s_mult_lsb = 8\'d0;\n');
    fp.write('always @ (posedge i_clk)\n');
    fp.write('  if (i_rst) begin\n');
    fp.write('    s_mult_msb <= 8\'d0;\n');
    fp.write('    s_mult_lsb <= 8\'d0;\n');
    fp.write('  end else\n');
    fp.write('    { s_mult_msb, s_mult_lsb } <= $unsigned(s_mult_a) * $unsigned(s_mult_b);\n');


Note: The results of this multiplication are available two clock cycles after the outport instruction setting the s_mult_a or s_mult_b value. This isn't a problem with the processor as the outport is probably followed by a drop instruction and the inport instruction to read either part of the multiplication has to be preceded by an instruction pushing the port number onto the data stack.

Note: While Python allows the entire logic block to be written using a single fp.write("""initial s_..."""); statement, breaking out the individual statements allows computed signal names to be included more cleanly and also accomodates conditional inclusion of code.

Recommendations

help

The PERIPHERAL configuration command will print the documentation string for peripherals if the parameter "help" is listed. For example, to get help for the monitor_stack peripheral, insert the peripheral using:

  PERIPHERAL monitor_stack help

This will display the documentation string for the monitor_stack peripheral and then terminate the build.

If there is no documentation string for the peripheral, the following message is printed and the build is terminated:

  No help for periperal XXX is provided

Note: The help message displays the name of the peripheral and the source file.