dakies/OSS_Verilog huggingface dataset:
module HazardDetector(
    input [15:0] inst,
    input [1:0] ID_EX_RFWriteAddress, EX_MEM_RFWriteAddress, MEM_WB_RFWriteAddress,
    input ID_EX_RegWrite, EX_MEM_RegWrite, MEM_WB_RegWrite,
    output reg Stall
    );
    /*
    [Hazard Detector module]
    Purpose:
        Detect data hazards in the CPU, and send out the 'Stall' signal indicating whether to stall the pipeline.
        
    Inputs:
        The instruction currently in the ID stage
        Register write enable and write address of EX, MEM, and WB stage.
    
    Output: 
        Stall: stall pipeline(1) or proceed without stalling(0)
    */
    
    always @(*) begin
    
        // for instructions that require both rs and rt
        // first if statement checks instruction type
        // second if statement checks data dependency
        if ((inst[15:12]==`OPCODE_R && (inst[5:0]==`FUNC_ADD || inst[5:0]==`FUNC_SUB || inst[5:0]==`FUNC_AND || inst[5:0]==`FUNC_ORR)) || inst[15:12]==`OPCODE_SWD || inst[15:12]==`OPCODE_BNE || inst[15:12]==`OPCODE_BEQ) begin 
          
            if (((ID_EX_RFWriteAddress ==inst[11:10]) && ID_EX_RegWrite) || ((EX_MEM_RFWriteAddress==inst[11:10]) && EX_MEM_RegWrite) || ((MEM_WB_RFWriteAddress==inst[11:10]) && MEM_WB_RegWrite) 
             || ((ID_EX_RFWriteAddress ==inst[9:8])   && ID_EX_RegWrite) || ((EX_MEM_RFWriteAddress==inst[9:8])   && EX_MEM_RegWrite) || ((MEM_WB_RFWriteAddress==inst[9:8])   && MEM_WB_RegWrite)) begin
                Stall = 1;
            end // of if statement that checks data dependency of rs and rt
            else begin
                Stall = 0;
            end
        end // of if statement that checks if both rs and rt are required
        
        // for instructions that require only rs
        // first if statement checks instruction type
        // second if statement checks data dependency
        else if ((inst[15:12]==`OPCODE_R && (inst[5:0]==`FUNC_NOT || inst[5:0]==`FUNC_TCP || inst[5:0]==`FUNC_SHL || inst[5:0]==`FUNC_SHR || inst[5:0]==`FUNC_WWD || inst[5:0]==`FUNC_JPR || inst[5:0]==`FUNC_JRL))
          || inst[15:12]==`OPCODE_ADI || inst[15:12]==`OPCODE_ORI || inst[15:12]==`OPCODE_LWD || inst[15:12]==`OPCODE_BGZ || inst[15:12]==`OPCODE_BLZ) begin
          
            if  (((ID_EX_RFWriteAddress==inst[11:10]) && ID_EX_RegWrite) || ((EX_MEM_RFWriteAddress==inst[11:10]) && EX_MEM_RegWrite) || ((MEM_WB_RFWriteAddress==inst[11:10]) && MEM_WB_RegWrite)) begin
                Stall = 1;
            end // of if statement that checks data dependency of rs
            else begin
                Stall = 0;
            end
        end // of if statement that checks if rs is required
        
        else begin
            Stall = 0;
        end
        
    end // of always @(*)
    
endmodule
module ALU (
    ALUCtrl,
    Sign,
    in1,
    in2,
    out
);

parameter ADD = 0;
parameter SUB = 1;
parameter AND = 2;
parameter OR = 3;
parameter XOR = 4;
parameter NOR = 5;
parameter SLL = 6;
parameter SRL = 7;
parameter SRA = 8;
parameter SLT = 9;

input [4:0] ALUCtrl;
input Sign;
input [31:0] in1;
input [31:0] in2;
output [31:0] out;

reg [31:0] out;

wire lt_low31;
wire lt_sign;
assign lt_low31 = (in1[30:0] < in2[30:0]);
assign lt_sign = (
    (in1[31] ^ in2[31]) ? 
    (in1[31] > in2[31] ? 1 : 0)
    : lt_low31
);

always @(*) begin
    case(ALUCtrl)
    ADD: out <= in1 + in2;
    SUB: out <= in1 - in2;
    AND: out <= in1 & in2;
    OR: out <= in1 | in2;
    XOR: out <= in1 ^ in2;
    NOR: out <= ~(in1 | in2);
    SLL: out <= in2 << in1[4:0];
    SRL: out <= in2 >> in1[4:0];
    SRA: out <= {{32{in2[31]}}, in2} >> in1[4:0];
    SLT: out <= {31'h00000000, Sign ? lt_sign : in1 < in2};
    default: out <= 0;
    endcase
end

endmodule
module EX_MEM(
    input wire clk,
    input wire reset,
    
    input wire MemRead_EX,
    input wire MemWrite_EX,
    input wire [31:0] ALUOut_EX,
    input wire [4:0] Rw_EX,
    input wire [1:0] MemtoReg_EX,
    input wire RegWrite_EX,
    input wire [31:0] rt_EX,
    input wire LoadByte_EX,
    input wire [31:0] PC_EX,
    input wire Load_EX,

    output reg MemRead_MEM,
    output reg MemWrite_MEM,
    output reg [31:0] ALUOut_MEM,
    output reg [4:0] Rw_MEM,
    output reg [1:0] MemtoReg_MEM,
    output reg RegWrite_MEM,
    output reg [31:0] rt_MEM,
    output reg LoadByte_MEM,
    output reg [31:0] PC_MEM,
    output reg Load_MEM
);

initial begin
    MemRead_MEM <= 0;
    MemWrite_MEM <= 0;
    ALUOut_MEM <= 0;
    Rw_MEM <= 0;
    MemtoReg_MEM <= 0;
    RegWrite_MEM <= 0;
    rt_MEM <= 0;
    LoadByte_MEM <= 0;
    PC_MEM <= 0; 
    Load_MEM <= 0;
end

always@(posedge clk or posedge reset) begin
    if(reset) begin
        MemRead_MEM <= 0;
        MemWrite_MEM <= 0;
        ALUOut_MEM <= 0;
        Rw_MEM <= 0;
        MemtoReg_MEM <= 0;
        RegWrite_MEM <= 0;
        rt_MEM <= 0;
        LoadByte_MEM <= 0;
        PC_MEM <= 0;
        Load_MEM <= 0;
    end
    else begin
        MemRead_MEM <= MemRead_EX;
        MemWrite_MEM <= MemWrite_EX;
        ALUOut_MEM <= ALUOut_EX;
        Rw_MEM <= Rw_EX;
        MemtoReg_MEM <= MemtoReg_EX;
        RegWrite_MEM <= RegWrite_EX;
        rt_MEM <= rt_EX;
        LoadByte_MEM <= LoadByte_EX;
        PC_MEM <= PC_EX;
        Load_MEM <= Load_EX;
    end
end

endmodule
module ALUControl (
    OpCode,
    Funct,
    ALUCtrl,
    Sign
);

parameter ADD = 0;
parameter SUB = 1;
parameter AND = 2;
parameter OR = 3;
parameter XOR = 4;
parameter NOR = 5;
parameter SLL = 6;
parameter SRL = 7;
parameter SRA = 8;
parameter SLT = 9;

input [5:0] OpCode;
input [5:0] Funct;
output [4:0] ALUCtrl;
output Sign;

reg [4:0] ALUCtrl;
reg Sign;

always @(OpCode, Funct) begin
    case(OpCode)
    6'h23: ALUCtrl <= ADD;  // lw
    6'h20: ALUCtrl <= ADD;  // lb
    6'h2b: ALUCtrl <= ADD;  // sw
    6'h0f: ALUCtrl <= ADD; // lui
    6'h08: begin
        ALUCtrl <= ADD;
        Sign <= 1;
    end
    6'h09: begin
        ALUCtrl <= ADD;
        Sign <= 0;
    end
    6'h0c: ALUCtrl <= AND;
    6'h0a: begin
        ALUCtrl <= SLT;
        Sign <= 1;
    end
    6'h0b: begin
        ALUCtrl <= SLT;
        Sign <= 0;
    end
    6'h04: ALUCtrl <= SUB;  // beq
    default: begin // Opcode = 0
        case(Funct)
        6'h20: begin
            ALUCtrl <= ADD;
            Sign <= 1;
        end
        6'h21: begin
            ALUCtrl <= ADD;
            Sign <= 0;
        end
        6'h22: begin
            ALUCtrl <= SUB;
            Sign <= 1;
        end
        6'h23: begin
            ALUCtrl <= SUB;
            Sign <= 0;
        end
        6'h24: ALUCtrl <= AND;
        6'h25: ALUCtrl <= OR;
        6'h26: ALUCtrl <= XOR;
        6'h27: ALUCtrl <= NOR;
        6'h00: ALUCtrl <= SLL;
        6'h02: begin
            ALUCtrl <= SRL;
            Sign <= 0;
        end
        6'h03: begin
            ALUCtrl <= SRA;
            Sign <= 1;
        end
        6'h2a: begin
            ALUCtrl <= SLT;
            Sign <= 1;
        end
        6'h2b: begin
            ALUCtrl <= SLT;
            Sign <= 0;
        end
        6'h08: ALUCtrl <= ADD;  // jr
        6'h09: ALUCtrl <= ADD;  // jalr
        default: ALUCtrl <= ALUCtrl;
        endcase
    end
    endcase    
end
    
endmodule
module ALUForwarding(
    input wire [4:0] rs_EX,
    input wire [4:0] rt_EX,
    input wire [4:0] Rw_MEM,
    input wire [4:0] Rw_WB,
    input wire RegWrite_MEM,
    input wire RegWrite_WB,
    input wire ALUSrcA_EX,
    input wire ALUSrcB_EX,
    output wire [1:0] ALUChooseA,       // A: 0-dataA  1-Shamt  2-WriteData_MEM  3-WriteData_WB 
    output wire [1:0] ALUChooseB        // B: 0-dataB  1-Imm    2-WriteData_MEM  3-WriteData_WB
);

    assign ALUChooseA = ALUSrcA_EX == 1 ? 1 :
                        (RegWrite_MEM && (Rw_MEM == rs_EX) && (Rw_MEM != 0)) ? 2 :   // 优先判断MEM阶段，即前一条指令
                        (RegWrite_WB && (Rw_WB == rs_EX) && (Rw_WB != 0)) ? 3 : 0;
    assign ALUChooseB = ALUSrcB_EX == 1 ? 1 : 
                        (RegWrite_MEM && (Rw_MEM == rt_EX) && (Rw_MEM != 0)) ? 2 :   // 优先判断MEM阶段，即前一条指令
                        (RegWrite_WB && (Rw_WB == rt_EX) && (Rw_WB != 0)) ? 3 : 0;

endmodule
module Control(OpCode, Funct,
	PCSrc, Branch, RegWrite, RegDst, 
	MemRead, MemWrite, MemtoReg, 
	ALUSrc1, ALUSrc2, ExtOp, LuOp, JOp, LoadByte
);
	input wire [5:0] OpCode;
	input wire [5:0] Funct;
	output wire [1:0] PCSrc;
	output wire Branch;
	output wire RegWrite;
	output wire [1:0] RegDst;
	output wire MemRead;
	output wire MemWrite;
	output wire [1:0] MemtoReg;
	output wire ALUSrc1;
	output wire ALUSrc2;
	output wire ExtOp;
	output wire LuOp;
	output wire JOp;
	output wire LoadByte;
	
	// Your code below

	assign PCSrc = (OpCode == 6'h02 || OpCode == 6'h03) ? 1 :		// j,jal: 1 -- jr,jalr: 2 -- 0 
					(OpCode == 0 && (Funct == 6'h08 || Funct == 6'h09)) ? 2 : 0;
	     
	assign Branch = OpCode == 6'h04 || OpCode == 6'h05 || OpCode == 6'h06 || OpCode == 6'h07 || OpCode == 6'h01;
	
	assign RegWrite = (OpCode == 6'h2b || OpCode == 6'h04 || OpCode == 6'h05 || OpCode == 6'h06 || OpCode == 6'h07 || OpCode == 6'h01 ||
						OpCode == 6'h02 || (OpCode == 6'h00 && Funct == 6'h08)) ? 0 : 1;
	
	assign RegDst = (OpCode == 6'h23 || OpCode == 6'h20 || OpCode == 6'h0f || OpCode == 6'h08 || OpCode == 6'h09 ||
						OpCode == 6'h0c || OpCode == 6'h0a || OpCode == 6'h0b) ? 0 :
							OpCode == 6'h03 ? 2 : 1;	// 0: rt; 1: rd; 2: ra

	assign MemRead = OpCode == 6'h23 || OpCode == 6'h20;

	assign MemWrite = OpCode == 6'h2b;

	assign MemtoReg = OpCode == 6'h23 || OpCode == 6'h20 ? 1 :
						(OpCode == 6'h03 || (OpCode == 6'h00 && Funct == 6'h09)) ? 2 : 0;
	
	assign ALUSrc1 = (OpCode == 6'h00 && (Funct == 6'h00 || Funct == 6'h02 || Funct == 6'h03)) ? 1 : 0;
	
	assign ALUSrc2 = (OpCode == 6'h23 || OpCode == 6'h20 || OpCode == 6'h2b || OpCode == 6'h0f ||
						OpCode == 6'h08 || OpCode == 6'h09 || OpCode == 6'h0c ||
							OpCode == 6'h0a || OpCode == 6'h0b) ? 1 : 0;

	assign ExtOp = OpCode == 6'h0c ? 0 : 1;

	assign LuOp = OpCode == 6'h0f;

	assign JOp = OpCode == 6'h02 || OpCode == 6'h03 || (OpCode == 6'h00 && (Funct == 6'h08 || Funct == 6'h09));
	
	assign LoadByte = OpCode == 6'h20;
	// Your code above
	
endmodule
module ImmProcess(ExtOp, LuiOp, Immediate, ImmExtOut, ImmExtShift); 
    //Input Control Signals
    input ExtOp; //'0'-zero extension, '1'-signed extension
    input LuiOp; //for lui instruction
    //Input
    input [15:0] Immediate;
    //Output
    output [31:0] ImmExtOut;
    output [31:0] ImmExtShift;

    wire [31:0] ImmExt;
    
    assign ImmExt = {ExtOp? {16{Immediate[15]}}: 16'h0000, Immediate};
    assign ImmExtShift = ImmExt << 2;
    assign ImmExtOut = LuiOp? {Immediate, 16'h0000}: ImmExt;

endmodule
module IF_ID(
    input wire clk,
    input wire reset,
    input wire flush_IFID,
    input wire hold,
    input wire Load_EX,     // if Load, flush is more important than hold

    input wire [31:0] Instruction,
    input wire [31:0] PC_IF,
    output reg [5:0] OpCode,
    output reg [4:0] rs,
    output reg [4:0] rt,
    output reg [4:0] rd,
    output reg [4:0] Shamt,
    output reg [5:0] Funct,
    output reg [31:0] PC_ID
);

initial begin
    OpCode <= 0;
    rs <= 0;
    rt <= 0;
    rd <= 0;
    Shamt <= 0;
    Funct <= 0;
    PC_ID <= 0;
end

always @(posedge clk or posedge reset) begin
    if(reset || (flush_IFID && Load_EX)) begin       // || flush_IFID
        OpCode <= 0;
        rs <= 0;
        rt <= 0;
        rd <= 0;
        Shamt <= 0;
        Funct <= 0;
        PC_ID <= 0;
    end
    else if (hold) begin
        OpCode <= OpCode;
        rs <= rs;
        rt <= rt;
        rd <= rd;
        Shamt <= Shamt;
        Funct <= Funct;
        PC_ID <= PC_ID;
    end
    else if (flush_IFID) begin
        OpCode <= 0;
        rs <= 0;
        rt <= 0;
        rd <= 0;
        Shamt <= 0;
        Funct <= 0;
        PC_ID <= 0;
    end
    else begin
        OpCode <= Instruction[31:26];
        rs <= Instruction[25:21];
        rt <= Instruction[20:16];
        rd <= Instruction[15:11];
        Shamt <= Instruction[10:6];
        Funct <= Instruction[5:0];
        PC_ID <= PC_IF;
    end
//     else if(!hold) begin
//         if(flush_IFID) begin
//             OpCode <= 0;
//             rs <= 0;
//             rt <= 0;
//             rd <= 0;
//             Shamt <= 0;
//             Funct <= 0;
//             PC_ID <= 0;
//         end
//         else begin
//             OpCode <= Instruction[31:26];
//             rs <= Instruction[25:21];
//             rt <= Instruction[20:16];
//             rd <= Instruction[15:11];
//             Shamt <= Instruction[10:6];
//             Funct <= Instruction[5:0];
//             PC_ID <= PC_IF;
//         end
//     end
//     else begin
//         OpCode <= OpCode;
//         rs <= rs;
//         rt <= rt;
//         rd <= rd;
//         Shamt <= Shamt;
//         Funct <= Funct;
//         PC_ID <= PC_ID;
//     end

end

endmodule
module test_pipeline();
	
	reg reset;
	reg sysclk;
	wire [7:0] leds;
	wire [7:0] bcd7;
	wire [3:0] an;
	
	PipelineCPU pipelineCpu(sysclk, reset, leds, bcd7, an);
	
	initial begin
		reset = 1;
		sysclk = 1;
		#10 reset = 0;
	end
	
	always #5 sysclk = ~sysclk;
		
endmodule
module CLK(
    input wire sysclk,
    input wire reset,
    output reg clk
);

reg [31:0] count;

initial begin
    count <= 0;
end

always@(posedge sysclk or posedge reset) begin
    if(reset) begin
        count <= 0;
        clk <= 0;
    end
    else if(count >= 2) begin
        clk <= ~clk;
        count <= 0;
    end
    else begin
        count <= count + 1;
    end
end

endmodule
module MEM_WB(
    input wire clk,
    input wire reset,

    input wire RegWrite_MEM,
    input wire [1:0] MemtoReg_MEM,
    input wire [4:0] Rw_MEM,
    input wire [31:0] ReadData_MEM,
    input wire [31:0] ALUOut_MEM,
    input wire [31:0] PC_MEM,
    input wire Load_MEM,

    output reg RegWrite_WB,
    output reg [1:0] MemtoReg_WB,
    output reg [4:0] Rw_WB,
    output reg [31:0] ReadData_WB,
    output reg [31:0] ALUOut_WB,
    output reg [31:0] PC_WB,
    output reg Load_WB
);

initial begin
    RegWrite_WB <= 0;
    MemtoReg_WB <= 0;
    Rw_WB <= 0;
    ReadData_WB <= 0;
    ALUOut_WB <= 0;
    PC_WB <= 0;
    Load_WB <= 0;
end

always @(posedge clk or posedge reset) begin
    if(reset) begin
        RegWrite_WB <= 0;
        MemtoReg_WB <= 0;
        Rw_WB <= 0;
        ReadData_WB <= 0;
        ALUOut_WB <= 0;
        PC_WB <= 0;
        Load_WB <= 0;
    end
    else begin
        RegWrite_WB <= RegWrite_MEM;
        MemtoReg_WB <= MemtoReg_MEM;
        Rw_WB <= Rw_MEM;
        ReadData_WB <= ReadData_MEM;
        ALUOut_WB <= ALUOut_MEM;
        PC_WB <= PC_MEM;
        Load_WB <= Load_MEM;
    end
end

endmodule
module BranchJudge(
    input wire [5:0] OpCode,
    input wire [31:0] data1_ID,
    input wire [31:0] data2_ID,
    input wire Branch,
    output reg Zero
);

    always@(*) begin
        if(Branch) begin
            if(OpCode == 6'h04) begin       // beq
                Zero <= data1_ID == data2_ID;
            end
            else if(OpCode == 6'h05) begin  // bne
                Zero <= data1_ID != data2_ID;
            end
            else if(OpCode == 6'h06) begin  // blez
                Zero <= (data1_ID <= data2_ID);
            end
            else if(OpCode == 6'h07) begin  // bgtz
                Zero <= (data1_ID > data2_ID);
            end
            else if(OpCode == 6'h01) begin  // bltz
                Zero <= (data1_ID < data2_ID);
            end
            else begin
                Zero <= Zero;
            end
        end
        else begin
            Zero <= 0;
        end
    end

endmodule
module RegisterFile(clk, reset, RegWrite, Read_register1, Read_register2, Write_register, Write_data, Read_data1, Read_data2);
	input reset, clk;
	input RegWrite;
	input [4:0] Read_register1, Read_register2, Write_register;
	input [31:0] Write_data;
	output [31:0] Read_data1, Read_data2;
	
	reg [31:0] RF_data[31:0];
	wire Writable;
	
	assign Writable = RegWrite && (Write_register != 5'b00000);
	
	assign Read_data1 = (Write_register == Read_register1 && Writable) ? Write_data :
						(Read_register1 == 5'b00000)? 32'h00000000: RF_data[Read_register1];
	assign Read_data2 = (Write_register == Read_register2 && Writable) ? Write_data :
						(Read_register2 == 5'b00000)? 32'h00000000: RF_data[Read_register2];
	
	integer i;
	always @(posedge reset or posedge clk)
		if (reset)
			for (i = 1; i < 32; i = i + 1)
				RF_data[i] <= 32'h00000000;
		else if (Writable)
			RF_data[Write_register] <= Write_data;

endmodule
module BranchForwarding(
    input wire [4:0] rs,
    input wire [4:0] rt,
    input wire [4:0] Rw_MEM,
    input wire RegWrite_MEM,
    input wire Load_WB,
    input wire [4:0] Rw_WB,
    output wire [1:0] BrForwardingA,
    output wire [1:0] BrForwardingB
);

    assign BrForwardingA = rs == Rw_WB && Load_WB ? 2 : 
                           rs == Rw_MEM && RegWrite_MEM ? 1 : 0;
    assign BrForwardingB = rt == Rw_WB && Load_WB ? 2 : 
                           rt == Rw_MEM && RegWrite_MEM ? 1 : 0;

endmodule
module PC(clk, reset, PC_i, PC_o);
    //Input Clock Signals
    input reset;             
    input clk;
    //Input PC             
    input [31:0] PC_i;
    //Output PC  
    output reg [31:0] PC_o; 
    
    initial begin
        PC_o <= 0;
    end

    always@(posedge reset or posedge clk)
    begin
        if(reset) begin
            PC_o <= 0;
        end else begin
            PC_o <= PC_i;
        end
    end
endmodule
module tb_vga;
    reg clk_4x, clk_2x, clk;
    reg reset;
	reg sel_ram;
	reg sel_ctl;
	reg we;
	reg [12:0] addr;
	reg [7:0] din;
	wire [7:0] ram_dout;
	wire [7:0] ctl_dout;
	wire [1:0] vga_r, vga_g, vga_b;
	wire vga_vs, vga_hs;
	
    // 40 MHz clock source
    always
        #12.5 clk_4x = ~clk_4x;
    
	// generate 2x, 1x clocks from 4x clk
	always @(posedge clk_4x)
		{clk,clk_2x} <= {clk,clk_2x} + 2'b01;
	
    // reset
    initial
    begin
`ifdef icarus
  		$dumpfile("tb_vga.vcd");
		$dumpvars;
`endif
        
        // init regs
        clk_4x = 1'b0;
        clk_2x = 1'b0;
        clk = 1'b0;
        reset = 1'b1;
		sel_ram = 1'b0;
		sel_ctl = 1'b0;
		we = 1'b0;
		addr = 13'h0000;
		din = 8'h00;
        
        // release reset
        #60
		@(posedge clk)
        reset = 1'b0;
        
`ifdef icarus
        // stop after 1 sec
		//#40000000 $finish; 	// full frame
		#1000000 $finish;		//quicker for testing
`endif
    end
    
    // Unit under test
	vga uut
	(
		.clk(clk),
		.clk_4x(clk_4x),
		.reset(reset),
		.sel_ram(sel_ram),
		.sel_ctl(sel_ctl),
		.we(we),
		.addr(addr),
		.din(din),
		.ram_dout(ram_dout),
		.ctl_dout(ctl_dout),
		.vga_r(vga_r),
		.vga_g(vga_g),
		.vga_b(vga_b),
		.vga_vs(vga_vs),
		.vga_hs(vga_hs)
	);
endmodule
module Keyboard(
    input       HCLK,
    input       HRESETn,
    input   [3:0]   col,
    output  wire    [3:0] key_interrupt
);


reg [11:0]  sreg0;
wire    [11:0]  sreg0_nxt;

reg [11:0]  sreg1;
wire    [11:0]  sreg1_nxt;

reg [11:0]  sreg2;
wire    [11:0]  sreg2_nxt;

reg [11:0]  sreg3;
wire    [11:0]  sreg3_nxt;

assign  sreg0_nxt   =   sreg0 + 1'b1;
assign  sreg1_nxt   =   sreg1 + 1'b1;
assign  sreg2_nxt   =   sreg2 + 1'b1;
assign  sreg3_nxt   =   sreg3 + 1'b1;

always@(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn) begin
        sreg0   <=  12'b0;
    end else if(col[0]) begin
        if(sreg0 != 12'hfff)
           sreg0   <=  sreg0_nxt;
    end else 
        sreg0   <=  12'b0;
end

always@(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn) begin
        sreg1   <=  12'b0;
    end else if(col[1]) begin
        if(sreg1 != 16'hfff)
           sreg1   <=  sreg1_nxt;
    end else 
        sreg1   <=  12'b0;
end

always@(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn) begin
        sreg2   <=  12'b0;
    end else if(col[2]) begin
        if(sreg2 != 12'hfff)
           sreg2   <=  sreg2_nxt;
    end else 
        sreg2   <=  12'b0;
end

always@(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn) begin
        sreg3   <=  12'b0;
    end else if(col[3]) begin
        if(sreg3 != 12'hfff)
           sreg3   <=  sreg3_nxt;
    end else 
        sreg3   <=  12'b0;
end

reg [3:0] key_reg;

assign key_interrupt[0] =   (sreg0 != 12'hfff) & (sreg0_nxt == 12'hfff);

assign key_interrupt[1] =   (sreg1 != 12'hfff) & (sreg1_nxt == 12'hfff);

assign key_interrupt[2] =   (sreg2 != 12'hfff) & (sreg2_nxt == 12'hfff);

assign key_interrupt[3] =   (sreg3 != 12'hfff) & (sreg3_nxt == 12'hfff);

endmodule
module CortexM0_SoC_vlg_tst();

reg clk;
reg RSTn;
                        
CortexM0_SoC i1 (
    .clk(clk),
    .RSTn(RSTn)
);

initial begin                                                  
    clk = 0;
    RSTn=0;
    #100
    RSTn=1;

end  
    
always begin                                                  
    #10 clk = ~clk;
end       

endmodule
module GPIO (
    input outEn,
    input clk,
    input RSTn,
    input [7:0]  oData,  
    output[7:0]  iData,  
    inout[7:0]  ioPin
);
reg [7:0] tmp;

always@(posedge clk or negedge RSTn) begin
  if(~RSTn) tmp <= 8'd0;
  else tmp <= ioPin;
end

assign iData = tmp;
assign ioPin = outEn ? oData : 8'bzzzzzzzz;

endmodule
module Block_RAM #(
    parameter ADDR_WIDTH = 14
)   (
    input clka,
    input [ADDR_WIDTH-1:0] addra,
    input [ADDR_WIDTH-1:0] addrb,
    input [31:0] dina,
    input [3:0] wea,
    output reg [31:0] doutb
);

(* ram_style="block" *)reg [31:0] mem [(2**ADDR_WIDTH-1):0];

initial begin
    $readmemh("G:/workspace-windows/M0_task/Task1/keil/code.hex",mem);
end

always@(posedge clka) begin
    if(wea[0]) mem[addra][7:0] <= dina[7:0];
end
always@(posedge clka) begin
    if(wea[1]) mem[addra][15:8] <= dina[15:8];
end
always@(posedge clka) begin
    if(wea[2]) mem[addra][23:16] <= dina[23:16];
end
always@(posedge clka) begin
    if(wea[3]) mem[addra][31:24] <= dina[31:24];
end

always@(posedge clka) begin
    doutb <= mem[addrb];
end

endmodule
module AHBlite_SlaveMUX (

    input HCLK,
    input HRESETn,
    input HREADY,

    //port 0
    input P0_HSEL,
    input P0_HREADYOUT,
    input P0_HRESP,
    input [31:0] P0_HRDATA,

    //port 1
    input P1_HSEL,
    input P1_HREADYOUT,
    input P1_HRESP,
    input [31:0] P1_HRDATA,

    //port 2
    input P2_HSEL,
    input P2_HREADYOUT,
    input P2_HRESP,
    input [31:0] P2_HRDATA,

    //port 3
    input P3_HSEL,
    input P3_HREADYOUT,
    input P3_HRESP,
    input [31:0] P3_HRDATA,

    //port 4
    input P4_HSEL,
    input P4_HREADYOUT,
    input P4_HRESP,
    input [31:0] P4_HRDATA,

    //output
    output wire HREADYOUT,
    output wire HRESP,
    output wire [31:0] HRDATA
);

//reg the hsel
reg [4:0] hsel_reg;

always@(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn) hsel_reg <= 5'b00000;
    else if(HREADY) hsel_reg <= {P0_HSEL,P1_HSEL,P2_HSEL,P3_HSEL,P4_HSEL};
end

//hready mux
reg hready_mux;

always@(*) begin
    case(hsel_reg)
    5'b00001 : begin hready_mux = P4_HREADYOUT;end
    5'b00010 : begin hready_mux = P3_HREADYOUT;end
    5'b00100 : begin hready_mux = P2_HREADYOUT;end
    5'b01000 : begin hready_mux = P1_HREADYOUT;end
    5'b10000 : begin hready_mux = P0_HREADYOUT;end
    default : begin hready_mux = 1'b1;end
    endcase
end

assign HREADYOUT = hready_mux;

//hresp mux
reg hresp_mux;

always@(*) begin
    case(hsel_reg)
    5'b00001 : begin hresp_mux = P4_HRESP;end
    5'b00010 : begin hresp_mux = P3_HRESP;end
    5'b00100 : begin hresp_mux = P2_HRESP;end
    5'b01000 : begin hresp_mux = P1_HRESP;end
    5'b10000 : begin hresp_mux = P0_HRESP;end
    default : begin hresp_mux = 1'b0;end
    endcase
end

assign HRESP = hresp_mux;

//hrdata mux
reg [31:0] hrdata_mux;

always@(*) begin
    case(hsel_reg)
    5'b00001 : begin hrdata_mux = P4_HRDATA;end
    5'b00010 : begin hrdata_mux = P3_HRDATA;end
    5'b00100 : begin hrdata_mux = P2_HRDATA;end
    5'b01000 : begin hrdata_mux = P1_HRDATA;end
    5'b10000 : begin hrdata_mux = P0_HRDATA;end
    default : begin hrdata_mux = 32'b0;end
    endcase
end

assign HRDATA = hrdata_mux;

endmodule
module AHBlite_Block_RAM #(
    parameter                       ADDR_WIDTH = 14)(
    input  wire                     HCLK,    
    input  wire                     HRESETn, 
    input  wire                     HSEL,    
    input  wire   [31:0]            HADDR,   
    input  wire   [1:0]             HTRANS,  
    input  wire   [2:0]             HSIZE,   
    input  wire   [3:0]             HPROT,   
    input  wire                     HWRITE,  
    input  wire   [31:0]            HWDATA,   
    input wire                      HREADY, 
    output wire                     HREADYOUT, 
    output wire   [31:0]            HRDATA,  
    output wire   [1:0]             HRESP,
    output wire   [ADDR_WIDTH-1:0]  BRAM_RDADDR,
    output wire   [ADDR_WIDTH-1:0]  BRAM_WRADDR,
    input  wire   [31:0]            BRAM_RDATA,
    output wire   [31:0]            BRAM_WDATA,
    output wire   [3:0]             BRAM_WRITE
);

assign HRESP = 2'b0;
assign HRDATA = BRAM_RDATA;

wire trans_en;
assign trans_en = HSEL & HTRANS[1];

wire write_en;
assign write_en = trans_en & HWRITE;

wire read_en;
assign read_en = trans_en & (~HWRITE);

reg [3:0] size_dec;
always@(*) begin
  case({HADDR[1:0],HSIZE[1:0]})
    4'h0 : size_dec = 4'h1;
    4'h1 : size_dec = 4'h3;
    4'h2 : size_dec = 4'hf;
    4'h4 : size_dec = 4'h2;
    4'h8 : size_dec = 4'h4;
    4'h9 : size_dec = 4'hc;
    4'hc : size_dec = 4'h8;
    default : size_dec = 4'h0;
  endcase
end

reg [3:0] size_reg;
always@(posedge HCLK or negedge HRESETn) begin
  if(~HRESETn) size_reg <= 0;
  else if(write_en & HREADY) size_reg <= size_dec;
end


reg [ADDR_WIDTH-1:0] addr_reg;
always@(posedge HCLK or negedge HRESETn) begin
  if(~HRESETn) addr_reg <= 0;
  else if(trans_en & HREADY) addr_reg <= HADDR[(ADDR_WIDTH+1):2];
end


reg wr_en_reg;

always@(posedge HCLK or negedge HRESETn) begin
  if(~HRESETn) wr_en_reg <= 1'b0;
  else if(HREADY) wr_en_reg <= write_en;
  else wr_en_reg <= 1'b0;
end

assign BRAM_RDADDR = HADDR[(ADDR_WIDTH+1):2];
assign BRAM_WRADDR  = addr_reg;
assign HREADYOUT = 1'b1;
assign BRAM_WRITE = wr_en_reg ? size_reg : 4'h0;
assign BRAM_WDATA = HWDATA; 

endmodule
module AHBlite_Decoder
#(
    /*RAMCODE enable parameter*/
    parameter Port0_en = 1,
    /************************/

    /*RAMDATA enable parameter*/
    parameter Port1_en = 0,
    /************************/

    /*WaterLight enable parameter*/
    parameter Port2_en = 0,
    /************************/

    /*UART enable parameter*/
    parameter Port3_en=0,
    /************************/

    /*GPIO enable parameter*/
    parameter Port4_en=0
    /************************/

    
)(
    input [31:0] HADDR,

    /*RAMCODE OUTPUT SELECTION SIGNAL*/
    output wire P0_HSEL,

    /*WaterLight OUTPUT SELECTION SIGNAL*/
    output wire P1_HSEL,

    /*RAMDATA OUTPUT SELECTION SIGNAL*/
    output wire P2_HSEL,

    /*UART OUTPUT SELECTION SIGNAL*/
    output wire P3_HSEL,       

    /*UART OUTPUT SELECTION SIGNAL*/
    output wire P4_HSEL  
);

//RAMCODE-----------------------------------

//0x00000000-0x0000ffff
/*Insert RAMCODE decoder code there*/
assign P0_HSEL = (HADDR[31:16] == 16'h0000) ? Port0_en : 1'd0;
/***********************************/



//PERIPHRAL-----------------------------

//0X40000000 WaterLight MODE
//0x40000004 WaterLight SPEED
/*Insert WaterLight decoder code there*/
assign P2_HSEL = 1'd0;
/***********************************/

//0X40000010 UART RX DATA
//0X40000014 UART TX STATE
//0X40000018 UART TX DATA
/*Insert UART decoder code there*/
assign P3_HSEL = 1'b0;
/***********************************/

//0x40000028 OUT  ENABLE
//0X40000024 IN DATA
//0X40000020 OUT DATA
/*Insert GPIO decoder code there*/
assign P4_HSEL = 1'd0;
/***********************************/

//RAMDATA-----------------------------
//0X20000000-0X2000FFFF
/*Insert RAMDATA decoder code there*/
assign P1_HSEL = 1'b0;
/***********************************/

endmodule
module AHBlite_GPIO(
    input  wire          HCLK,    
    input  wire          HRESETn, 
    input  wire          HSEL,    
    input  wire   [31:0] HADDR,   
    input  wire    [1:0] HTRANS,  
    input  wire    [2:0] HSIZE,   
    input  wire    [3:0] HPROT,   
    input  wire          HWRITE,  
    input  wire   [31:0] HWDATA,  
    input  wire          HREADY,  
    output wire          HREADYOUT, 
    output wire   [31:0] HRDATA,  
    output wire          HRESP,
    output wire         outEn,
    output wire   [7:0] oData,
    input  wire   [7:0] iData  
);

assign HRESP = 1'b0;
assign HREADYOUT = 1'b1;

wire write_en;
assign write_en = HSEL & HTRANS[1] & HWRITE & HREADY;

wire read_en;
assign read_en=HSEL&HTRANS[1]&(~HWRITE)&HREADY;

reg [3:0] addr_reg;
always@(posedge HCLK or negedge HRESETn) begin
  if(~HRESETn) addr_reg <= 4'h0;
  else if(read_en || write_en) addr_reg <= HADDR[3:0];
end

reg rd_en_reg;
always@(posedge HCLK or negedge HRESETn) begin
  if(~HRESETn) rd_en_reg <= 1'b0;
  else if(read_en) rd_en_reg <= 1'b1;
  else rd_en_reg <= 1'b0;
end

reg wr_en_reg;
always@(posedge HCLK or negedge HRESETn) begin
  if(~HRESETn) wr_en_reg <= 1'b0;
  else if(write_en) wr_en_reg <= 1'b1;
  else  wr_en_reg <= 1'b0;
end


// always@(*) begin
//   if(rd_en_reg) begin
//     if(addr_reg == 4'h4) HRDATA <= {24'b0,iData};
//     else HRDATA <= 32'd0;
//     end 
//     else HRDATA <= 32'd0;
// end]

assign HRDATA = (rd_en_reg  & (addr_reg == 4'h4)) ? {24'd0,iData} : 32'd0;

reg [7:0] oData_reg;
reg outEn_reg;
always@(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn) begin
        oData_reg <= 8'd0;
        outEn_reg <= 1'd0;
    end
    else if(wr_en_reg & addr_reg == 4'h0)  oData_reg <= HWDATA[7:0];
    else if(wr_en_reg & addr_reg == 4'h8)  outEn_reg <= HWDATA[0];
  end
    

assign oData = oData_reg;
assign outEn = outEn_reg;

endmodule
module CortexM0_SoC_vlg_tst();

reg clk;
reg RSTn;
reg TXD;
                        
CortexM0_SoC i1 (
    .clk(clk),
    .RSTn(RSTn)
);

initial begin                                                  
    clk = 0;
    RSTn=0;
    #100
    RSTn=1;

end  
    
always begin                                                  
    #10 clk = ~clk;
end       

endmodule
module WaterLight(
    input [7:0] WaterLight_mode,
    input [31:0] WaterLight_speed,
    input clk,
    input RSTn,
    output reg [7:0] LED,
    output wire LEDclk
);

//------------------------------------------------------
//  PWM
//------------------------------------------------------

reg [31:0] pwm_cnt;

always@(posedge clk or negedge RSTn) begin
    if(~RSTn) pwm_cnt <= 32'b0;
    else if(pwm_cnt == WaterLight_speed) pwm_cnt <= 32'b0;
    else pwm_cnt <= pwm_cnt + 1'b1;
end

reg light_clk;

always@(posedge clk or negedge RSTn) begin
    if(~RSTn) light_clk <= 1'b0;
    else if(pwm_cnt == WaterLight_speed) light_clk <= ~light_clk;
end

assign LEDclk = light_clk;

//------------------------------------------------------
//  LEFT MODE
//------------------------------------------------------

reg [7:0] mode1;

always@(posedge light_clk or negedge RSTn) begin
    if(~RSTn) mode1 <= 8'h01;
    else begin
        case(mode1)
        8'h01 : mode1 <= 8'h02;
        8'h02 : mode1 <= 8'h04;
        8'h04 : mode1 <= 8'h08;
        8'h08 : mode1 <= 8'h10;
        8'h10 : mode1 <= 8'h20;
        8'h20 : mode1 <= 8'h40;
        8'h40 : mode1 <= 8'h80;
        default : mode1 <= 8'h01;
        endcase
    end
end

//------------------------------------------------------
//  RIGHT MODE
//------------------------------------------------------

reg [7:0] mode2;

always@(posedge light_clk or negedge RSTn) begin
    if(~RSTn) mode2 <= 8'h80;
    else begin
        case(mode2)
        8'h80 : mode2 <= 8'h40;
        8'h40 : mode2 <= 8'h20;
        8'h20 : mode2 <= 8'h10;
        8'h10 : mode2 <= 8'h08;
        8'h08 : mode2 <= 8'h04;
        8'h04 : mode2 <= 8'h02;
        8'h02 : mode2 <= 8'h01;
        default : mode2 <= 8'h80;
        endcase
    end
end

//------------------------------------------------------
//  FLASH MODE
//------------------------------------------------------

wire [7:0] mode3;

assign mode3 = (light_clk == 1'b0) ? 8'h00 : 8'hff;

//------------------------------------------------------
//  OUTPUT MUX
//------------------------------------------------------


endmodule
module AHBlite_WaterLight(
    input  wire          HCLK,    
    input  wire          HRESETn, 
    input  wire          HSEL,    
    input  wire   [31:0] HADDR,   
    input  wire    [1:0] HTRANS,  
    input  wire    [2:0] HSIZE,   
    input  wire    [3:0] HPROT,   
    input  wire          HWRITE,  
    input  wire   [31:0] HWDATA,  
    input  wire          HREADY,  
    output wire          HREADYOUT, 
    output wire   [31:0] HRDATA,  
    output wire          HRESP,
    output reg     [7:0] WaterLight_mode,
    output reg     [31:0] WaterLight_speed  
);

assign HRESP = 1'b0;
assign HREADYOUT = 1'b1;

wire write_en;
assign write_en = HSEL & HTRANS[1] & HWRITE & HREADY;

reg addr_reg;
always@(posedge HCLK or negedge HRESETn) begin
  if(~HRESETn) addr_reg <= 1'b0;
  else if(HSEL & HREADY & HTRANS[1]) addr_reg <= HADDR[2];
end

reg wr_en_reg;
always@(posedge HCLK or negedge HRESETn) begin
  if(~HRESETn) wr_en_reg <= 1'b0;
  else if(write_en) wr_en_reg <= 1'b1;
  else wr_en_reg <= 1'b0;
end

always@(posedge HCLK) begin
    if(~HRESETn) begin
        WaterLight_mode <= 8'h00;
        WaterLight_speed <= 32'h00000000;
    end else if(wr_en_reg && HREADY) begin
        if(~addr_reg)
            WaterLight_mode <= HWDATA[7:0];
        else    
            WaterLight_speed <= HWDATA;
    end
end

assign HRDATA = (addr_reg) ? WaterLight_speed : {24'b0,WaterLight_mode};

endmodule
module Block_RAM #(
    parameter ADDR_WIDTH = 14
)   (
    input clka,
    input [ADDR_WIDTH-1:0] addra,
    input [ADDR_WIDTH-1:0] addrb,
    input [31:0] dina,
    input [3:0] wea,
    output reg [31:0] doutb
);

(* ram_style="block" *)reg [31:0] mem [(2**ADDR_WIDTH-1):0];

initial begin
    $readmemh("C:/Users/range/Desktop/CortexM0_SoC_cd/Task2/keil/code.hex",mem);
end

always@(posedge clka) begin
    if(wea[0]) mem[addra][7:0] <= dina[7:0];
end
always@(posedge clka) begin
    if(wea[1]) mem[addra][15:8] <= dina[15:8];
end
always@(posedge clka) begin
    if(wea[2]) mem[addra][23:16] <= dina[23:16];
end
always@(posedge clka) begin
    if(wea[3]) mem[addra][31:24] <= dina[31:24];
end

always@(posedge clka) begin
    doutb <= mem[addrb];
end

endmodule
module AHBlite_SlaveMUX (

    input HCLK,
    input HRESETn,
    input HREADY,

    //port 0
    input P0_HSEL,
    input P0_HREADYOUT,
    input P0_HRESP,
    input [31:0] P0_HRDATA,

    //port 1
    input P1_HSEL,
    input P1_HREADYOUT,
    input P1_HRESP,
    input [31:0] P1_HRDATA,

    //port 2
    input P2_HSEL,
    input P2_HREADYOUT,
    input P2_HRESP,
    input [31:0] P2_HRDATA,

    //port 3
    input P3_HSEL,
    input P3_HREADYOUT,
    input P3_HRESP,
    input [31:0] P3_HRDATA,

    //output
    output wire HREADYOUT,
    output wire HRESP,
    output wire [31:0] HRDATA
);

//reg the hsel
reg [3:0] hsel_reg;

always@(posedge HCLK or negedge HRESETn) begin
    if(~HRESETn) hsel_reg <= 4'b0000;
    else if(HREADY) hsel_reg <= {P0_HSEL,P1_HSEL,P2_HSEL,P3_HSEL};
end

//hready mux
reg hready_mux;

always@(*) begin
    case(hsel_reg)
    4'b0001 : begin hready_mux = P3_HREADYOUT;end
    4'b0010 : begin hready_mux = P2_HREADYOUT;end
    4'b0100 : begin hready_mux = P1_HREADYOUT;end
    4'b1000 : begin hready_mux = P0_HREADYOUT;end
    default : begin hready_mux = 1'b1;end
    endcase
end

assign HREADYOUT = hready_mux;

//hresp mux
reg hresp_mux;

always@(*) begin
    case(hsel_reg)
    4'b0001 : begin hresp_mux = P3_HRESP;end
    4'b0010 : begin hresp_mux = P2_HRESP;end
    4'b0100 : begin hresp_mux = P1_HRESP;end
    4'b1000 : begin hresp_mux = P0_HRESP;end
    default : begin hresp_mux = 1'b0;end
    endcase
end

assign HRESP = hresp_mux;

//hrdata mux
reg [31:0] hrdata_mux;

always@(*) begin
    case(hsel_reg)
    4'b0001 : begin hrdata_mux = P3_HRDATA;end
    4'b0010 : begin hrdata_mux = P2_HRDATA;end
    4'b0100 : begin hrdata_mux = P1_HRDATA;end
    4'b1000 : begin hrdata_mux = P0_HRDATA;end
    default : begin hrdata_mux = 32'b0;end
    endcase
end

assign HRDATA = hrdata_mux;

endmodule
module AHBlite_Decoder
#(
    /*RAMCODE enable parameter*/
    parameter Port0_en = 1,
    /************************/

    /*WaterLight enable parameter*/
    parameter Port1_en = 0,
    /************************/

    /*RAMDATA enable parameter*/
    parameter Port2_en = 0,
    /************************/

    /*UART enable parameter*/
    parameter Port3_en=0
    /************************/
)(
    input [31:0] HADDR,

    /*RAMCODE OUTPUT SELECTION SIGNAL*/
    output wire P0_HSEL,

    /*WaterLight OUTPUT SELECTION SIGNAL*/
    output wire P1_HSEL,

    /*RAMDATA OUTPUT SELECTION SIGNAL*/
    output wire P2_HSEL,

    /*UART OUTPUT SELECTION SIGNAL*/
    output wire P3_HSEL       
);

//RAMCODE-----------------------------------

//0x00000000-0x0000ffff
/*Insert RAMCODE decoder code there*/
assign P0_HSEL = (HADDR[31:16] == 16'h0000) ? Port0_en : 1'b0; 
/***********************************/



//PERIPHRAL-----------------------------

//0X40000000 WaterLight MODE
//0x40000004 WaterLight SPEED
/*Insert WaterLight decoder code there*/
assign P2_HSEL = 1'b0; 
/***********************************/

//0X40000010 UART RX DATA
//0X40000014 UART TX STATE
//0X40000018 UART TX DATA
/*Insert UART decoder code there*/
assign P3_HSEL = 1'b0;
/***********************************/

//RAMDATA-----------------------------
//0X20000000-0X2000FFFF
/*Insert RAMDATA decoder code there*/
assign P1_HSEL = 1'b0; 
/***********************************/

endmodule
module CortexM0_SoC_vlg_tst();

reg clk;
reg RSTn;
reg[3:0] col;
                        
CortexM0_SoC i1 (
    .clk(clk),
    .RSTn(RSTn),
    .col(col)
);

initial begin                                                  
    clk = 0;
    RSTn=0;
    #100
    RSTn=1;
    #100
    col = 4'b0001;
    #100000
    col = 4'b0000;

end  
    
always begin                                                  
    #5 clk = ~clk;
end       

endmodule
module WaterLight(
    input [7:0] WaterLight_mode,
    input [31:0] WaterLight_speed,
    input clk,
    input RSTn,
    output reg [7:0] LED,
    output wire LEDclk
);

//------------------------------------------------------
//  PWM
//------------------------------------------------------

reg [31:0] pwm_cnt;

always@(posedge clk or negedge RSTn) begin
    if(~RSTn) pwm_cnt <= 32'b0;
    else if(pwm_cnt == WaterLight_speed) pwm_cnt <= 32'b0;
    else pwm_cnt <= pwm_cnt + 1'b1;
end

reg light_clk;

always@(posedge clk or negedge RSTn) begin
    if(~RSTn) light_clk <= 1'b0;
    else if(pwm_cnt == WaterLight_speed) light_clk <= ~light_clk;
end

assign LEDclk = light_clk;

//------------------------------------------------------
//  LEFT MODE
//------------------------------------------------------

reg [7:0] mode1;

always@(posedge light_clk or negedge RSTn) begin
    if(~RSTn) mode1 <= 8'h01;
    else begin
        case(mode1)
        8'h01 : mode1 <= 8'h02;
        8'h02 : mode1 <= 8'h04;
        8'h04 : mode1 <= 8'h08;
        8'h08 : mode1 <= 8'h10;
        8'h10 : mode1 <= 8'h20;
        8'h20 : mode1 <= 8'h40;
        8'h40 : mode1 <= 8'h80;
        default : mode1 <= 8'h01;
        endcase
    end
end

//------------------------------------------------------
//  RIGHT MODE
//------------------------------------------------------

reg [7:0] mode2;

always@(posedge light_clk or negedge RSTn) begin
    if(~RSTn) mode2 <= 8'h80;
    else begin
        case(mode2)
        8'h80 : mode2 <= 8'h40;
        8'h40 : mode2 <= 8'h20;
        8'h20 : mode2 <= 8'h10;
        8'h10 : mode2 <= 8'h08;
        8'h08 : mode2 <= 8'h04;
        8'h04 : mode2 <= 8'h02;
        8'h02 : mode2 <= 8'h01;
        default : mode2 <= 8'h80;
        endcase
    end
end

//------------------------------------------------------
//  FLASH MODE
//------------------------------------------------------

wire [7:0] mode3;

assign mode3 = (light_clk == 1'b0) ? 8'h00 : 8'hff;

//------------------------------------------------------
//  OUTPUT MUX
//------------------------------------------------------

always@(*) begin
    case(WaterLight_mode)
    8'h01 : begin LED = mode1;end  
    8'h02 : begin LED = mode2;end
    8'h03 : begin LED = mode3;end
    default : begin LED = 8'h00;end
    endcase
end

endmodule
module AHBlite_WaterLight(
    input  wire          HCLK,    
    input  wire          HRESETn, 
    input  wire          HSEL,    
    input  wire   [31:0] HADDR,   
    input  wire    [1:0] HTRANS,  
    input  wire    [2:0] HSIZE,   
    input  wire    [3:0] HPROT,   
    input  wire          HWRITE,  
    input  wire   [31:0] HWDATA,  
    input  wire          HREADY,  
    output wire          HREADYOUT, 
    output wire   [31:0] HRDATA,  
    output wire          HRESP,
    output reg     [7:0] WaterLight_mode,
    output reg     [31:0] WaterLight_speed  
);

assign HRESP = 1'b0;
assign HREADYOUT = 1'b1;

wire write_en;
assign write_en = HSEL & HTRANS[1] & HWRITE & HREADY;

reg addr_reg;
always@(posedge HCLK or negedge HRESETn) begin
  if(~HRESETn) addr_reg <= 1'b0;
  else if(write_en) addr_reg <= HADDR[2];
end

reg wr_en_reg;
always@(posedge HCLK or negedge HRESETn) begin
  if(~HRESETn) wr_en_reg <= 1'b0;
  else if(write_en) wr_en_reg <= 1'b1;
  else wr_en_reg <= 1'b0;
end

always@(posedge HCLK) begin
    if(~HRESETn) begin
        WaterLight_mode <= 8'h00;
        WaterLight_speed <= 32'h00000000;
    end else if(wr_en_reg && HREADY) begin
        if(~addr_reg)
            WaterLight_mode <= HWDATA[7:0];
        else    
            WaterLight_speed <= HWDATA;
    end
end

assign HRDATA = (addr_reg) ? WaterLight_speed : {24'b0,WaterLight_mode};

endmodule
module Block_RAM #(
    parameter ADDR_WIDTH = 14
)   (
    input clka,
    input [ADDR_WIDTH-1:0] addra,
    input [ADDR_WIDTH-1:0] addrb,
    input [31:0] dina,
    input [3:0] wea,
    output reg [31:0] doutb
);

(* ram_style="block" *)reg [31:0] mem [(2**ADDR_WIDTH-1):0];

initial begin
    $readmemh("G:/workspace-windows/M0_task/Task3_key/keil/code.hex",mem);
end

always@(posedge clka) begin
    if(wea[0]) mem[addra][7:0] <= dina[7:0];
end
always@(posedge clka) begin
    if(wea[1]) mem[addra][15:8] <= dina[15:8];
end
always@(posedge clka) begin
    if(wea[2]) mem[addra][23:16] <= dina[23:16];
end
always@(posedge clka) begin
    if(wea[3]) mem[addra][31:24] <= dina[31:24];
end

always@(posedge clka) begin
    doutb <= mem[addrb];
end

endmodule
module AHBlite_Decoder
#(
    /*RAMCODE enable parameter*/
    parameter Port0_en = 1,
    /************************/

    /*RAMDATA  enable parameter*/
    parameter Port1_en = 1,
    /************************/

    /*WaterLight enable parameter*/
    parameter Port2_en = 1,
    /************************/

    /*UART enable parameter*/
    parameter Port3_en=0,
    /************************/

    /*GPIO enable parameter*/
    parameter Port4_en=0
    /************************/

    
)(
    input [31:0] HADDR,

    /*RAMCODE OUTPUT SELECTION SIGNAL*/
    output wire P0_HSEL,

    /*WaterLight OUTPUT SELECTION SIGNAL*/
    output wire P1_HSEL,

    /*RAMDATA OUTPUT SELECTION SIGNAL*/
    output wire P2_HSEL,

    /*UART OUTPUT SELECTION SIGNAL*/
    output wire P3_HSEL,       

    /*UART OUTPUT SELECTION SIGNAL*/
    output wire P4_HSEL  
);

//RAMCODE-----------------------------------

//0x00000000-0x0000ffff
/*Insert RAMCODE decoder code there*/
assign P0_HSEL = (HADDR[31:16] == 16'h0000) ? Port0_en : 1'd0;
/***********************************/



//PERIPHRAL-----------------------------

//0X40000000 WaterLight MODE
//0x40000004 WaterLight SPEED
/*Insert WaterLight decoder code there*/
assign P2_HSEL = (HADDR[31:4] == 28'h4000000) ? Port2_en : 1'd0;
/***********************************/

//0X40000010 UART RX DATA
//0X40000014 UART TX STATE
//0X40000018 UART TX DATA
/*Insert UART decoder code there*/
assign P3_HSEL = 1'b0;
/***********************************/

//0x40000028 OUT  ENABLE
//0X40000024 IN DATA
//0X40000020 OUT DATA
/*Insert GPIO decoder code there*/
assign P4_HSEL =  1'd0;
/***********************************/

//RAMDATA-----------------------------
//0X20000000-0X2000FFFF
/*Insert RAMDATA decoder code there*/
assign P1_HSEL = (HADDR[31:16] == 16'h2000) ? Port1_en : 1'b0;
/***********************************/

endmodule
module UART_RX(
    input clk,
    input clk_uart,
    input RSTn,
    input RXD,
    output reg [7:0] data,
    output wire interrupt,
    output wire bps_en
);

//shift register
reg [7:0] shift_reg;
always@(posedge clk) begin
    if(~RSTn) shift_reg <= 8'hff;
    else shift_reg <= {RXD,shift_reg[7:1]};
end

wire re_start;
assign re_start = (shift_reg == 8'h0f) ? 1'b1 : 1'b0;

// recive counter
reg counter_en;
reg [3:0] counter;

always@(posedge clk or negedge RSTn) begin
    if(~RSTn) counter_en <= 1'b0;
    else if(re_start&&(~counter_en)) counter_en <= 1'b1;
    else if(counter == 4'h9) counter_en <= 1'b0;
end

always@(posedge clk or negedge RSTn) begin
    if(~RSTn) counter <= 4'h0;
    else if(counter_en) begin 
        if(clk_uart) counter <= counter + 1'b1;
        else if(counter == 4'h9) counter <= 4'h0;
    end
end

assign bps_en = counter_en;

// RXD re
always@(posedge clk or negedge RSTn) begin
    if(~RSTn) data <= 8'h00;
    else if(counter_en) begin
        if(clk_uart && (counter <= 4'h8)) data[counter-1] <= RXD;
    end
end

//interrupt
assign interrupt = (counter == 4'h9) ? 1'b1 : 1'b0;


endmodule
module clkuart_pwm 
	#( parameter BPS_PARA = 434 )
	(
	input bps_en,
	input clk,
	input RSTn,		
	output reg clk_uart		
);	
 
reg	[12:0] cnt = 0;

always @ (posedge clk or negedge RSTn) begin
	if(~RSTn) cnt <= 13'b0;
	else if((cnt >= BPS_PARA-1)||(!bps_en)) cnt <= 13'b0;		
	else cnt <= cnt + 1'b1;
end

always @ (posedge clk or negedge RSTn) begin
	if(~RSTn) clk_uart <= 1'b0;
	else if(cnt == (BPS_PARA>>1)) clk_uart <= 1'b1;
	else clk_uart <= 1'b0;	
end
 
endmodule
module Block_RAM #(
    parameter ADDR_WIDTH = 14
)   (
    input clka,
    input [ADDR_WIDTH-1:0] addra,
    input [ADDR_WIDTH-1:0] addrb,
    input [31:0] dina,
    input [3:0] wea,
    output reg [31:0] doutb
);

(* ram_style="block" *)reg [31:0] mem [(2**ADDR_WIDTH-1):0];

initial begin
    $readmemh("C:/Users/tianj/Desktop/CortexM0_SoC_Task/Task3/keil/code.hex",mem);
end

always@(posedge clka) begin
    if(wea[0]) mem[addra][7:0] <= dina[7:0];
end
always@(posedge clka) begin
    if(wea[1]) mem[addra][15:8] <= dina[15:8];
end
always@(posedge clka) begin
    if(wea[2]) mem[addra][23:16] <= dina[23:16];
end
always@(posedge clka) begin
    if(wea[3]) mem[addra][31:24] <= dina[31:24];
end

always@(posedge clka) begin
    doutb <= mem[addrb];
end

endmodule
module AHBlite_UART(
    input  wire          HCLK,    
    input  wire          HRESETn, 
    input  wire          HSEL,    
    input  wire   [31:0] HADDR,   
    input  wire    [1:0] HTRANS,  
    input  wire    [2:0] HSIZE,   
    input  wire    [3:0] HPROT,   
    input  wire          HWRITE,  
    input  wire   [31:0] HWDATA,  
    input  wire          HREADY,  
    output wire          HREADYOUT, 
    output reg    [31:0] HRDATA,  
    output wire          HRESP,
    input  wire    [7:0] UART_RX,
    input  wire          state,
    output wire          tx_en,
    output wire    [7:0] UART_TX
);

assign HRESP = 1'b0;
assign HREADYOUT = 1'b1;

wire read_en;
assign read_en=HSEL&HTRANS[1]&(~HWRITE)&HREADY;

wire write_en;
assign write_en=HSEL&HTRANS[1]&(HWRITE)&HREADY;

reg [3:0] addr_reg;
always@(posedge HCLK or negedge HRESETn) begin
  if(~HRESETn) addr_reg <= 4'h0;
  else if(read_en || write_en) addr_reg <= HADDR[3:0];
end

reg rd_en_reg;
always@(posedge HCLK or negedge HRESETn) begin
  if(~HRESETn) rd_en_reg <= 1'b0;
  else if(read_en) rd_en_reg <= 1'b1;
  else rd_en_reg <= 1'b0;
end

reg wr_en_reg;
always@(posedge HCLK or negedge HRESETn) begin
  if(~HRESETn) wr_en_reg <= 1'b0;
  else if(write_en) wr_en_reg <= 1'b1;
  else  wr_en_reg <= 1'b0;
end

always@(*) begin
  if(rd_en_reg) begin
    if(addr_reg == 4'h0) HRDATA <= {24'b0,UART_RX};
    else if(addr_reg == 4'h4) HRDATA <= {31'b0,state};
    else HRDATA <= 32'b0;
  end else
    HRDATA <= 32'b0;
end

assign tx_en = wr_en_reg ? 1'b1 : 1'b0;
assign UART_TX = wr_en_reg ? HWDATA[7:0] : 8'b0;


endmodule