for k, v in {'uart': uart,
'rs232': rs232,
- 'sdr': sdram,
+ 'sdr': sdram, <--
'twi': twi,
'quart': quart,
ps.flexbus2("", ('C', 0), 0)
+We then need to generate the spec. At the top level the following command is
+then run:
+
+ $ python src/pinmux_generator.py -o i_class -s i_class
+
+Checking the resultant markdown file ./i\_class/i\_class.mdwn, we find that
+several entries have been added at the required location:
+
+| Pin | Mux0 | Mux1 | Mux2 | Mux3 |
+| --- | ----------- | ----------- | ----------- | ----------- |
+| 28 | B GPIOB_B0 | B FB_AD2 | | B EMMC_CMD |
+| 29 | B GPIOB_B1 | B FB_AD3 | | B EMMC_CLK |
+| 30 | B GPIOB_B2 | B FB_AD4 | | B EMMC_D0 |
+| 31 | B GPIOB_B3 | B FB_AD5 | | B EMMC_D1 |
+| 32 | B GPIOB_B4 | B FB_AD6 | | B EMMC_D2 |
+| 33 | B GPIOB_B5 | B FB_AD7 | | B EMMC_D3 |
+| 34 | B GPIOB_B6 | B FB_CS0 | | B EMMC_D4 |
+| 35 | B GPIOB_B7 | B FB_CS1 | | B EMMC_D5 |
+| 36 | B GPIOB_B8 | B FB_ALE | | B EMMC_D6 |
+| 37 | B GPIOB_B9 | B FB_OE | B FB_TBST | B EMMC_D7 |
+| 38 | B GPIOB_B10 | B FB_RW | | |
+
+We also check i\_class/interfaces.txt to see if the single requested emmc
+interface is there:
+
+ gpiob 1
+ eint 1
+ mqspi 1
+ emmc 1 <--
+ uart 3
+
+Also we examine the i\_class/emmc.txt file to check that it has the right
+types of pin definitions:
+
+ cmd out
+ clk out
+ d0 inout bus
+ d1 inout bus
+ d2 inout bus
+ d3 inout bus
+ d4 inout bus
+ d5 inout bus
+ d6 inout bus
+ d7 inout bus
+
+and we check the i\_class/pinmap.txt tab-separated file to see if it
+contains the entries corresponding to the markdown table:
+
+ 24 A 4 gpioa_a24 mspi1_ck jtag_tms mmc0_d0
+ 25 A 4 gpioa_a25 mspi1_nss jtag_tdi mmc0_d1
+ 26 A 4 gpioa_a26 mspi1_io0 jtag_tdo mmc0_d2
+ 27 A 4 gpioa_a27 mspi1_io1 jtag_tck mmc0_d3
+ 28 B 4 gpiob_b0 fb_ad2 emmc_cmd
+ 29 B 4 gpiob_b1 fb_ad3 emmc_clk
+ 30 B 4 gpiob_b2 fb_ad4 emmc_d0
+ 31 B 4 gpiob_b3 fb_ad5 emmc_d1
+ 32 B 4 gpiob_b4 fb_ad6 emmc_d2
+ 33 B 4 gpiob_b5 fb_ad7 emmc_d3
+ 34 B 4 gpiob_b6 fb_cs0 emmc_d4
+ 35 B 4 gpiob_b7 fb_cs1 emmc_d5
+ 36 B 4 gpiob_b8 fb_ale emmc_d6
+ 37 B 4 gpiob_b9 fb_oe fb_tbst emmc_d7
+
+This concludes this section as the purpose of the spec-generation side,
+to create documentation and TSV files for the second phase, has been
+fulfilled. Note that we did *not* declare in PinSpec that this
+peripheral is to be added onto the fastbus, as by default peripherals
+are added to a single AXI4-Lite interface.
+
+## Adding the pinmux code auto-generator
+
+The next phase begins with adding class support to auto-generate the pinmux
+code. Starting with the following command:
+
+ $ python src/pinmux_generator.py -o i_class
+
+The first thing to do is look at i\_class/bsv\_src/pinmux.bsv, and search
+for both PeripheralSideMMC and PeripheralSideEMMC. PeripheralSideMMC is
+very short and compact:
+
+ // interface declaration between MMC and pinmux
+ (*always_ready,always_enabled*)
+ interface PeripheralSideMMC;
+ interface Put#(Bit#(1)) cmd;
+ interface Put#(Bit#(1)) clk;
+ interface Put#(Bit#(4)) out;
+ interface Put#(Bit#(4)) out_en;
+ interface Get#(Bit#(4)) in;
+ endinterface
+
+whereas PeripheralSideEMMC is a mess:
+
+ interface PeripheralSideEMMC;
+ interface Put#(Bit#(1)) cmd;
+ interface Put#(Bit#(1)) clk;
+ interface Put#(Bit#(1)) d0_out;
+ interface Put#(Bit#(1)) d0_outen;
+ interface Get#(Bit#(1)) d0_in;
+ interface Put#(Bit#(1)) d1_out;
+ interface Put#(Bit#(1)) d1_outen;
+ interface Get#(Bit#(1)) d1_in;
+ interface Put#(Bit#(1)) d2_out;
+ interface Put#(Bit#(1)) d2_outen;
+ interface Get#(Bit#(1)) d2_in;
+ ...
+ ...
+ endinterface
+
+To correct this, we need to create an InterfaceEMMC class in
+src/bsv/interface\_decl.py that generates the right code. However on
+close inspection, given that the format needed is identical (except for
+the number of data lines), we can probably get away with using *exactly*
+the same class:
+
+ class Interfaces(InterfacesBase, PeripheralInterfaces):
+
+ def __init__(self, pth=None):
+ InterfacesBase.__init__(self, Interface, pth,
+ {'gpio': InterfaceGPIO,
+ ...
+ ...
+ 'mmc': InterfaceSD,
+ 'emmc': InterfaceSD, <--
+ 'fb': InterfaceFlexBus,
+ ...
+
+and after re-running the command the output looks like this:
+
+ interface PeripheralSideEMMC;
+ interface Put#(Bit#(1)) cmd;
+ interface Put#(Bit#(1)) clk;
+ interface Put#(Bit#(8)) out;
+ interface Put#(Bit#(8)) out_en;
+ interface Get#(Bit#(8)) in;
+ endinterface
+
+Success! The class InterfaceSD appears to be sufficiently generic that
+it could understand that it had been passed 8-pins worth of data with
+exactly the same names, rather than 4. This is encouraging in the sense
+that re-using the SD/MMC BSV generation code should also be as easy.
+
+## Adding the slow peripheral code-generator
+
+So this time we will try cut/pasting src/bsv/peripheral\_gen/sdmmc.py
+to create a base class, MMCBase. The only two common functions are
+pinname\_out and \_mk\_pincon.
+
+class MMCBase(PBase):
+
+ def pinname_out(self, pname):
+ if pname in ['cmd', 'clk']:
+ return pname
+ return ''
+
+ def _mk_pincon(self, name, count, typ):
+ ...
+ ...
+
+Then, the sdmmc class is modified to inherit it, this time cutting *out*
+all but those two functions:
+
+ from bsv.peripheral\_gen.mmcbase import MMCBase <--
+
+ class sdmmc(MMCBase): <--
+
+And at the same time we create an emmc.py file where all occurrences of
+sdmmc are replaced with emmc:
+
+ class emmc(MMCBase):
+
+ def slowimport(self):
+ return "import emmc_dummy :: *;"
+
+ ...
+ ...
+
+ def _mk_connection(self, name=None, count=0):
+ return "emmc{0}.slave"
+
+Finally, to use it, just as with sdram, we add the new peripheral
+at the bottom of src/bsv/peripheral\_gen/base.py, in the "PFactory"
+(Peripheral Factory) class:
+
+ from gpio import gpio
+ from rgbttl import rgbttl
+ from flexbus import flexbus
+ from emmc import emmc <--
+
+ for k, v in {'uart': uart,
+ 'rs232': rs232,
+ 'emmc': emmc, <--
+
+For the actual auto-generation phase, this really should be all that's
+needed. Re-running the code-generator we can examine the auto-generated
+slow\_peripherals.bsv file and can confirm that yes, an "import emmc\_dummy"
+has been added, that an mmc0 instance has been created, that it is added
+to the slave fabric, and that its cmd, clk and in/out/out\_en are all
+connected up.
+
+The last remaining task will therefore be to create an interim emmc
+"dummy" BSV file.
+
+## Creating the dummy emmc peripheral
+
+Adding the actual peripheral is done in a different repository,
+shakti-peripherals, which can be cloned with:
+
+ $ git clone gitolite3@libre-riscv.org:shakti-peripherals.git
+
+or public:
+
+ $ git clone git://libre-riscv.org/shakti-peripherals.git
+
+Here, what we will do is take a straight copy of
+src/peripherals/sdmmc/sdcard\_dummy.bsv and call it
+src/peripherals/emmc/emmc\_dummy.bsv. Then replace all occurrences
+of "sdcard" with "emmc" and also update the SDBUSWIDTH from 4 to 8.
+Whilst this appears wasteful it is by far the simplest and quickest
+way to get working code, that should definitely, definitely be
+re-factored later.
+
+The next stage is to return to the pinmux repository and add the
+import of the new emmc subdirectory to the BSVINCDIR in both
+src/bsv/Makefile.template and Makefile.peripherals.template:
+
+ BSVINCDIR:= $(BSVINCDIR):../../../src/peripherals/src/peripherals/spi
+ BSVINCDIR:= $(BSVINCDIR):../../../src/peripherals/src/peripherals/sdmmc
+ BSVINCDIR:= $(BSVINCDIR):../../../src/peripherals/src/peripherals/emmc
+ BSVINCDIR:= $(BSVINCDIR):../../../src/peripherals/src/peripherals/flexbus
+
+Really these should also be auto-generated. Testing through compiling
+can now take place.
+
+## Compiling the BSV to verilog
+
+Here an additional repository is required, which can be cloned as follows:
+
+ $ git clone gitolite3@libre-riscv.org:shakti-iclass.git
+
+or public:
+
+ $ git clone git://libre-riscv.org/shakti-iclass.git
+
+This pulls in submodules automatically, and begins building the BSV,
+using the following commands:
+
+ $ ./bin/gitmoduleupdate.sh
+ $ make
+
+As the compilation of the soc can take some time, it is possible to use
+the Makefile.peripherals to compile *only* the slow\_peripherals.bsv
+file (which we did not do with the sdram case because sdram is a fast
+peripheral). This would be achieved with the following commands:
+
+ $ make spec_to_pinmux
+ $ make pinmux_to_bsv
+ $ cd build/i_class/bsv_src
+ $ make -f Makefile.peripherals gen_verilog
+
+## Summary
+
+This particular example has been something of a "cheat". The similarity
+between SD/MMC and eMMC is so high - the only differences being the name
+of the interface and the number of data pins - that it was simple and
+straightforward to re-use significant amounts of code, cut/paste style,
+carrying out some re-factoring where needed.
+
+It does however have the advantage of being quite a short tutorial, that
+illustrates key aspects of adding slow bus peripherals.
# Conclusion