package vexriscv.demo import spinal.core._ import vexriscv.plugin.Plugin import vexriscv.{Stageable, DecoderService, VexRiscv} //This plugin example will add a new instruction named SIMD_ADD which do the following : // //RD : Regfile Destination, RS : Regfile Source //RD( 7 downto 0) = RS1( 7 downto 0) + RS2( 7 downto 0) //RD(16 downto 8) = RS1(16 downto 8) + RS2(16 downto 8) //RD(23 downto 16) = RS1(23 downto 16) + RS2(23 downto 16) //RD(31 downto 24) = RS1(31 downto 24) + RS2(31 downto 24) // //Instruction encoding : //0000011----------000-----0110011 // |RS2||RS1| |RD | // //Note : RS1, RS2, RD positions follow the RISC-V spec and are common for all instruction of the ISA class SimdAddPlugin extends Plugin[VexRiscv]{ //Define the concept of IS_SIMD_ADD signals, which specify if the current instruction is destined for ths plugin object IS_SIMD_ADD extends Stageable(Bool) //Callback to setup the plugin and ask for different services override def setup(pipeline: VexRiscv): Unit = { import pipeline.config._ //Retrieve the DecoderService instance val decoderService = pipeline.service(classOf[DecoderService]) //Specify the IS_SIMD_ADD default value when instruction are decoded decoderService.addDefault(IS_SIMD_ADD, False) //Specify the instruction decoding which should be applied when the instruction match the 'key' parttern decoderService.add( //Bit pattern of the new SIMD_ADD instruction key = M"0000011----------000-----0110011", //Decoding specification when the 'key' pattern is recognized in the instruction List( IS_SIMD_ADD -> True, REGFILE_WRITE_VALID -> True, //Enable the register file write BYPASSABLE_EXECUTE_STAGE -> True, //Notify the hazard management unit that the instruction result is already accessible in the EXECUTE stage (Bypass ready) BYPASSABLE_MEMORY_STAGE -> True, //Same as above but for the memory stage RS1_USE -> True, //Notify the hazard management unit that this instruction use the RS1 value RS2_USE -> True //Same than above but for RS2. ) ) } override def build(pipeline: VexRiscv): Unit = { import pipeline._ import pipeline.config._ //Add a new scope on the execute stage (used to give a name to signals) execute plug new Area { //Define some signals used internally to the plugin val rs1 = execute.input(RS1).asUInt //32 bits UInt value of the regfile[RS1] val rs2 = execute.input(RS2).asUInt val rd = UInt(32 bits) //Do some computation rd(7 downto 0) := rs1(7 downto 0) + rs2(7 downto 0) rd(16 downto 8) := rs1(16 downto 8) + rs2(16 downto 8) rd(23 downto 16) := rs1(23 downto 16) + rs2(23 downto 16) rd(31 downto 24) := rs1(31 downto 24) + rs2(31 downto 24) //When the instruction is a SIMD_ADD one, then write the result into the register file data path. when(execute.input(IS_SIMD_ADD)) { execute.output(REGFILE_WRITE_DATA) := rd.asBits } } } }