Copyright 2012, Sinclair, R.F., Inc.
Table of Contents
Introduction
Command
9x8 Cores
Creating new Peripherals
Reccomendations
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.
TODO
TODO
New peripherals are created using a Python class with the following member
functions:
__init__(self,config,param_list):
Where:
- config is the computer compiler configuration state when
the peripheral configuration command is encountered.
- param_list is a list of the space separated parameters on
the peripheral
configuration command following the name of the peripheral. This list
is used to provide mandatory and optional parameters to the
core. For example, the UART_Tx peripheral requires
information to generate the desired baud rate and allows an optional
name to facilitate distinguishing between multiple instances of the
same peripheral.
For example, the parameters in the peripheral configuration
command
PERIPHERAL name param1 \
param2=options \
param3="a string" \
param4=value
is converted to the space delimited string
param1 param2=option param3="a string" param4=value
which is then provided to the __init__ function as a
list() with the following four tuples:
('param1',)
('param2','option',)
('param3','"a string"',)
('param4','value',)
These tuples can then be parsed within the __init__ function to
intialize the object.
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:
- signal name
- signal width
- 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:
- 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:
- signal name
- signal width
- 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.
- Add these same signals to config['signals'], one at a
time using tuples with the following ordered format:
- signal name
- 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:
- 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:
- signal name
- signal width
- 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.
- Add these same signals to config['signals'], one at a
time using tuples with the following ordered format:
- signal name
- 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.
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.