/**************************************************************************** MR16+GPIO+TImer ペリフェラルモジュール Version 2007.4.4  拡張されるモジュール 16bit x 4 GP-IN PORT 16bit x 8 Address decode for Direct IN PORT 16bit x 12 GP-OUT PORT 16bit x 1 Timer with auto vecter interrupt x 4 external auto vected IRQ/ACK メモリマップ +-------------+------------------------+ | address | device | +-------------+------------------------+ |00000h-0EFFFh| external bus | +-------------+------------------------+ |0F000h-0F001h| GPOUT O_P0 / GPIN I_P0| |0F002h-0F003h| GPOUT O_P1 / GPIN I_P1| |0F004h-0F005h| GPOUT O_P2 / GPIN I_P2| |0F006h-0F007h| GPOUT O_P3 / GPIN I_P3| |0F008h-0F009h| GPOUT O_P4 / | |0F00Ah-0F00Bh| GPOUT O_P5 / | |0F00Ch-0F00Dh| GPOUT O_P6 / | |0F00Eh-0F00Fh| GPOUT O_P7 / | |0F010h-0F011h| GPOUT O_P8 / | |0F012h-0F013h| GPOUT O_P9 / | |0F014h-0F015h| GPOUT O_PA / | |0F016h-0F017h| GPOUT O_PB / | +-------------+------------------------+ |0F018h-0F01Fh| 16bit Timer | +-------------+------------------------+ |0F020h-0FFFFh| do not access | +-------------+------------------------+ 割り込みベクター、ソースと優先順位 +---------+-----------------+------------+ | vector | source | priority | +---------+-----------------+------------+ |0000-0001| reset | --- | |0002-0003| 16bit Timer | 1(highest) | |0004-0005| IRQ0 lowst piro | 2 | |0006-0007| IRQ1 | 3 | |0008-0009| IRQ2 | 4 | |000A-000B| IRQ3 higest piro| 5(lowst) | +---------+-----------------+------------+ ****************************************************************************/ // enable Timer Module Option `define TIMER_MODULE module mr16_mpu ( I_RESET,I_CLK,I_CEN, // Address Bus O_A,O_D,I_D,O_WR,O_ECS, // Timer I_TMRG, //GPIO periferal O_P0,O_P1,O_P2,O_P3, O_P4,O_P5,O_P6,O_P7, O_P8,O_P9,O_PA,O_PB, I_P0,I_P1,I_P2,I_P3, O_I4,O_I5,O_I6,O_I7, O_I8,O_I9,O_IA,O_IB, //Interrupt source I_INT,O_ACK ); input I_RESET; input I_CLK; input I_CEN; // Address Bus output [15:0] O_A; output [15:0] O_D; input [15:0] I_D; output O_ECS; output O_WR; // Timer input I_TMRG; // GP-OUT output [15:0] O_P0,O_P1,O_P2,O_P3; output [15:0] O_P4,O_P5,O_P6,O_P7; output [15:0] O_P8,O_P9,O_PA,O_PB; // GP-IN input [15:0] I_P0,I_P1,I_P2,I_P3; // DATA BUS IN output O_I4,O_I5,O_I6,O_I7; output O_I8,O_I9,O_IA,O_IB; input [3:0] I_INT; output [3:0] O_ACK; //*************************************************************************** // core I/F //*************************************************************************** reg [3:1] vector; wire iack; wire [15:0] d_addr, d_in , d_out; wire [1:0] d_wr; wire irq = vector!=0; mr16core cpu( .Reset(I_RESET), .Clock(I_CLK), .ClockEnable(I_CEN), .ResetVector(15'h0000), .IntReq(irq),.IntAck(iack),.IntVector({12'h0000,vector[3:1]}), .Address(d_addr),.WriteData(d_out),.ReadData(d_in),.WriteEnable(d_wr) ); //*************************************************************************** // address decoder //*************************************************************************** wire mem16_cs = 1'b1;// I_CEN; wire io_cs = mem16_cs & (d_addr[15:12]==4'b1111); // 0f000h-0ffffh wire mem_cs = mem16_cs & ~io_cs; // 00000h-0efffh wire tmr_cs = io_cs & d_addr[4] & d_addr[3]; // 0f01ch-0f01fh wire wr16 = d_wr[0]; //*************************************************************************** // memory I/O //*************************************************************************** assign O_A = d_addr; assign O_D = d_out; assign O_WR = d_wr[0]; assign O_ECS = mem_cs; //*************************************************************************** // 16bit Timer Unit //*************************************************************************** wire timer_ack = (vector == 3'b001) & iack; wire timer_irq; `ifdef TIMER_MODULE timer #(16) timer ( .I_RESET(I_RESET), .I_CLK(I_CLK), .I_GATE(I_TMRG), .I_A(d_addr[1]), .I_CS(tmr_cs), .I_WR(wr16), .I_D(d_out), .O_D(), // no readback .O_INT(timer_irq), .I_IACK(timer_ack) ); `else assign timer_irq = 1'b0; `endif //*************************************************************************** // GPIO //*************************************************************************** reg [15:0] O_P0,O_P1,O_P2,O_P3; reg [15:0] O_P4,O_P5,O_P6,O_P7; reg [15:0] O_P8,O_P9,O_PA,O_PB; reg O_I4,O_I5,O_I6,O_I7; reg O_I8,O_I9,O_IA,O_IB; reg [15:0] gpio_in_mux; always @(posedge I_CLK) begin if(I_RESET) begin gpio_in_mux <= 16'h0000; O_P0 <= 16'h0000; O_P1 <= 16'h0000; O_P2 <= 16'h0000; O_P3 <= 16'h0000; O_P4 <= 16'h0000; O_P5 <= 16'h0000; O_P6 <= 16'h0000; O_P7 <= 16'h0000; O_P8 <= 16'h0000; O_P9 <= 16'h0000; O_PA <= 16'h0000; O_PB <= 16'h0000; O_I4 <= 1'b0; O_I5 <= 1'b0; O_I6 <= 1'b0; O_I7 <= 1'b0; O_I8 <= 1'b0; O_I9 <= 1'b0; O_IA <= 1'b0; O_IB <= 1'b0; end else begin // IN ack signal O_I4 <= io_cs & ~wr16 & (d_addr[4:1]==4'b0100); O_I5 <= io_cs & ~wr16 & (d_addr[4:1]==4'b0101); O_I6 <= io_cs & ~wr16 & (d_addr[4:1]==4'b0110); O_I7 <= io_cs & ~wr16 & (d_addr[4:1]==4'b0111); O_I8 <= io_cs & ~wr16 & (d_addr[4:1]==4'b1000); O_I9 <= io_cs & ~wr16 & (d_addr[4:1]==4'b1001); O_IA <= io_cs & ~wr16 & (d_addr[4:1]==4'b1010); O_IB <= io_cs & ~wr16 & (d_addr[4:1]==4'b1011); // OUT port if(io_cs & wr16) begin case(d_addr[4:1]) 4'b0000: O_P0 <= d_out; 4'b0001: O_P1 <= d_out; 4'b0010: O_P2 <= d_out; 4'b0011: O_P3 <= d_out; 4'b0100: O_P4 <= d_out; 4'b0101: O_P5 <= d_out; 4'b0110: O_P6 <= d_out; 4'b0111: O_P7 <= d_out; 4'b1000: O_P8 <= d_out; 4'b1001: O_P9 <= d_out; 4'b1010: O_PA <= d_out; 4'b1011: O_PB <= d_out; endcase end // inport mux gpio_in_mux <= d_addr[2:1]==2'b11 ? I_P3 : d_addr[2:1]==2'b10 ? I_P2 : d_addr[2:1]==2'b01 ? I_P1 : I_P0; end end //*************************************************************************** // interrupt //*************************************************************************** `define VECTOR_TIMER (16'h0002) `define VECTOR_INT0 (16'h0004) `define VECTOR_INT1 (16'h0006) `define VECTOR_INT2 (16'h0008) `define VECTOR_INT3 (16'h000A) always @(posedge I_CLK) begin if(I_CEN) begin vector <= 3'b000; // lowest if(I_INT[3]) vector[3:1] <= `VECTOR_INT3/2; if(I_INT[2]) vector[3:1] <= `VECTOR_INT2/2; if(I_INT[1]) vector[3:1] <= `VECTOR_INT1/2; if(I_INT[0]) vector[3:1] <= `VECTOR_INT0/2; if(timer_irq) vector[3:1] <= `VECTOR_TIMER/2; // highest end end assign O_ACK[0] = (vector[3:1] == `VECTOR_INT0/2) & iack; assign O_ACK[1] = (vector[3:1] == `VECTOR_INT1/2) & iack; assign O_ACK[2] = (vector[3:1] == `VECTOR_INT2/2) & iack; assign O_ACK[3] = (vector[3:1] == `VECTOR_INT3/2) & iack; //*************************************************************************** // data input mux //*************************************************************************** reg mem_cs_r; always @(posedge I_CLK) mem_cs_r <= mem_cs; mux_2 #(16) top_din_mux( .I0(gpio_in_mux), // GPIO .I1(I_D), // memory .S(mem_cs_r),.O(d_in)); endmodule //*************************************************************************** // n bit timer module // // +----+-----+------+---+---+---+---+ // |I_A | R/W |b15..4|b3 |b2 |b1 |b0 | // +----+-----+------+---+---+---+---+ // | 0 | WR | timer interval | // | 1 | WR | --- |RST|IEN|RUN|IRQ| // | x | RD | timer counter | // +----+-----+------+---+---+---+---+ // RST: reset timer counter // IEN: interrupt enable // RUN: count enable // IRQ: interruput request (auto clear) // // if timer==0 then timer reload and set IRQ // if I_GATE==1'b1 then timer--; // //*************************************************************************** module timer(I_RESET,I_CLK,I_GATE,I_A,I_CS,I_WR,I_D,O_D,O_INT,I_IACK); parameter TIMER_WIDTH = 16; input I_RESET; input I_CLK; input I_GATE; input I_A; input I_CS; input I_WR; input [TIMER_WIDTH-1:0] I_D; output [TIMER_WIDTH-1:0] O_D; output O_INT; input I_IACK; reg [TIMER_WIDTH-1:0] timer_cnt , timer_int; reg [2:0] timer_ctrl; // bit0=IRQ,1=RUN,2=INT EN,3=reset counter wire [TIMER_WIDTH-1:0] next_timer = timer_cnt-(timer_ctrl[1]&I_GATE); wire timer_overflow = ~timer_cnt[TIMER_WIDTH-1] & next_timer[TIMER_WIDTH-1]; wire timer_ctr_load = (I_CS & I_WR & I_A); wire timer_int_load = (I_CS & I_WR & ~I_A); wire timer_cnt_load = (timer_ctr_load & I_D[3]) | timer_overflow; always @(posedge I_CLK or posedge I_RESET) begin if(I_RESET) begin timer_cnt <= {TIMER_WIDTH{1'b0}}; timer_int <= {TIMER_WIDTH{1'b0}}; timer_ctrl <= 3'b000; end else begin // timer reload / countup timer_cnt <= timer_cnt_load ? timer_int : next_timer; // interval register if(timer_int_load) timer_int <= I_D[TIMER_WIDTH-1:0]; // vector auto clear if(I_IACK) timer_ctrl[0] <= 1'b0; else if(timer_overflow) timer_ctrl[0] <= timer_ctrl[2]; // IRQ EN // ctrl load if(timer_ctr_load) timer_ctrl <= I_D[2:0]; end end // interrupt output assign O_INT = timer_ctrl[0]; assign O_D = 16'h00;//timer_cnt; endmodule