NET "buttons<1>" LOC="E18";
NET "buttons<2>" LOC="D18";
NET "buttons<3>" LOC="B18";
+
+NET "vs" LOC = "u3" |SLEW = "fast";
+NET "hs" LOC = "t4" |SLEW = "fast";
+NET "r<2>" LOC = "r8";
+NET "r<1>" LOC = "t8";
+NET "r<0>" LOC = "r9";
+NET "g<2>" LOC = "p6";
+NET "g<1>" LOC = "p8";
+NET "g<0>" LOC = "n8";
+NET "b<1>" LOC = "u4";
+NET "b<0>" LOC = "u5";
\ No newline at end of file
`define INSN_EI 8'b11111011
`define INSN_INCDEC_HL 8'b0011010x
`define INSN_INCDEC_reg8 8'b00xxx10x
-`define INSN_LDM_A 8'b111xx000 // 1111 for ld A, x; 1110 for ld x, A; bit 1 specifies 16m8 or 8m8
+`define INSN_LD8M_A 8'b111x0000 // 1111 for ld A, x; 1110 for ld x, A; bit 1 specifies 16m8 or 8m8
+`define INSN_LD16M_A 8'b111x1010 // 1111 for ld A, x; 1110 for ld x, A; bit 1 specifies 16m8 or 8m8
`define INSN_cc_NZ 2'b00
`define INSN_cc_Z 2'b01
inout [7:0] data,
input clk, // 8MHz clock
input wr, rd,
- output reg irq = 0);
+ output wire lcdcirq,
+ output wire vblankirq,
+ output wire vgavs, vgahs,
+ output wire [2:0] vgar, vgag, output wire [1:0] vgab);
/***** Internal clock that is stable and does not depend on CPU in single/double clock mode *****/
reg clk4 = 0;
always @(posedge clk)
clk4 = ~clk4;
+ /***** LCD control registers *****/
+ reg [7:0] rLCDC = 8'h91;
+ reg [7:0] rSTAT = 8'h00;
+ reg [7:0] rSCY = 8'b00;
+ reg [7:0] rSCX = 8'b00;
+ reg [7:0] rLYC = 8'b00;
+ reg [7:0] rDMA = 8'b00;
+ reg [7:0] rBGP = 8'b00;
+ reg [7:0] rOBP0 = 8'b00;
+ reg [7:0] rOBP1 = 8'b00;
+ reg [7:0] rWY = 8'b00;
+ reg [7:0] rWX = 8'b00;
+
/***** Sync generation *****/
/* A complete cycle takes 456 clocks.
2'b10)
: 2'b01;
- always @(posedge clk)
+ assign vgavs = (posy > 147) && (posy < 151);
+ assign vgahs = (posx < 250) && (posx < 350);
+ assign vgar = (posx < 160) && (posy < 144) ? {posy == rLYC ? 3'b111 : 3'b000} : 3'b000;
+ assign vgag = (posx < 160) && (posy < 144) ? {posy < rSCY ? 3'b111 : 3'b000} : 3'b000;
+ assign vgab = (posx < 160) && (posy < 144) ? {2'b11} : 2'b00;
+
+ reg mode00irq = 0, mode01irq = 0, mode10irq = 0, lycirq = 0;
+ assign lcdcirq = (rSTAT[3] & mode00irq) | (rSTAT[4] & mode01irq) | (rSTAT[5] & mode10irq) | (rSTAT[6] & lycirq);
+ assign vblankirq = (posx == 0 && posy == 153);
+
+ always @(posedge clk4)
begin
if (posx == 455) begin
posx <= 0;
- if (posy == 153)
+ if (posy == 153) begin
posy <= 0;
- else
+ if (0 == rLYC)
+ lycirq <= 1;
+ end else begin
posy <= posy + 1;
- end else
+ /* Check for vblank and generate an IRQ if needed. */
+ if (posy == 143) begin
+ mode01irq <= 1;
+ end
+ if ((posy + 1) == rLYC)
+ lycirq <= 1;
+
+ end
+ end else begin
posx <= posx + 1;
+ if (posx == 165)
+ mode00irq <= 1;
+ else if (posx == 373)
+ mode10irq <= 1;
+ else begin
+ mode00irq <= 0;
+ mode01irq <= 0;
+ mode10irq <= 0;
+ end
+ lycirq <= 0;
+ end
+
end
/***** Bus interface *****/
- reg [7:0] rLCDC = 8'h91;
- reg [7:0] rSTAT = 8'h00;
- reg [7:0] rSCY = 8'b00;
- reg [7:0] rSCX = 8'b00;
- reg [7:0] rLYC = 8'b00;
- reg [7:0] rDMA = 8'b00;
- reg [7:0] rBGP = 8'b00;
- reg [7:0] rOBP0 = 8'b00;
- reg [7:0] rOBP1 = 8'b00;
- reg [7:0] rWY = 8'b00;
- reg [7:0] rWX = 8'b00;
-
assign data = rd ?
(addr == `ADDR_LCDC) ? rLCDC :
(addr == `ADDR_STAT) ? {rSTAT[7:3], (rLYC == posy) ? 1'b1 : 1'b0, mode} :
output wire [7:0] leds,
output serio,
output wire [3:0] digits,
- output wire [7:0] seven);
+ output wire [7:0] seven,
+ output wire hs, vs,
+ output wire [2:0] r, g,
+ output wire [1:0] b);
wire clk;
CPUDCM dcm (.CLKIN_IN(xtal), .CLKFX_OUT(clk));
wire [7:0] data;
wire wr, rd;
- wire irq, tmrirq, lcdcirq;
+ wire irq, tmrirq, lcdcirq, vblankirq;
wire [7:0] jaddr;
wire [1:0] state;
.clk(clk),
.wr(wr),
.rd(rd),
- .irq(lcdcirq));
+ .lcdcirq(lcdcirq),
+ .vblankirq(vblankirq),
+ .vgahs(hs),
+ .vgavs(vs),
+ .vgar(r),
+ .vgag(g),
+ .vgab(b));
AddrMon amon(
.addr(addr),
.wr(wr),
.addr(addr),
.data(data),
- .vblank(0),
+ .vblank(vblankirq),
.lcdc(lcdcirq),
.tovf(tmrirq),
.serial(0),
`include "insn_di-ei.v"
`include "insn_incdec_hl.v"
`include "insn_incdec_reg8.v"
-`include "insn_ldm_a.v"
\ No newline at end of file
+`include "insn_ldm_a.v"
- SECTION "a",HOME
+ SECTION "a",HOME[$00]
+
+start: jp main
+
+ section "vbl",HOME[$40]
+ jp vbl
+
+ section "lcdc",HOME[$48]
+ jp lcdc
+
+ section "tmro",HOME[$50]
+ jp tmro
main:
ld a, $FF
ld [$FF51],a
+
+; ld a, $04
+; ld [$FFFF], a
ld sp, $DFF0
ld a, $04 ;start timer, 4.096KHz
- ld [$FF07], a
+ ld c, $07
+ ld [c], a
ld hl, $DF81
xor a
signon:
db $0D,$0A,$1B,"[1mFPGABoy Diagnostic ROM",$1B,"[0m",$0D,$0A,0
- section "fuq",HOME[$100]
-irqhand:
+vbl:
+lcdc:
+ PUSH AF
+
+ xor a
+ ld c, $0F
+ ld [c], a
+
+ POP AF
+
+ reti
+
+tmro:
PUSH AF
PUSH BC
PUSH DE
PUSH HL
xor a
- ld [$FF0F], a
+ ld c, $0F
+ ld [c], a
ld hl, $DF82
ld a, [hld]
ld a, $41 ; print A
call putc
.noprint:
- inc [hl]
+ ld hl, $DF81
ld a, [hl]
- ld [$FF51], a
+ add 1
+ ld [hl], a
+ ld c, $51
+ ld [c], a
POP HL
POP DE
; Test DI/EI delay
di
- ld hl, .difail
+ ld hl, .dinocausefail
ld c, $0F ; First, wait until an interrupt happens...
.wait: ld a, [c]
+ and $04
cp 0
jr z, .wait
ei ; Now make sure that an IRQ didn't happen on EI/DI
di
ld a, [c]
+ and $04
cp 0
jr z, .fail
+ ld hl, .dicausefail
ei ; Make sure that an IRQ does happen on EI/NOP/DI
nop
+ nop
di
ld a, [c]
+ and $04
cp 0
jr nz, .fail
ei
db "CPL",0
.inc16fail:
db "INC16",0
-.difail:
- db "DI/EI delay",0
+.dinocausefail:
+ db "DI/EI does not cause interrupt",0
+.dicausefail:
+ db "DI/NOP/EI cause interrupt",0
.testfailed:
db " test failed.",$0D,$0A,0
.ok:
// If opcode[1], then ld 16m8, else ld 8m8
`ifdef EXECUTE
- `INSN_LDM_A: begin
+ `INSN_LD8M_A,`INSN_LD16M_A: begin
case (cycle)
0: begin
`EXEC_INC_PC
`endif
`ifdef WRITEBACK
- `INSN_LDM_A: begin
+ `INSN_LD8M_A,`INSN_LD16M_A: begin
case (cycle)
0: if (!opcode[1]) begin
tmp <= 8'hFF;
cycle <= 1; /* Skip cycle 1 */
end
1: tmp2 <= rdata;
- 2: if (opcode[1])
+ 2: if (!opcode[1])
tmp2 <= rdata;
else
tmp <= rdata;
SECTION "a",HOME
main:
- ld c, $51 ; Note that we are alive.
- ld a, $FF
- ld [c],a
+ ld a, $FF ; Note that we are alive.
+ ld [$FF51],a
ld sp, $DFF0