groups: sdram1, sdram2 and sdram3. Firstly, sdram1, covering the base
functionality:
-def sdram1(suffix, bank):
- buspins = []
- inout = []
- for i in range(8):
- pname = "SDRDQM%d*" % i
- buspins.append(pname)
- for i in range(8):
- pname = "SDRD%d*" % i
- buspins.append(pname)
- inout.append(pname)
- for i in range(12):
- buspins.append("SDRAD%d+" % i)
- for i in range(8):
- buspins.append("SDRDEN%d+" % i)
- for i in range(2):
- buspins.append("SDRBA%d+" % i)
- buspins += ['SDRCKE+', 'SDRRASn+', 'SDRCASn+', 'SDRWEn+',
- 'SDRCSn0++']
- return (buspins, inout)
+ def sdram1(suffix, bank):
+ buspins = []
+ inout = []
+ for i in range(8):
+ pname = "SDRDQM%d*" % i
+ buspins.append(pname)
+ for i in range(8):
+ pname = "SDRD%d*" % i
+ buspins.append(pname)
+ inout.append(pname)
+ for i in range(12):
+ buspins.append("SDRAD%d+" % i)
+ for i in range(2):
+ buspins.append("SDRBA%d+" % i)
+ buspins += ['SDRCKE+', 'SDRRASn+', 'SDRCASn+', 'SDRWEn+',
+ 'SDRCSn0++']
+ return (buspins, inout)
This function, if used on its own, would define an 8-bit SDRAM bus with
12-bit addressing. Checking off the names against the corresponding BSV
-definition we find
+definition we find that most of them are straightforward. Outputs
+must have a "+" after the name (in the python representation), inputs
+must have a "-".
+
+However we run smack into an interesting brick-wall with the in/out pins.
+In/out pins which are routed through the same IO pad need a *triplet* of
+signals: one input wire, one output wire and *one direction control wire*.
+Here however we find that the SDRAM controller, which is a wrapper around
+the opencores SDRAM controller, has a *banked* approach to direction-control
+that will need to be dealt with, later. So we do *not* make the mistake
+of adding 8 SDRDENx pins: the BSV code will need to be modified to
+add 64 one-for-one enabling pins. We do not also make the mistake of
+adding separate unidirectional "in" and separate unidirectional "out" signals
+under different names, as the pinmux code is a *PAD* centric tool.
+
+The second function extends the 8-bit data bus to 64-bits, and extends
+the address lines to 13-bit wide:
+
+ def sdram3(suffix, bank):
+ buspins = []
+ inout = []
+ for i in range(12, 13):
+ buspins.append("SDRAD%d+" % i)
+ for i in range(8, 64):
+ pname = "SDRD%d*" % i
+ buspins.append(pname)
+ inout.append(pname)
+ return (buspins, inout)
+
+In this way, alternative SDRAM controller implementations can use sdram1
+on its own; implementors may add "extenders" (named sdram2, sdram4) that
+cover extra functionality, and, interestingly, in a pinbank scenario,
+the number of pins on any given GPIO bank may be kept to a sane level.
+
+The next phase is to add the (now supported) peripheral to the list
+of pinspecs at the bottom of the file, so that it can actually be used:
+
+ pinspec = (('IIS', i2s),
+ ('MMC', emmc),
+ ('FB', flexbus1),
+ ('FB', flexbus2),
+ ('SDR', sdram1),
+ ('SDR', sdram2),
+ ('SDR', sdram3), <---
+ ('EINT', eint),
+ ('PWM', pwm),
+ ('GPIO', gpio),
+ )
+
+This gives a declaration that any time the function(s) starting with
+"sdram" are used to add pins to a pinmux, it will be part of the
+"SDR" peripheral. Note that flexbus is similarly subdivided into
+two groups.
+
+# Adding the peripheral to a chip's pinmux specification
+
+Next, we add the peripheral to an actual chip's specification. In this
+case it is to be added to i\_class, so we open src/spec/i\_class.py. The
+first thing to do is to add a single-mux (dedicated) bank of 92 pins (!)
+which covers all of the 64-bit Data lines, 13 addresses and supporting
+bank-selects and control lines. It is added as Bank "D", the next
+contiguous bank:
+
+ def pinspec():
+ pinbanks = {
+ 'A': (28, 4),
+ 'B': (18, 4),
+ 'C': (24, 1),
+ 'D': (92, 1), <---
+ }
+ fixedpins = {
+ 'CTRL_SYS': [
+
+This declares the width of the pinmux to one (a dedicated peripheral
+bank). Note in passing that A and B are both 4-entry.
+Next, an SDRAM interface is conveniently added to the chip's pinmux
+with two simple lines of code:
+
+ ps.gpio("", ('B', 0), 0, 0, 18)
+ ps.flexbus1("", ('B', 0), 1, spec=flexspec)
+
+ ps.flexbus2("", ('C', 0), 0)
+
+ ps.sdram1("", ('D', 0), 0) <--
+ ps.sdram3("", ('D', 35), 0) <--
+
+Note that the first argument is blank, indicating that this is the only
+SDRAM interface to be added. If more than one SDRAM interface is desired
+they would be numbered from 0 and identified by their suffix. The second
+argument is a tuple of (Bank Name, Bank Row Number), and the third argument
+is the pinmux column (which in this case must be zero).
+
+At the top level the following command is then run:
+
+ $ python src/pinmux_generator.py -o i_class -s i_class
+
+The output may be found in the ./i\_class subdirectory, and it is worth
+examining the i\_class.mdwn file. A table named "Bank D" will have been
+created and it is worth just showing the first few entries here:
+
+| Pin | Mux0 | Mux1 | Mux2 | Mux3 |
+| --- | ----------- | ----------- | ----------- | ----------- |
+| 70 | D SDR_SDRDQM0 |
+| 71 | D SDR_SDRDQM1 |
+| 72 | D SDR_SDRDQM2 |
+| 73 | D SDR_SDRDQM3 |
+| 74 | D SDR_SDRDQM4 |
+| 75 | D SDR_SDRDQM5 |
+| 76 | D SDR_SDRDQM6 |
+| 77 | D SDR_SDRDQM7 |
+| 78 | D SDR_SDRD0 |
+| 79 | D SDR_SDRD1 |
+| 80 | D SDR_SDRD2 |
+| 81 | D SDR_SDRD3 |
+| 82 | D SDR_SDRD4 |
+| 83 | D SDR_SDRD5 |
+| 84 | D SDR_SDRD6 |
+| 85 | D SDR_SDRD7 |
+| 86 | D SDR_SDRAD0 |
+| 87 | D SDR_SDRAD1 |
+
+Returning to the definition of sdram1 and sdram3, this table clearly
+corresponds to the functions in src/spec/pinfunctions.py which is
+exactly what we want. It is however extremely important to verify.
+
+This basically concludes the first stage of adding a peripheral to
+the pinmux / autogenerator tool. It allows peripherals to be assessed
+for viability prior to actually committing the engineering resources
+to their deployment.