I want to add a MMIO Peripheral, but this is strange

**Hello everyone, **

I have the Artix-7 35T FPGA and I am trying to add MMIO peripheral in Freedom E300 platform.

I am reffering to https://github.com/ucb-bar/project-template.

So I add mypwm directory and PWM.scala in freedom/sifive-blocks/src/main/scala/devices/.

The code is shown below.

The main questions are why there are no PWM generation blocks in the TLPWM block and why the pwmout output port( 1bit) does not generated in generated RTL.


//package example
package sifive.blocks.devices.mypwm

import chisel3._
import chisel3.util._
import freechips.rocketchip.subsystem.BaseSubsystem
import freechips.rocketchip.config.{Parameters, Field}
import freechips.rocketchip.diplomacy._
import freechips.rocketchip.regmapper.{HasRegMap, RegField}
import freechips.rocketchip.tilelink._
import freechips.rocketchip.util.UIntIsOneOf

case class MYPWMParams(address: BigInt, beatBytes: Int)

class MYPWMBase(w: Int) extends Module {
val io = IO(new Bundle {
val mypwmout = Output(Bool())
val period = Input(UInt(w.W))
val duty = Input(UInt(w.W))
val enable = Input(Bool())

// The counter should count up until period is reached
val counter = Reg(UInt(w.W))

when (counter >= (io.period - 1.U)) {
counter := 0.U
} .otherwise {
counter := counter + 1.U

// If MYPWM is enabled, mypwmout is high when counter < duty
// If MYPWM is not enabled, it will always be low
io.mypwmout := io.enable && (counter < io.duty)

trait MYPWMTLBundle extends Bundle {
val mypwmout = Output(Bool())

trait MYPWMTLModule extends HasRegMap {
val io: MYPWMTLBundle
implicit val p: Parameters
def params: MYPWMParams

// How many clock cycles in a MYPWM cycle?
val period = Reg(UInt(32.W))
// For how many cycles should the clock be high?
val duty = Reg(UInt(32.W))
// Is the MYPWM even running at all?
val enable = RegInit(false.B)

val base = Module(new MYPWMBase(32))
io.mypwmout := base.io.mypwmout
base.io.period := period
base.io.duty := duty
base.io.enable := enable

0x00 -> Seq(
RegField(32, period)),
0x04 -> Seq(
RegField(32, duty)),
0x08 -> Seq(
RegField(1, enable)))

class MYPWMTL(c: MYPWMParams)(implicit p: Parameters)
extends TLRegisterRouter(
c.address, “mypwm”, Seq(“ucbbar,mypwm”),
beatBytes = c.beatBytes)(
new TLRegBundle(c, _) with MYPWMTLBundle)(
new TLRegModule(c, _, _) with MYPWMTLModule)

trait HasPeripheryMYPWM { this: BaseSubsystem =>
implicit val p: Parameters

private val address = 0x10001000
private val portName = “mypwm”

val mypwm = LazyModule(new MYPWMTL(
MYPWMParams(address, pbus.beatBytes))§)

pbus.toVariableWidthSlave(Some(portName)) { mypwm.node }

trait HasPeripheryMYPWMModuleImp extends LazyModuleImp {
implicit val p: Parameters
val outer: HasPeripheryMYPWM

val mypwmout = IO(Output(Bool()))

mypwmout := outer.mypwm.module.io.mypwmout

and add this code in $(freedom)/src/main/~~/System.scala


class MYE300ArtyDevKitSystem(implicit p: Parameters) extends E300ArtyDevKitSystem
with HasPeripheryMYPWM {
override lazy val module = new MYE300ArtyDevKitSystemModule(this)

class MYE300ArtyDevKitSystemModule(l: MYE300ArtyDevKitSystem)
extends E300ArtyDevKitSystemModule(l) with HasPeripheryMYPWMModuleImp


and edit E300ArtyDevKitSystem to MYE300ArtyDevKitSystem in Platform.scala

I just wanted to see if the MMIO Peri IP was generated properly, so I did not connect the external IO.

However, the following RTL was generated as a result of compilation.

The generated code does not show the PWM output port and the PWM generation block.

However, as a result of the simulation, the register(period, duty, enable) setting is performed by the C code.

generated Verilog code

module MYPWMTL(
input clock,
input reset,
output auto_in_a_ready,
input auto_in_a_valid,
input [2:0] auto_in_a_bits_opcode,
input [2:0] auto_in_a_bits_param,
input [1:0] auto_in_a_bits_size,
input [5:0] auto_in_a_bits_source,
input [28:0] auto_in_a_bits_address,
input [3:0] auto_in_a_bits_mask,
input [31:0] auto_in_a_bits_data,
input auto_in_a_bits_corrupt,
input auto_in_d_ready,
output auto_in_d_valid,
output [2:0] auto_in_d_bits_opcode,
output [1:0] auto_in_d_bits_size,
output [5:0] auto_in_d_bits_source,
output [31:0] auto_in_d_bits_data

reg [31:0] period;
reg [31:0] duty;
reg enable;

TLMonutor_74 TLMonitor(


always @(posedge clock) begin
if (_T_396) begin
period <= auto_in_a_bits_data;
if (_T_354) begin
duty <= auto_in_a_bits_data;
if (reset) begin
enable <= 1’h0;
end else begin
if (_T_312) begin
enable <= _T_316;


What is the problem?? I need help.

Thank you!!

1 Like