module krasin_3_bit_8_channel_pwm_driver (
  input [7:0] io_in,
  output [7:0] io_out
);
    
  wire clk = io_in[0];
  wire pset = io_in[1];
  wire [2:0] addr = io_in[4:2];
  wire [2:0] level = io_in[7:5];

  wire [7:0] pwm_out;
  assign io_out[7:0] = pwm_out;

  // This register is used to determine if the execution just started and we need to reset.
  // It's a bullshit implementation and will most likely not work. I am curious to test it anyway.
  // The idea is that initially this register has a somewhat random value. If it does not match what we expect,
  // we're in a reset mode and set this register to the expected state + reset all other registers.
  // This is not a great way, as it does not guarantee anything, but I already use all input pins and
  // like to live dangerously.
  reg[8:0] reset_canary = 0;

  // 3-bit PWM counter that goes from 0 to 7.
  reg [2:0] counter;

  function is_reset (input [8:0] a);
    begin
      is_reset = (a != 8'b01010101);
    end
  endfunction

  // PWM level for channel0.
  // 0 means always off.
  // 1 means that PWM will be on for just 1 clock cycle and then off for the other 6, giving 1/7 on average.
  // 6 means 6/7 on.
  // 7 means always on.
  reg [2:0] pwm0_level;
  // The rest of the channels.
  reg [2:0] pwm1_level;
  reg [2:0] pwm2_level;
  reg [2:0] pwm3_level;
  reg [2:0] pwm4_level;
  reg [2:0] pwm5_level;
  reg [2:0] pwm6_level;
  reg [2:0] pwm7_level;

  function is_on(input [3:0] level, input[3:0] counter);
    begin
      is_on = (counter < level);
    end
  endfunction // is_on

  assign pwm_out[0] = is_on(pwm0_level, counter);
  assign pwm_out[1] = is_on(pwm1_level, counter);
  assign pwm_out[2] = is_on(pwm2_level, counter);
  assign pwm_out[3] = is_on(pwm3_level, counter);
  assign pwm_out[4] = is_on(pwm4_level, counter);
  assign pwm_out[5] = is_on(pwm5_level, counter);
  assign pwm_out[6] = is_on(pwm6_level, counter);
  assign pwm_out[7] = is_on(pwm7_level, counter);

  // external clock is 1000Hz.
  always @(posedge clk) begin
    // if reset, set counter and pwm levels to 0
    if (is_reset(reset_canary)) begin
      reset_canary = 8'b01010101;
      counter <= 0;
      pwm0_level <= 0;
      pwm1_level <= 0;
      pwm2_level <= 0;
      pwm3_level <= 0;
      pwm4_level <= 0;
      pwm5_level <= 0;
      pwm6_level <= 0;
      pwm7_level <= 0;
    end else begin // if (is_reset(reset_canary))
      if (counter == 6) begin
        // Roll over.
        counter <= 0;
      end else begin
        // increment counter
        counter <= counter + 1'b1;
      end
      if (pset) begin
        case (addr)
          0: pwm0_level <= level;
          1: pwm1_level <= level;
          2: pwm2_level <= level;
          3: pwm3_level <= level;
          4: pwm4_level <= level;
          5: pwm5_level <= level;
          6: pwm6_level <= level;
          7: pwm7_level <= level;
        endcase
      end // if (set)
    end
  end // always @ (posedge clk)
endmodule