/******************************************************
*                                                     
*  Description:  Vorlage Ampelsteurerung                                
*         Date:  05.01.2018                          
*    File Name:  ampel_wo_src.v                              
*      Version:  1.2                                  
*       Target:  Simulation and Synthesis             
*   Technology:                                       
*                                                     
* Rev   Author   Date          Changes                
* -----------------------------------------------------
* 1.0   RHK      10.10.2011    Initial Release        
* 1.1   JZ       10.03.2016    several bugfixes
* 1.2   JZ       05.01.2018    angepasst auf neues Ampelboard
* 1.3   MW       07.03.2019    STATE Konstanten angepasst
*******************************************************/

`timescale 1ns / 1ps

module ampel (
  input              CLOCK_50,
  input        [1:0] KEY,
  output       [2:0] LEDH_L,
  output       [2:0] LEDH_R,
  output       [2:0] LEDN_L,
  output       [2:0] LEDN_R,
  output       [1:0] LEDF_L,
  output       [1:0] LEDF_R, 
  output reg			DBG  
);

reg [9:0] CLKDIV1;
reg [9:0] CLKDIV2;
reg [9:0] CLKDIV3;

reg MELDER;
reg MELDER_Q;
reg MELDER_QQ;
reg MELDER_ACK;
reg CLOCK_ENABLE;

reg START_WARTEN;
reg [3:0] STATE;
reg [2:0] HAUPTSTR;
reg [2:0] NEBENSTR;
reg [1:0] FUSSGAENGER;

reg [3:0] WARTEZAEHLER;
reg [3:0] WARTEWERT;

wire en_div_1;
wire en_div_2;
wire en_div_3;

wire tc_div_1;
wire tc_div_2;
wire tc_div_3;

wire [9:0] q_div_1;
wire [9:0] q_div_2;
wire [9:0] q_div_3;

//                       R Gr
parameter FUSS_AUS   = 2'b00;
parameter FUSS_ROT   = 2'b10;
parameter FUSS_GRUEN = 2'b01;
//                      R Ge Gr
parameter AUTO_AUS   = 3'b000;
parameter AUTO_ROT   = 3'b100;
parameter AUTO_GELB  = 3'b010;
parameter AUTO_GRUEN = 3'b001;

assign RESET                     = ~KEY[1];

assign LEDH_L  = HAUPTSTR;
assign LEDH_R  = HAUPTSTR;
assign LEDN_L = NEBENSTR;
assign LEDN_R = NEBENSTR;
assign LEDF_L = FUSSGAENGER;
assign LEDF_R = FUSSGAENGER;

`ifdef SIMULATION
`define DIVVAL1 10-1
`define DIVVAL3 5-1
`else
`define DIVVAL1 1000-1
`define DIVVAL3 50-1
`endif

`define FUSS_WARTEN       4  //Wartezeit
`define GELB_DAUER        4  //Wartezeit 
`define FUSS_GRUEN_DAUER  4  //Wartezeit
`define ALLE_ROT_DAUER    4  //Wartezeit

`define HAUPT_GRUEN_DAUER 4  //Wartezeit
`define NEBEN_GRUEN_DAUER 4  //Wartezeit


`define PHASEVAL 8

//clock divider to generate 1 Hz
//

assign en_div_1 = 1'b1;
assign en_div_2 = tc_div_1;
assign en_div_3 = tc_div_1 & tc_div_2;

always  begin
      CLOCK_ENABLE = tc_div_3;
end

// synchronisze KEY to CLOCK_50
always @(posedge CLOCK_50) begin
      MELDER_Q = ~KEY[0];
      MELDER_QQ = MELDER_Q;
end

// Melder sofort setzen 
// Melder zuruecksetzen wenn die Anforderung von der Statemachine verarbeitet
// wurde. Die Ampelanlage gibt den FUSSGAENGERn nur dann gruen wenn
// ein Melder anstehst...			
always @(posedge CLOCK_50 or negedge RESET) begin
  if (RESET)
    MELDER <= 1'b0;
  else begin
      case ({MELDER_QQ, MELDER_ACK})
            2'b01: MELDER <= 1'b0;
            2'b10: MELDER <= 1'b1;
            2'b11: MELDER <= ~MELDER;
            default: ;
      endcase
  end 	
end   

assign WARTEN_FERTIG = (WARTEZAEHLER == 4'b0000);

//Wartezaehler
always @(posedge CLOCK_50 or RESET) begin
      if(RST) begin
            WARTEZAEHLER <= WARTEWERT;
      end
      else if(CLOCK_ENABLE)  begin
            if (START_WARTEN)
                  WARTEZAEHLER <= WARTEWERT;
                  START_WARTEN <= 1'b0;
            if (~WARTEN_FERTIG)
                  WARTEZAEHLER <= WARTEZAEHLER - 1'b1;
      end
end

always @(posedge CLOCK_50 or negedge RESET)
  if (RESET)
    begin
    HAUPTSTR     <= AUTO_GRUEN;
    NEBENSTR     <= AUTO_ROT;
    FUSSGAENGER  <= FUSS_ROT;
    START_WARTEN <= 1'b0;
    STATE        <= 4'd0;
    MELDER_ACK   <= 1'b0;
    end
  else
  if (CLOCK_ENABLE)
  case (STATE)
    4'd0: begin
            if(WARTEN_FERTIG) begin
                  HAUPTSTR <= AUTO_GRUEN;
                  NEBENSTR <= AUTO_ROT;
                  FUSSGAENGER <= FUSS_ROT;
                  START_WARTEN <= 1'b1;
                  WARTEWERT <= HAUPT_GRUEN_DAUER;
            end else begin
                  START_WARTEN <= 1'b0;
            end
          end        
    4'd1: begin
            if(WARTEN_FERTIG) begin
                  HAUPTSTR = AUTO_GELB;
                  NEBENSTR <= AUTO_ROT;
                  FUSSGAENGER <= FUSS_ROT;
                  START_WARTEN <= 1'b1;
                  WARTEWERT <= GELB_DAUER;
            end else begin
                  START_WARTEN <= 1'b0;
            end
          end
    4'd2: begin
            if(WARTEN_FERTIG && MELDER) begin
                  HAUPTSTR <= AUTO_ROT;
                  NEBENSTR <= AUTO_ROT;
                  FUSSGAENGER <= FUSS_ROT;
                  START_WARTEN <= 1'b1;
                  WARTEWERT <= FUSS_WARTEN;
                  MELDER_ACK <= 1'b1; 

            end else if (WARTEN_FERTIG && ~MELDER) begin
                  HAUPTSTR <= AUTO_ROT;
                  NEBENSTR <= AUTO_ROT;
                  FUSSGAENGER <= FUSS_ROT;
                  START_WARTEN <= 1'b1;
                  WARTEWERT <= ALLE_ROT_DAUER;

            end else if(~WARTEN_FERTIG) begin
                  START_WARTEN <= 1'b0;
            end
          end
    4'd3: begin
            if(WARTEN_FERTIG) begin
                  HAUPTSTR <= AUTO_ROT;
                  NEBENSTR <= AUTO_ROT;
                  FUSSGAENGER <= FUSS_GRUEN;
                  START_WARTEN <= 1'b1;
                  WARTEWERT <= FUSS_GRUEN_DAUER;
                  MELDER_ACK <= 1'b0;

            end else begin
                  START_WARTEN <= 1'b0;
            end
          end 
    4'd4: begin
            if(WARTEN_FERTIG) begin
                  HAUPTSTR <= AUTO_ROT;
                  NEBENSTR <= AUTO_GELB|AUTO_ROT;
                  FUSSGAENGER <= FUSS_ROT;
                  START_WARTEN <= 1'b1;
                  WARTEWERT <= GELB_DAUER;

            end else begin
                  START_WARTEN <= 1'b0;
            end
          end
    4'd5: begin
            if(WARTEN_FERTIG) begin
                  HAUPTSTR <= AUTO_ROT;
                  NEBENSTR <= AUTO_GRUEN;
                  FUSSGAENGER <= FUSS_ROT;
                  START_WARTEN <= 1'b1;
                  WARTEWERT = NEBEN_GRUEN_DAUER;

            end else begin
                  START_WARTEN <= 1'b0;
            end
          end
    4'd6: begin
            if(WARTEN_FERTIG) begin
                  HAUPTSTR = AUTO_ROT;
                  NEBENSTR = AUTO_GELB;
                  FUSSGAENGER = FUSS_ROT;
                  START_WARTEN = 1'b1;
                  WARTEWERT = GELB_DAUER;

            end else begin
                  START_WARTEN <= 1'b0;
            end
          end     
    4'd7: begin
            if(WARTEN_FERTIG) begin
                  HAUPTSTR = AUTO_ROT;
                  NEBENSTR = AUTO_ROT;
                  FUSSGAENGER = FUSS_ROT;
                  START_WARTEN = 1'b1;
                  WARTEWERT = ALLE_ROT_DAUER;

            end else begin
                  START_WARTEN <= 1'b0;
            end
          end     
    4'd8: begin
            if(WARTEN_FERTIG) begin
                  HAUPTSTR = AUTO_GELB|AUTO_ROT;
                  NEBENSTR = AUTO_ROT;
                  FUSSGAENGER = FUSS_ROT;
                  START_WARTEN = 1'b1;
                  WARTEWERT = GELB_DAUER;

            end else begin
                  START_WARTEN <= 1'b0;
            end
          end     
    default:                      
          STATE <= 4'd1;
  endcase

mod_n_counter_10bit #(.N(DIVVAL1)) clock_divider_1(
      .CLK(CLOCK_50),
      .RST(RESET),
      .EN(en_div_1),
      .Q(q_div_1),
      .TC(tc_div_1)
);

mod_n_counter_10bit #(.N(DIVVAL1)) clock_divider_2(
      .CLK(CLOCK_50),
      .RST(RESET),
      .EN(en_div_2),
      .Q(q_div_2),
      .TC(tc_div_2)
);

mod_n_counter_10bit #(.N(DIVVAL3)) clock_divider_3(
      .CLK(CLOCK_50),
      .RST(RESET),
      .EN(en_div_3),
      .Q(q_div_3),
      .TC(tc_div_3)
);
                        
endmodule
