├── doc ├── .gitignore ├── system_design_spec.pdf └── papiGB_design_document.md ├── sim ├── generated_frames │ └── .gitignore ├── signals │ ├── mmu_cpu_gpu_sel │ ├── dzcpu_states │ ├── gpu_dst │ ├── gpu_uop │ ├── timer_states │ ├── dzcpu_reg_select │ ├── gpu_src │ ├── flow_ids │ ├── dzcpu_uop_cmd │ └── tb_simple_dzcpu.gtkw ├── .gitignore ├── Makefile ├── resources │ ├── tetris_oam_fe00_fe9f.dump │ └── zelda_game_scene_1_oam_fe00_fe9f.dump └── reference │ └── bios_vram_9800_9bff.dump ├── tests └── asm │ ├── .gitignore │ ├── test_PUSHDE.asm │ ├── test_ANDn2.asm │ ├── test_SUBn.asm │ ├── test_CPn.asm │ ├── test_SUBr_a.asm │ ├── test_ADDn.asm │ ├── test_LDHLmr_h.asm │ ├── test_LDHLmr_l.asm │ ├── test_XORan.asm │ ├── test_DECBC.asm │ ├── test_DECDE.asm │ ├── test_DECHL.asm │ ├── test_INCBC.asm │ ├── test_INCDE.asm │ ├── test_INCHL.asm │ ├── test_INCSP.asm │ ├── test_SUBAn.asm │ ├── test_JRNCn2.asm │ ├── test_LDHLDA.asm │ ├── test_LDIOnA.asm │ ├── test_RLCA.asm │ ├── test_RRA.asm │ ├── test_RRc.asm │ ├── test_push-pop_bc.asm │ ├── test_CB_SHL_b_2.asm │ ├── test_ADDr_a.asm │ ├── test_DECSP.asm │ ├── test_ORr_a.asm │ ├── test_XORr_a.asm │ ├── test_LDHLmr_a.asm │ ├── test_LDHLmr_b.asm │ ├── test_LDHLmr_c.asm │ ├── test_LDHLmr_d.asm │ ├── test_LDHLmr_e.asm │ ├── test_LDSPHL.asm │ ├── test_PUSHHL_POPHL.asm │ ├── test_ANDn.asm │ ├── test_ANDr_a.asm │ ├── test_CB_SHL_b.asm │ ├── test_PUSHDE_POPDE.asm │ ├── test_SBCr_a.asm │ ├── test_LDrr_aa.asm │ ├── test_LDrr_ha.asm │ ├── test_LDrr_hb.asm │ ├── test_LDrr_hc.asm │ ├── test_LDrr_hd.asm │ ├── test_LDrr_he.asm │ ├── test_LDrr_hh.asm │ ├── test_LDrr_hl.asm │ ├── test_PUSHAF.asm │ ├── test_ADCr_a.asm │ ├── test_ADDr_h.asm │ ├── test_JPCnn.asm │ ├── test_JRNCn.asm │ ├── test_ORr_b.asm │ ├── test_ORr_c.asm │ ├── test_ORr_d.asm │ ├── test_ORr_h.asm │ ├── test_ORr_l.asm │ ├── test_SUBr_b.asm │ ├── test_SUBr_c.asm │ ├── test_ADDr_e.asm │ ├── test_ADDr_l.asm │ ├── test_LDIOCA.asm │ ├── test_ORr_e.asm │ ├── test_SUBr_d.asm │ ├── test_SUBr_h.asm │ ├── test_XORr_b.asm │ ├── test_XORr_c.asm │ ├── test_XORr_d.asm │ ├── test_XORr_e.asm │ ├── test_XORr_h.asm │ ├── test_XORr_l.asm │ ├── test_ADDr_b.asm │ ├── test_ADDr_c.asm │ ├── test_JPHL.asm │ ├── test_JPNZnn.asm │ ├── test_SUBr_l.asm │ ├── test_ADDr_d.asm │ ├── test_ADDr_d_2.asm │ ├── test_ANDr_b.asm │ ├── test_ANDr_c.asm │ ├── test_ANDr_d.asm │ ├── test_ANDr_e.asm │ ├── test_ANDr_h.asm │ ├── test_ANDr_l.asm │ ├── test_INCr_b.asm │ ├── test_JPZnn.asm │ ├── test_LDrr_ab.asm │ ├── test_LDrr_ac.asm │ ├── test_LDrr_ad.asm │ ├── test_LDrr_ae.asm │ ├── test_LDrr_ah.asm │ ├── test_LDrr_al.asm │ ├── test_LDrr_da.asm │ ├── test_LDrr_la.asm │ ├── test_LDrr_lh.asm │ ├── test_LDrr_ll.asm │ ├── test_ORn.asm │ ├── test_LDrr_ba.asm │ ├── test_LDrr_bb.asm │ ├── test_LDrr_bc.asm │ ├── test_LDrr_ca.asm │ ├── test_LDrr_cb.asm │ ├── test_LDrr_cc.asm │ ├── test_SBCn.asm │ ├── test_DECr_a.asm │ ├── test_INCr_a.asm │ ├── test_DECr_b.asm │ ├── test_SUBr_e.asm │ ├── test_INCr_c.asm │ ├── test_LDrr_db.asm │ ├── test_LDrr_dc.asm │ ├── test_LDrr_dd.asm │ ├── test_LDrr_de.asm │ ├── test_LDrr_dh.asm │ ├── test_LDrr_dl.asm │ ├── test_LDrr_eb.asm │ ├── test_LDrr_ec.asm │ ├── test_LDrr_ed.asm │ ├── test_LDrr_eh.asm │ ├── test_LDrr_el.asm │ ├── test_LDrr_lb.asm │ ├── test_LDrr_lc.asm │ ├── test_LDrr_ld.asm │ ├── test_LDrr_le.asm │ ├── test_RETI.asm │ ├── test_ADDHLSP.asm │ ├── test_DECr_d.asm │ ├── test_DECr_h.asm │ ├── test_INCr_d.asm │ ├── test_INCr_h.asm │ ├── test_LDrr_ea.asm │ ├── test_LDrr_ee.asm │ ├── test_DECr_c.asm │ ├── test_DECr_e.asm │ ├── test_DECr_l.asm │ ├── test_INCr_b_flags.asm │ ├── test_INCr_e.asm │ ├── test_INCr_l.asm │ ├── test_LDrr_bd.asm │ ├── test_LDrr_be.asm │ ├── test_LDrr_bh.asm │ ├── test_LDrr_bl.asm │ ├── test_LDrr_cd.asm │ ├── test_LDrr_ce.asm │ ├── test_LDrr_ch.asm │ ├── test_LDrr_cl.asm │ ├── test_JRCn.asm │ ├── test_SBCr_b.asm │ ├── test_SBCr_c.asm │ ├── test_SBCr_d.asm │ ├── test_SBCr_e.asm │ ├── test_SBCr_h.asm │ ├── test_SBCr_l.asm │ ├── test_ORHL.asm │ ├── test_ADCr_b.asm │ ├── test_ADCr_c.asm │ ├── test_ADCr_d.asm │ ├── test_ADCr_e.asm │ ├── test_ADCr_h.asm │ ├── test_ADCr_l.asm │ ├── test_INCr_c_flags.asm │ ├── test_RETC.asm │ ├── test_JRn.asm │ ├── test_INCHLm.asm │ ├── test_CALLNZnn.asm │ ├── test_LDrHLm_b.asm │ ├── test_LDrHLm_c.asm │ ├── test_LDrHLm_d.asm │ ├── test_LDrHLm_e.asm │ ├── test_LDrHLm_h.asm │ ├── test_LDrHLm_l.asm │ ├── test_LDABCm.asm │ ├── test_LDADEm.asm │ ├── test_LDrHLm_a.asm │ └── README ├── script ├── create_gb_from_asm.sh ├── run_gearboysim.sh ├── create_dump_from_hex.pl └── check_bios_log.py ├── .travis.yml ├── ucf ├── pgb_vga.ucf └── pgb_lcd.ucf ├── rtl ├── sound_controller_modules │ ├── tb_simple_mx.v │ ├── SoundControllerOSC2.v │ ├── SoundControllerOSC1.v │ ├── tb_simple_channel2.v │ ├── tb_simple_channel4.v │ ├── tb_simple_channel3.v │ ├── tb_simple_channel1.v │ ├── SoundControllerMX.v │ ├── SoundControllerChannel2.v │ ├── SoundControllerChannel1.v │ ├── SoundControllerChannel3.v │ └── SoundControllerChannel4.v ├── aDefinitions.v ├── interrupts.v ├── io.v ├── gpu_definitions.v ├── VgaController.v ├── pGB.v ├── bios.v └── gpu_ucode_rom.v ├── tb └── tb_simple_io.v ├── cad └── papiGB.scad └── README.md /doc/.gitignore: -------------------------------------------------------------------------------- 1 | *.docx 2 | -------------------------------------------------------------------------------- /sim/generated_frames/.gitignore: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /sim/signals/mmu_cpu_gpu_sel: -------------------------------------------------------------------------------- 1 | 0 bus_owner_cpu 2 | 1 bus_owner_gpu 3 | -------------------------------------------------------------------------------- /tests/asm/.gitignore: -------------------------------------------------------------------------------- 1 | *.dump 2 | *.gb 3 | *.hex 4 | *.map 5 | *.obj 6 | *.sym 7 | -------------------------------------------------------------------------------- /sim/signals/dzcpu_states: -------------------------------------------------------------------------------- 1 | 0 AFTER_RESET 2 | 1 START_FLOW 3 | 2 RUN_FLOW 4 | 3 END_FLOW 5 | -------------------------------------------------------------------------------- /doc/system_design_spec.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/diegovalverde/papiGB/HEAD/doc/system_design_spec.pdf -------------------------------------------------------------------------------- /sim/.gitignore: -------------------------------------------------------------------------------- 1 | *.log 2 | *.vcd 3 | *.dump 4 | *.ppm 5 | *.swp 6 | *.swap 7 | ise/ 8 | tb_simple_dzcpu 9 | -------------------------------------------------------------------------------- /sim/signals/gpu_dst: -------------------------------------------------------------------------------- 1 | 12 vmem_addr 2 | 13 wBh 3 | 14 wBl 4 | 15 bg_buffer_block_sel 5 | 16 state 6 | 17 r0 7 | 18 r1 8 | 19 r2 9 | -------------------------------------------------------------------------------- /sim/signals/gpu_uop: -------------------------------------------------------------------------------- 1 | 0 nop 2 | 1 wrl 3 | 2 wrr 4 | 3 add 5 | 4 sub 6 | 5 addl 7 | 6 jnz 8 | 7 wbg 9 | 8 subl 10 | 9 rvmem 11 | 10 shl 12 | -------------------------------------------------------------------------------- /script/create_gb_from_asm.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | rgbasm -o ${1}.obj ../tests/asm/${1}.asm 4 | rgblink -m ${1}.map -n ${1}.sym -o ${1}.gb ${1}.obj 5 | -------------------------------------------------------------------------------- /sim/signals/timer_states: -------------------------------------------------------------------------------- 1 | 0 AFTER_RESET 2 | 1 WAIT_FOR_TICK 3 | 2 INC 4 | 3 INC_BTAKEN 5 | 4 INC_BTAKEN_NOT_EOF 6 | 5 WAIT_EOF 7 | 8 | -------------------------------------------------------------------------------- /tests/asm/test_PUSHDE.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | ld d, 10 4 | ld e, 25 5 | push de 6 | ;the expected value in the stack is 1025 7 | -------------------------------------------------------------------------------- /sim/signals/dzcpu_reg_select: -------------------------------------------------------------------------------- 1 | 0 b 2 | 1 c 3 | 2 d 4 | 3 e 5 | 4 h 6 | 5 l 7 | 6 hl 8 | 7 a 9 | 8 pc 10 | 9 sp 11 | 10 spl 12 | 11 sph 13 | 12 x8 14 | 13 x16 15 | 14 io_c 16 | 15 de -------------------------------------------------------------------------------- /tests/asm/test_ANDn2.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $1 7 | and a, $10 8 | ;af=$00a0 9 | push af 10 | -------------------------------------------------------------------------------- /tests/asm/test_SUBn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $df 7 | sub a, $5 8 | ;af=$da40 9 | push af 10 | -------------------------------------------------------------------------------- /tests/asm/test_CPn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | cp a, $90 8 | ;the value af=$0050 9 | push af 10 | -------------------------------------------------------------------------------- /tests/asm/test_SUBr_a.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, 20 7 | sub a 8 | ; A=0, flags Z=1, H=1, C=1 9 | push af 10 | -------------------------------------------------------------------------------- /tests/asm/test_ADDn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $f8 7 | add $8 8 | ;the value expected is 00b0 9 | push af 10 | -------------------------------------------------------------------------------- /tests/asm/test_LDHLmr_h.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld [hl],h 7 | dec hl 8 | ld [hl],h 9 | ;the value expected is $FFFF 10 | -------------------------------------------------------------------------------- /tests/asm/test_LDHLmr_l.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld [hl],l 7 | dec hl 8 | ld [hl],l 9 | ;the value expected is $FDFC 10 | -------------------------------------------------------------------------------- /tests/asm/test_XORan.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $7F 7 | xor a, $ED 8 | ;the value expected is af=$9200 9 | push af 10 | -------------------------------------------------------------------------------- /tests/asm/test_DECBC.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld bc, $cafe 7 | dec bc 8 | ;the value expected is $cafd not flags affected 9 | push bc 10 | -------------------------------------------------------------------------------- /tests/asm/test_DECDE.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld de, $cafe 7 | dec de 8 | ;the value expected is $cafd not flags affected 9 | push de 10 | -------------------------------------------------------------------------------- /tests/asm/test_DECHL.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld hl, $cafe 7 | dec hl 8 | ;the value expected is $cafd not flags affected 9 | push hl 10 | -------------------------------------------------------------------------------- /tests/asm/test_INCBC.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld bc, $cafd 7 | inc bc 8 | ;the value expected is $cafe not flags affected 9 | push bc 10 | -------------------------------------------------------------------------------- /tests/asm/test_INCDE.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld de, $ffff 7 | inc de 8 | ;the value expected is $0000 not flags affected 9 | push de 10 | -------------------------------------------------------------------------------- /tests/asm/test_INCHL.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld hl, $00ff 7 | inc hl 8 | ;the value expected is $0100 not flags affected 9 | push hl 10 | -------------------------------------------------------------------------------- /tests/asm/test_INCSP.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFD 6 | ld hl, $ffff 7 | inc sp 8 | ;the value expected is $ffff not flags affected 9 | push hl 10 | -------------------------------------------------------------------------------- /tests/asm/test_SUBAn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $0 7 | sub a, $88 8 | 9 | ;the value expected is bc=$7870 10 | push af 11 | -------------------------------------------------------------------------------- /tests/asm/test_JRNCn2.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ;af = $da40 6 | jr nc, end 7 | 8 | ld a, $80 9 | ;the value expected is af=$8040 10 | end: 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_LDHLDA.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld a, $15 7 | 8 | ldd [hl],a 9 | ldd [hl],a 10 | ;the value expected is $1515 11 | -------------------------------------------------------------------------------- /tests/asm/test_LDIOnA.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | 6 | ld a, $35 7 | ld [$FF00+$FD],a 8 | dec a 9 | ld [$FF00+$FC],a 10 | ;the value expected is $3534 11 | -------------------------------------------------------------------------------- /tests/asm/test_RLCA.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ;f = 70 6 | ld a, $88 7 | ld sp, $FFFE 8 | rlca 9 | ;the value expected is af=$1110 10 | push af 11 | -------------------------------------------------------------------------------- /tests/asm/test_RRA.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ;f = 70 6 | ld a, $fe 7 | ld sp, $FFFE 8 | rr a 9 | ;the value expected is af=$ff40 10 | push af 11 | -------------------------------------------------------------------------------- /tests/asm/test_RRc.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld c, $ff 7 | rr c 8 | ld a, c 9 | ;the value expected is bc=$ff10 10 | push af 11 | -------------------------------------------------------------------------------- /tests/asm/test_push-pop_bc.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | ld b, 8 4 | ld c, 7 5 | push bc 6 | ld b, 6 7 | nop 8 | pop bc 9 | ;the value expected is b=8 and c=7 10 | nop 11 | -------------------------------------------------------------------------------- /tests/asm/test_CB_SHL_b_2.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld b, $FF 7 | srl b 8 | ld a, b 9 | ;the value expected is bc=$7f10 10 | push af 11 | -------------------------------------------------------------------------------- /tests/asm/test_ADDr_a.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $02 7 | or a,a 8 | nop 9 | add a, a 10 | ;the value expected is 4 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_DECSP.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFF 6 | dec sp 7 | ld hl, $cafa 8 | dec hl 9 | ;the value expected is $caf9 not flags affected 10 | push hl 11 | -------------------------------------------------------------------------------- /tests/asm/test_ORr_a.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $80 7 | or a, a 8 | ;the value expected is $20 with flasgs Z=0 9 | ;af=$8000 10 | push af 11 | -------------------------------------------------------------------------------- /tests/asm/test_XORr_a.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $80 7 | xor a, a 8 | ;the value expected is $00 with flasgs Z=1 9 | ;af=$0080 10 | push af 11 | -------------------------------------------------------------------------------- /tests/asm/test_LDHLmr_a.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld a, $95 7 | ld [hl],a 8 | dec hl 9 | dec a 10 | ld [hl],a 11 | ;the value expected is $9594 12 | -------------------------------------------------------------------------------- /tests/asm/test_LDHLmr_b.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld b, $50 7 | ld [hl],b 8 | dec hl 9 | dec b 10 | ld [hl],b 11 | ;the value expected is $504f 12 | -------------------------------------------------------------------------------- /tests/asm/test_LDHLmr_c.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld c, $f2 7 | ld [hl],c 8 | dec hl 9 | dec c 10 | ld [hl],c 11 | ;the value expected is $f2f1 12 | -------------------------------------------------------------------------------- /tests/asm/test_LDHLmr_d.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld d, $11 7 | ld [hl],d 8 | dec hl 9 | dec d 10 | ld [hl],d 11 | ;the value expected is $1110 12 | -------------------------------------------------------------------------------- /tests/asm/test_LDHLmr_e.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld e, $23 7 | ld [hl],e 8 | dec hl 9 | dec e 10 | ld [hl],e 11 | ;the value expected is $2322 12 | -------------------------------------------------------------------------------- /tests/asm/test_LDSPHL.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFE 6 | 7 | ld a, 1 8 | or a,a 9 | 10 | ld sp,hl 11 | 12 | push af 13 | 14 | ;the value expected is $0100 15 | -------------------------------------------------------------------------------- /tests/asm/test_PUSHHL_POPHL.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | ld l, 7 4 | ld h, 3 5 | push hl 6 | ld l, 0 7 | nop 8 | pop hl 9 | ;the expected value in l= 7 and h=3 10 | nop 11 | nop 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | before_install: 2 | - sudo apt-get update -qq 3 | - sudo apt-get install -qq iverilog 4 | - chmod +x script/ci_script.sh 5 | 6 | install: true 7 | 8 | script: 9 | - script/ci_script.sh 10 | 11 | after_failure: true 12 | 13 | after_script: true 14 | -------------------------------------------------------------------------------- /tests/asm/test_ANDn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $ff 7 | and a, $15 8 | ;the value expected is $00 with flasgs Z=0 N=0 H=1 C=0 9 | ;af=$1520 10 | push af 11 | -------------------------------------------------------------------------------- /tests/asm/test_ANDr_a.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $20 7 | and a, a 8 | ;the value expected is $20 with flasgs Z=0 N=0 H=1 C=0 9 | ;af=$2020 10 | push af 11 | -------------------------------------------------------------------------------- /tests/asm/test_CB_SHL_b.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld b, $0F 7 | ld c, $00 8 | srl b 9 | ld a, b 10 | ;the value expected is bc=$0710 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_PUSHDE_POPDE.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | ld d, 10 4 | ld e, 25 5 | push de 6 | ld d, 0 7 | nop 8 | pop de 9 | ;the expected value in d= 10 and e=25 10 | nop 11 | nop 12 | -------------------------------------------------------------------------------- /tests/asm/test_SBCr_a.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $0F 7 | or a,a 8 | nop 9 | sbc a, a 10 | ;Expected Z=1 N=1 H=0 C=0 -- AF=00C0 11 | push af 12 | -------------------------------------------------------------------------------- /sim/signals/gpu_src: -------------------------------------------------------------------------------- 1 | 0 null 2 | 12 vmem_addr 3 | 13 bh 4 | 14 bl 5 | 15 bg_buffer_block_sel 6 | 1 state 7 | 16 cur_tile 8 | 17 r1 9 | 18 r2 10 | 19 r3 11 | 20 vmem_data 12 | 21 bgmoffset 13 | 22 bg_col_offset 14 | 23 bgtoffset 15 | 24 ly_mod_8 16 | 25 vmem_data_shl_4 17 | 18 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_aa.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $12 7 | or a,a ;borra las banderas 8 | 9 | ld a, a 10 | push af 11 | 12 | ;the value expected is $1200 13 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ha.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $3634 8 | ld a, $08 9 | 10 | ld h, a 11 | push hl 12 | ;the value expected is $0834 13 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_hb.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $3634 8 | ld b, $08 9 | 10 | ld h, b 11 | push hl 12 | ;the value expected is $0834 13 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_hc.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $3634 8 | ld c, $08 9 | 10 | ld h, c 11 | push hl 12 | ;the value expected is $0834 13 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_hd.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $3634 8 | ld d, $08 9 | 10 | ld h, d 11 | push hl 12 | ;the value expected is $0834 13 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_he.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $3634 8 | ld e, $08 9 | 10 | ld h, e 11 | push hl 12 | ;the value expected is $0834 13 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_hh.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $3634 8 | ld h, $08 9 | 10 | ld h, h 11 | push hl 12 | ;the value expected is $0834 13 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_hl.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $3634 8 | ld l, $08 9 | 10 | ld h, l 11 | push hl 12 | ;the value expected is $0808 13 | -------------------------------------------------------------------------------- /tests/asm/test_PUSHAF.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $dffb 6 | ld a, $1b 7 | push af 8 | nop 9 | ld a,$ff 10 | sub a,$ff 11 | nop 12 | nop 13 | pop af 14 | -------------------------------------------------------------------------------- /tests/asm/test_ADCr_a.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $0F 7 | or a,a 8 | nop 9 | adc a, a 10 | ;the value expected is a=$1E and f=$20 af=$1E20 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ADDr_h.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $0F 7 | ld h, $1F 8 | add a, h 9 | ;the value expected is $2E with flags H = 1 10 | ;$2E20 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_JPCnn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $ff 7 | add $01 8 | jp c, carry_label 9 | ld a, $07 10 | carry_label: 11 | ;expected $00b0 12 | push af 13 | -------------------------------------------------------------------------------- /tests/asm/test_JRNCn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $0 7 | rr a 8 | jr nc, end 9 | 10 | ld a, $cc 11 | ;the value expected is af=$8000 12 | end: 13 | push af 14 | -------------------------------------------------------------------------------- /tests/asm/test_ORr_b.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $39 7 | ld b, $aa 8 | or a, b 9 | ;the value expected is $bb with flasgs $00 10 | ;af=$bb00 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ORr_c.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $77 7 | ld c, $ca 8 | or a, c 9 | ;the value expected is $52 with flasgs Z=0 10 | ;af=$ff00 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ORr_d.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | ld d, $00 8 | or a, d 9 | ;the value expected is $67 with flasgs Z=1 10 | ;af=$0080 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ORr_h.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $e6 7 | ld h, $a9 8 | or a, h 9 | ;the value expected is $ef with flasgs Z=0 10 | ;af=$ef00 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ORr_l.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | ld l, $00 8 | or a, l 9 | ;the value expected is $00 with flasgs Z=1 10 | ;af=$0080 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_SUBr_b.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, 0 7 | ld b, 1 8 | sub a, b 9 | ;Expected A =-1. Flags Z=0, N=1, H=1, C=1. 10 | ; AF = FF70 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_SUBr_c.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, 20 7 | ld c, 20 8 | sub a, c 9 | ;Expected A=0. Flags Z=1, N=1, H=0, C=0. 10 | ; AF = FFC0 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ADDr_e.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $f0 7 | ld e, $10 8 | add a, e 9 | ;the value expected is $00 with flags Z=1 C=1 10 | ;af=0090 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ADDr_l.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $81 7 | ld l, $0F 8 | add a, l 9 | ;the value expected is $90 with flags H=1 10 | ;af=$9020 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_LDIOCA.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | 6 | ld a, $85 7 | ld c, $FD 8 | ld [$FF00+c],a 9 | ld a, $25 10 | dec c 11 | ld [$FF00+c],a 12 | ;the value expected is $8525 13 | -------------------------------------------------------------------------------- /tests/asm/test_ORr_e.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $11 7 | ld e, $10 8 | or a, e 9 | ;the value expected is $11 with flasgs $0000 10 | ;af=$1100 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_SUBr_d.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $50 7 | ld d, $0F 8 | sub a, d 9 | ;Expected A = 41, Flags Z=0, N=1, H=1, C=0 10 | ; AF = $4160 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_SUBr_h.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $A 7 | ld h, 0 8 | sub a, h 9 | ;Expected: A = $0A, Flags Z=0, N=1, H=0, C=0 10 | ; AF = $0A40 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_XORr_b.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $39 7 | ld b, $aa 8 | xor a, b 9 | ;the value expected is $93 with flasgs $00 10 | ;af=$9300 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_XORr_c.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $77 7 | ld c, $ca 8 | xor a, c 9 | ;the value expected is $bd with flasgs Z=0 10 | ;af=$bd00 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_XORr_d.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | ld d, $00 8 | xor a, d 9 | ;the value expected is $67 with flasgs Z=1 10 | ;af=$0080 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_XORr_e.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $11 7 | ld e, $10 8 | xor a, e 9 | ;the value expected is $01 with flasgs $0000 10 | ;af=$0100 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_XORr_h.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $e6 7 | ld h, $a9 8 | xor a, h 9 | ;the value expected is $ef with flasgs Z=0 10 | ;af=$4f00 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_XORr_l.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $a9 7 | ld l, $a9 8 | xor a, l 9 | ;the valu1e expected is $ef with flasgs Z=0 10 | ;af=$0080 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ADDr_b.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $ff 7 | ld b, $01 8 | add a, b 9 | ;the value expected is 00 - with Flags Z-H-C = 1 10 | ;af=00b0 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ADDr_c.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $0F 7 | ld c, $05 8 | add a, c 9 | ;the value expected is D-20 H-$14 with flags H = 1 10 | ;af=$1420 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_JPHL.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $0F 7 | ld hl, da_label 8 | jp hl 9 | or a,a 10 | nop 11 | da_label: 12 | ;expected $0fbe 13 | push af 14 | -------------------------------------------------------------------------------- /tests/asm/test_JPNZnn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $FF 7 | or a,$ff 8 | jp nz, da_label 9 | or a,a 10 | nop 11 | da_label: 12 | ;expected $0fbe 13 | push af 14 | -------------------------------------------------------------------------------- /tests/asm/test_SUBr_l.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | ld l, $0B 8 | sub a, l 9 | ;Expected: A = $F5, Flags Z=0, N=1, H=1, C=1 10 | ; AF = $F570 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ADDr_d.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $ff 7 | ld d, $11 8 | add a, d 9 | ;the value expected is D17 Hex-$10 with flags C=1 H=1 10 | ;af=$1030 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ADDr_d_2.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $02 7 | ld d, $ff 8 | add a, d 9 | ;the value expected is D17 Hex-$10 with flags C=1 H=1 10 | ;af=$1030 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ANDr_b.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $29 7 | ld b, $a8 8 | and a, b 9 | ;the value expected is $28 with flasgs Z=0 N=0 H=1 C=0 10 | ;af=$2820 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ANDr_c.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $77 7 | ld c, $5a 8 | and a, c 9 | ;the value expected is $52 with flasgs Z=0 N=0 H=1 C=0 10 | ;af=$5220 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ANDr_d.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $ff 7 | ld d, $67 8 | and a, d 9 | ;the value expected is $67 with flasgs Z=0 N=0 H=1 C=0 10 | ;af=$6720 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ANDr_e.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $20 7 | ld e, $49 8 | and a, e 9 | ;the value expected is $00 with flasgs Z=1 N=0 H=1 C=0 10 | ;af=$00a0 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ANDr_h.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $e6 7 | ld h, $a1 8 | and a, h 9 | ;the value expected is $a0 with flasgs Z=0 N=0 H=1 C=0 10 | ;af=$a020 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_ANDr_l.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $71 7 | ld l, $2f 8 | and a, l 9 | ;the value expected is $21 with flasgs Z=0 N=0 H=1 C=0 10 | ;af=$2120 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_INCr_b.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | or a, a ; Clears all flags 8 | ld b, $00 9 | ld c, $00 10 | inc b 11 | ;Expected BC = $0100 12 | push bc ; Tests BC 13 | -------------------------------------------------------------------------------- /tests/asm/test_JPZnn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | and a,$ff 8 | jp z, zero_label 9 | ld a, $ff 10 | nop 11 | zero_label: 12 | ;expected $00a0 13 | push af 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ab.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld b, $55 7 | ld a, $12 8 | or a,a ;borra las banderas 9 | 10 | ld a, b 11 | push af 12 | 13 | ;the value expected is $5500 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ac.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld c, $90 7 | ld a, $12 8 | or a,a ;borra las banderas 9 | 10 | ld a, c 11 | push af 12 | 13 | ;the value expected is $9000 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ad.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld d, $13 7 | ld a, $12 8 | or a,a ;borra las banderas 9 | 10 | ld a, d 11 | push af 12 | 13 | ;the value expected is $1300 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ae.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld e, $33 7 | ld a, $12 8 | or a,a ;borra las banderas 9 | 10 | ld a, e 11 | push af 12 | 13 | ;the value expected is $3300 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ah.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld h, $77 7 | ld a, $12 8 | or a,a ;borra las banderas 9 | 10 | ld a, h 11 | push af 12 | 13 | ;the value expected is $7700 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_al.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld l, $26 7 | ld a, $12 8 | or a,a ;borra las banderas 9 | 10 | ld a, l 11 | push af 12 | 13 | ;the value expected is $2600 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_da.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld de, $1313 8 | or a,a ;borra las banderas 9 | 10 | ld d, a 11 | push de 12 | ;the value expected is $1513 13 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_la.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $2120 8 | or a,a ;borra las banderas 9 | 10 | ld l, a 11 | push hl 12 | ;the value expected is $2115 13 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_lh.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $6463 8 | or a,a ;borra las banderas 9 | 10 | ld l, h 11 | push hl 12 | ;the value expected is $6464 13 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ll.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $7902 8 | or a,a ;borra las banderas 9 | 10 | ld l, l 11 | push hl 12 | ;the value expected is $7902 13 | -------------------------------------------------------------------------------- /tests/asm/test_ORn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $01 7 | or a, a 8 | or a, $15 9 | ;the value expected is $00 with flasgs Z=0 N=0 H=1 C=0 10 | ;af=$1500 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ba.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $8897 8 | or a,a ;borra las banderas 9 | 10 | ld b, a 11 | push bc 12 | 13 | ;the value expected is $1597 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_bb.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $9745 8 | or a,a ;borra las banderas 9 | 10 | ld b, b 11 | push bc 12 | 13 | ;the value expected is $4545 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_bc.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $9895 8 | or a,a ;borra las banderas 9 | 10 | ld b, c 11 | push bc 12 | 13 | ;the value expected is $9595 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ca.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $3634 8 | or a,a ;borra las banderas 9 | 10 | ld c, a 11 | push bc 12 | 13 | ;the value expected is $3615 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_cb.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $8897 8 | or a,a ;borra las banderas 9 | 10 | ld c, b 11 | push bc 12 | 13 | ;the value expected is $8888 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_cc.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $1587 8 | or a,a ;borra las banderas 9 | 10 | ld c, c 11 | push bc 12 | 13 | ;the value expected is $1587 14 | -------------------------------------------------------------------------------- /tests/asm/test_SBCn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $0 7 | or a,a 8 | ld a, $FF 9 | add a,$03 10 | nop 11 | sbc a, $01 12 | ;Expected C=1 -- AF=00C0 13 | push af 14 | -------------------------------------------------------------------------------- /tests/asm/test_DECr_a.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $80 7 | add a ; Sets carry flag <---OJO 8 | ld a, $10 9 | dec a ;Expected: AF = $0F03, Flags Z=0, N=1, H=1, C=1 10 | push af 11 | -------------------------------------------------------------------------------- /tests/asm/test_INCr_a.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $80 7 | add a ; Sets carry flag <---OJO 8 | ld a, $0F 9 | inc a ;Expected: AF = $1003, Flags Z=0, N=0, H=1, C=1 10 | push af 11 | -------------------------------------------------------------------------------- /tests/asm/test_DECr_b.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | or a, a ; Clears all flags 8 | ld b, $01 9 | ld c, $00 10 | dec b 11 | ;Expected BC = $0000, Flags Z=1, N=1, H=0, C=0 12 | push bc 13 | -------------------------------------------------------------------------------- /tests/asm/test_SUBr_e.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 ; 0000 0000 7 | ld e, $80 ; 1000 0000 8 | sub a, e 9 | ;Expected: A=$80, Flags Z=0, N=1, H=0, C=1 10 | ;AF = $8050 11 | push af 12 | -------------------------------------------------------------------------------- /tests/asm/test_INCr_c.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | or a, a ; Clears all flags 8 | ld b, $00 9 | ld c, $FF 10 | inc c 11 | ;Expected BC = $0000 12 | push bc ; Tests BC 13 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_db.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld de, $8782 8 | ld b, $11 9 | or a,a ;borra las banderas 10 | 11 | ld d, b 12 | push de 13 | ;the value expected is $1182 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_dc.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld de, $3634 8 | ld c, $47 9 | or a,a ;borra las banderas 10 | 11 | ld d, c 12 | push de 13 | ;the value expected is $4734 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_dd.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld de, $3634 8 | ld d, $52 9 | or a,a ;borra las banderas 10 | 11 | ld d, d 12 | push de 13 | ;the value expected is $5234 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_de.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld de, $3634 8 | ld d, $52 9 | or a,a ;borra las banderas 10 | 11 | ld d, e 12 | push de 13 | ;the value expected is $3434 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_dh.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld de, $3634 8 | ld h, $33 9 | or a,a ;borra las banderas 10 | 11 | ld d, h 12 | push de 13 | ;the value expected is $3334 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_dl.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld de, $3634 8 | ld l, $66 9 | or a,a ;borra las banderas 10 | 11 | ld d, l 12 | push de 13 | ;the value expected is $6634 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_eb.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld de, $3634 8 | ld b, $47 9 | or a,a ;borra las banderas 10 | 11 | ld e, b 12 | push de 13 | ;the value expected is $3647 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ec.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld de, $3634 8 | ld c, $89 9 | or a,a ;borra las banderas 10 | 11 | ld e, c 12 | push de 13 | ;the value expected is $3689 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ed.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld de, $3634 8 | ld d, $89 9 | or a,a ;borra las banderas 10 | 11 | ld e, d 12 | push de 13 | ;the value expected is $8989 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_eh.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld de, $3634 8 | ld h, $77 9 | or a,a ;borra las banderas 10 | 11 | ld e, h 12 | push de 13 | ;the value expected is $3677 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_el.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld de, $3634 8 | ld l, $08 9 | or a,a ;borra las banderas 10 | 11 | ld e, l 12 | push de 13 | ;the value expected is $3608 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_lb.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $6463 8 | ld b, $60 9 | or a,a ;borra las banderas 10 | 11 | ld l, b 12 | push hl 13 | ;the value expected is $6460 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_lc.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $6463 8 | ld c, $70 9 | or a,a ;borra las banderas 10 | 11 | ld l, c 12 | push hl 13 | ;the value expected is $6470 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ld.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $6463 8 | ld d, $80 9 | or a,a ;borra las banderas 10 | 11 | ld l, d 12 | push hl 13 | ;the value expected is $6480 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_le.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld hl, $6463 8 | ld e, $85 9 | or a,a ;borra las banderas 10 | 11 | ld l, e 12 | push hl 13 | ;the value expected is $6485 14 | -------------------------------------------------------------------------------- /tests/asm/test_RETI.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld hl, int_label 7 | push hl 8 | reti 9 | jp end_label 10 | int_label: 11 | ld hl, $71CE 12 | end_label: 13 | ;expected $71CE 14 | push hl 15 | -------------------------------------------------------------------------------- /tests/asm/test_ADDHLSP.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $1 7 | or a, a 8 | ld a, $0 9 | nop 10 | ld hl, $0001 11 | add hl,sp 12 | or a,l 13 | ;the value expected is $FF00 14 | push af 15 | -------------------------------------------------------------------------------- /tests/asm/test_DECr_d.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | or a, a ; Clears all flags 8 | ld d, $10 9 | ld e, $00 10 | dec d ;Expected: DE = $0F00, Flags Z=0, N=1, H=1, C=0 11 | push de 12 | -------------------------------------------------------------------------------- /tests/asm/test_DECr_h.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | or a, a ; Clears all flags 8 | ld h, $11 9 | ld l, $00 10 | dec h ;Expected: HL = $1000, Flags Z=0, N=1, H=0, C=0 11 | push hl 12 | -------------------------------------------------------------------------------- /tests/asm/test_INCr_d.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | or a, a ; Clears all flags 8 | ld d, $0F 9 | ld e, $00 10 | inc d ;Expected: DE = $1000, Flags Z=0, N=0, H=1, C=0 11 | push de 12 | -------------------------------------------------------------------------------- /tests/asm/test_INCr_h.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | or a, a ; Clears all flags 8 | ld h, $10 9 | ld l, $00 10 | inc h ;Expected: HL = $1100, Flags Z=0, N=0, H=0, C=0 11 | push hl 12 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ea.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $aa 7 | ld de, $3634 8 | ;ld l, $08 9 | or a,a ;borra las banderas 10 | 11 | ld e, a 12 | push de 13 | ;the value expected is $36aa 14 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ee.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld de, $3634 8 | ;ld d, $89 9 | or a,a ;borra las banderas 10 | 11 | ld e, e 12 | push de 13 | ;the value expected is $3634 14 | -------------------------------------------------------------------------------- /tests/asm/test_DECr_c.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | or a, a ; Clears all flags 8 | ld b, $00 9 | ld c, $00 10 | dec c 11 | ;Expected BC = $00FF, Flags Z=0, N=1, H=1, C=0 12 | push bc 13 | -------------------------------------------------------------------------------- /tests/asm/test_DECr_e.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $80 7 | add a ; Sets carry flag <---OJO 8 | ld d, $00 9 | ld e, $F1 10 | dec e ;Expected: DE = $00F0, Flags Z=0, N=1, H=0, C=1 11 | push de 12 | -------------------------------------------------------------------------------- /tests/asm/test_DECr_l.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $80 7 | add a ; Sets carry flag <---OJO 8 | ld h, $00 9 | ld l, $00 10 | dec l ;Expected: HL = $0011, Flags Z=0, N=1, H=1, C=1 11 | push hl 12 | -------------------------------------------------------------------------------- /tests/asm/test_INCr_b_flags.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | or a, a ; Clears all flags 8 | ld b, $00 9 | ld c, $00 10 | inc b 11 | ;Expected Flags Z=0 N=0 H=0 C=0, AF = $0000 12 | push af ; Tests Flags 13 | -------------------------------------------------------------------------------- /tests/asm/test_INCr_e.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $80 7 | add a ; Sets carry flag <---OJO 8 | ld d, $00 9 | ld e, $F0 10 | inc e ;Expected: DE = $00F1, Flags Z=0, N=0, H=0, C=1 11 | push de 12 | -------------------------------------------------------------------------------- /tests/asm/test_INCr_l.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $80 7 | add a ; Sets carry flag <---OJO 8 | ld h, $00 9 | ld l, $FF 10 | inc l ;Expected: HL = $0011, Flags Z=1, N=0, H=1, C=1 11 | push hl 12 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_bd.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $3597 8 | ld d, $40 9 | or a,a ;borra las banderas 10 | 11 | ld b, d 12 | push bc 13 | 14 | ;the value expected is $4097 15 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_be.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $8897 8 | ld e, $35 9 | or a,a ;borra las banderas 10 | 11 | ld b, e 12 | push bc 13 | 14 | ;the value expected is $3597 15 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_bh.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $8897 8 | ld h, $17 9 | or a,a ;borra las banderas 10 | 11 | ld b, h 12 | push bc 13 | 14 | ;the value expected is $1797 15 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_bl.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $8897 8 | ld l, $65 9 | or a,a ;borra las banderas 10 | 11 | ld b, l 12 | push bc 13 | 14 | ;the value expected is $6597 15 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_cd.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $8897 8 | ld d, $71 9 | or a,a ;borra las banderas 10 | 11 | ld c, d 12 | push bc 13 | 14 | ;the value expected is $8871 15 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ce.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $3634 8 | ld e, $71 9 | or a,a ;borra las banderas 10 | 11 | ld c, e 12 | push bc 13 | 14 | ;the value expected is $3671 15 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_ch.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $3634 8 | ld h, $52 9 | or a,a ;borra las banderas 10 | 11 | ld c, h 12 | push bc 13 | 14 | ;the value expected is $3652 15 | -------------------------------------------------------------------------------- /tests/asm/test_LDrr_cl.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld bc, $3634 8 | ld l, $12 9 | or a,a ;borra las banderas 10 | 11 | ld c, l 12 | push bc 13 | 14 | ;the value expected is $3612 15 | -------------------------------------------------------------------------------- /tests/asm/test_JRCn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | or a,a 8 | ld a,$FF 9 | add a,$10 10 | jr c, end 11 | 12 | ld a, $cc 13 | ;the value expected is af=$0F10 14 | end: 15 | push af 16 | -------------------------------------------------------------------------------- /tests/asm/test_SBCr_b.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $fF 7 | ld b, $0f 8 | or a,a 9 | nop 10 | add a, b 11 | nop 12 | sbc a, b 13 | ;Expected Z=0 N=1 H=1 C=1 -- AF =FE70 14 | push af 15 | -------------------------------------------------------------------------------- /tests/asm/test_SBCr_c.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $03 7 | ld c, $fe 8 | or a,a 9 | nop 10 | add a, c 11 | nop 12 | sbc a, c 13 | ;Expected Z=0 N=1 H=1 C=1 -- AF = 0270 14 | push af 15 | -------------------------------------------------------------------------------- /tests/asm/test_SBCr_d.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $02 7 | ld d, $ff 8 | or a,a 9 | nop 10 | add a, d 11 | nop 12 | sbc a, d 13 | ;Expected Z=0 N=1 H=1 C=1 -- AF = 0170 14 | push af 15 | -------------------------------------------------------------------------------- /tests/asm/test_SBCr_e.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld e, $ff 8 | or a,a 9 | nop 10 | add a, e 11 | nop 12 | sbc a, e 13 | ;Expected Z=0 N=1 H=1 C=1 -- AF = 1470 14 | push af 15 | -------------------------------------------------------------------------------- /tests/asm/test_SBCr_h.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $01 7 | ld h, $ff 8 | or a,a 9 | nop 10 | add a, h 11 | nop 12 | sbc a, h 13 | ;Expected Z=1 N=1 H=1 C=1 -- AF = 00F0 14 | push af 15 | -------------------------------------------------------------------------------- /tests/asm/test_SBCr_l.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $99 7 | ld l, $80 8 | or a,a 9 | nop 10 | add a, l 11 | nop 12 | sbc a, l 13 | ;Expected Z=0 N=1 H=0 C=1 -- AF = 9850 14 | push af 15 | -------------------------------------------------------------------------------- /tests/asm/test_ORHL.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld hl, $FFFD 7 | nop 8 | nop 9 | ld e, $23 10 | ld [hl],e 11 | ld a, $dc 12 | 13 | nop 14 | or a,[hl] 15 | 16 | ;af=$ff00 17 | push af 18 | -------------------------------------------------------------------------------- /tests/asm/test_ADCr_b.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $fF 7 | ld b, $0f 8 | or a,a 9 | nop 10 | add a, b 11 | nop 12 | adc a, b 13 | ;the value expected is a=$1E and f=$20 af=$1E20 14 | push af 15 | -------------------------------------------------------------------------------- /tests/asm/test_ADCr_c.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $03 7 | ld c, $fe 8 | or a,a 9 | nop 10 | add a, c 11 | nop 12 | adc a, c 13 | ;the value expected is a=$00 and f=$b0 af=$00b0 14 | push af 15 | -------------------------------------------------------------------------------- /tests/asm/test_ADCr_d.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $02 7 | ld d, $ff 8 | or a,a 9 | nop 10 | add a, d 11 | nop 12 | adc a, d 13 | ;the value expected is a=$01 and f=$30 af=$0130 14 | push af 15 | -------------------------------------------------------------------------------- /tests/asm/test_ADCr_e.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $15 7 | ld e, $ff 8 | or a,a 9 | nop 10 | add a, e 11 | nop 12 | adc a, e 13 | ;the value expected is a=$14 and f=$30 af=$1430 14 | push af 15 | -------------------------------------------------------------------------------- /tests/asm/test_ADCr_h.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $01 7 | ld h, $ff 8 | or a,a 9 | nop 10 | add a, h 11 | nop 12 | adc a, h 13 | ;the value expected is a=$00 and f=$b0 af=$00b0 14 | push af 15 | -------------------------------------------------------------------------------- /tests/asm/test_ADCr_l.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $99 7 | ld l, $80 8 | or a,a 9 | nop 10 | add a, l 11 | nop 12 | adc a, l 13 | ;the value expected is a=$9a and f=$00 af=$9a00 14 | push af 15 | -------------------------------------------------------------------------------- /tests/asm/test_INCr_c_flags.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld a, $00 7 | or a, a ; Clears all flags 8 | ld b, $00 9 | ld c, $FF 10 | inc c 11 | ;Expected Flags Z=1 N=0 H=1 C=1, AF = $00B0 12 | push af ; Tests Flags 13 | -------------------------------------------------------------------------------- /tests/asm/test_RETC.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld hl, carry_label 7 | push hl 8 | ld a, $ff 9 | add $01 10 | ret c 11 | jp end_label 12 | carry_label: 13 | ld a, $71 14 | end_label: 15 | ;expected $71b0 16 | push af 17 | -------------------------------------------------------------------------------- /tests/asm/test_JRn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | 5 | DS $100 6 | ld sp, $FFFE 7 | ld a, $00 8 | or a,a 9 | ld a,$FF 10 | add a,$10 11 | jr hola 12 | cesar: jr end 13 | hola: jr cesar 14 | 15 | ld a, $cc 16 | ;the value expected is af=$0F10 17 | end: 18 | push af 19 | -------------------------------------------------------------------------------- /sim/signals/flow_ids: -------------------------------------------------------------------------------- 1 | 1 LDSPnn 2 | 5 LDHLnn 3 | 9 LDHLDA 4 | 13 MAPcb 5 | 17 JRNZn 6 | 23 LDrn_c 7 | 26 LDrn_a 8 | 29 LDIOCA 9 | 32 INCr 10 | 33 LDHLmr_a 11 | 36 LDIOnA 12 | 43 LDDEnn 13 | 47 LDADEm 14 | 50 CALLnn 15 | 60 LDrn_b 16 | 63 PUSHBC 17 | 70 RLA 18 | 71 POPBC 19 | 77 DECr_b 20 | 78 LDHLIA 21 | 82 INCHL 22 | 83 RET 23 | 89 INCDE 24 | 90 CPn 25 | 98 LDmmA 26 | 184 ADDr_c 27 | -------------------------------------------------------------------------------- /tests/asm/test_INCHLm.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $FFFE 6 | ld hl, $C000 7 | ld a , $62 8 | 9 | ld [hl],a 10 | inc [hl] 11 | 12 | ld a,[hl] 13 | sub $63 14 | jp Z,exit 15 | ld a,$33 16 | exit: 17 | push af 18 | 19 | ;the value expected is $00C0, flag Z affected 20 | -------------------------------------------------------------------------------- /tests/asm/test_CALLNZnn.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld sp, $dfe2 6 | ld hl, $dfe0 7 | ld a, $ff 8 | sub a, $1 9 | call nz, label 10 | ld a, $cc 11 | label: 12 | ld a, [hl+] 13 | ld b, [hl] 14 | ld c, a 15 | 16 | ;the value expected is bc=$0208 17 | ld sp, $fffe 18 | push bc 19 | -------------------------------------------------------------------------------- /sim/signals/dzcpu_uop_cmd: -------------------------------------------------------------------------------- 1 | 0 nop 2 | 1 sma 3 | 2 srm 4 | 3 jcb 5 | 4 z801bop 6 | 5 smw 7 | 6 dec16 8 | 7 bit 9 | 8 addx16 10 | 9 spc 11 | 10 sx16r 12 | 11 sx8r 13 | 12 inc16 14 | 13 srx8 15 | 14 shl 16 | 15 subx16 17 | 16 srx16 18 | 17 seti 19 | 18 cibit 20 | 19 ceti 21 | 20 jint 22 | 21 anda 23 | 22 xorx16 24 | 23 rrot 25 | 24 xora 26 | 25 addx16c 27 | 26 addx16u 28 | 27 shr 29 | 30 shl8 30 | 31 addx16c_ext 31 | -------------------------------------------------------------------------------- /tests/asm/test_LDrHLm_b.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld sp, $FFFe 7 | 8 | ld a, 1 9 | or a,a 10 | 11 | ld a, $48 12 | 13 | ldd [hl],a 14 | ldd [hl],a 15 | ld hl, $FFFD 16 | 17 | nop 18 | nop 19 | ld b,[hl] 20 | 21 | push bc 22 | 23 | ;the value expected is $4800 24 | -------------------------------------------------------------------------------- /tests/asm/test_LDrHLm_c.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld sp, $FFFe 7 | 8 | ld a, 1 9 | or a,a 10 | 11 | ld a, $48 12 | 13 | ldd [hl],a 14 | ldd [hl],a 15 | ld hl, $FFFD 16 | 17 | nop 18 | nop 19 | ld c,[hl] 20 | 21 | push bc 22 | 23 | ;the value expected is $0048 24 | -------------------------------------------------------------------------------- /tests/asm/test_LDrHLm_d.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld sp, $FFFe 7 | 8 | ld a, 1 9 | or a,a 10 | 11 | ld a, $87 12 | 13 | ldd [hl],a 14 | ldd [hl],a 15 | ld hl, $FFFD 16 | 17 | nop 18 | nop 19 | ld d,[hl] 20 | 21 | push de 22 | 23 | ;the value expected is $8700 24 | -------------------------------------------------------------------------------- /tests/asm/test_LDrHLm_e.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld sp, $FFFe 7 | 8 | ld a, 1 9 | or a,a 10 | 11 | ld a, $87 12 | 13 | ldd [hl],a 14 | ldd [hl],a 15 | ld hl, $FFFD 16 | 17 | nop 18 | nop 19 | ld e,[hl] 20 | 21 | push de 22 | 23 | ;the value expected is $0087 24 | -------------------------------------------------------------------------------- /tests/asm/test_LDrHLm_h.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld sp, $FFFe 7 | 8 | ld a, 1 9 | or a,a 10 | 11 | ld a, $37 12 | 13 | ldd [hl],a 14 | ldd [hl],a 15 | ld hl, $FFFD 16 | 17 | nop 18 | nop 19 | ld h,[hl] 20 | 21 | push hl 22 | 23 | ;the value expected is $37fd 24 | -------------------------------------------------------------------------------- /tests/asm/test_LDrHLm_l.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld sp, $FFFe 7 | 8 | ld a, 1 9 | or a,a 10 | 11 | ld a, $37 12 | 13 | ldd [hl],a 14 | ldd [hl],a 15 | ld hl, $FFFD 16 | 17 | nop 18 | nop 19 | ld l,[hl] 20 | 21 | push hl 22 | 23 | ;the value expected is $ff37 24 | -------------------------------------------------------------------------------- /tests/asm/test_LDABCm.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld bc, $FFFD 7 | ld sp, $FFFe 8 | 9 | ld a, 1 10 | or a,a 11 | 12 | ld a, $58 13 | 14 | ldd [hl],a 15 | ldd [hl],a 16 | 17 | ld a, $10 18 | nop 19 | nop 20 | ld a,[bc] 21 | 22 | push af 23 | 24 | ;the value expected is $2000 25 | -------------------------------------------------------------------------------- /tests/asm/test_LDADEm.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld de, $FFFD 7 | ld sp, $FFFe 8 | 9 | ld a, 1 10 | or a,a 11 | 12 | ld a, $20 13 | 14 | ldd [hl],a 15 | ldd [hl],a 16 | 17 | ld a, $10 18 | nop 19 | nop 20 | ld a,[de] 21 | 22 | push af 23 | 24 | ;the value expected is $2000 25 | -------------------------------------------------------------------------------- /tests/asm/test_LDrHLm_a.asm: -------------------------------------------------------------------------------- 1 | SECTION "sec", ROM0 2 | DS $100 3 | jp $200 4 | DS $100 5 | ld hl, $FFFD 6 | ld sp, $FFFe 7 | 8 | ld a, 1 9 | or a,a 10 | 11 | ld a, $60 12 | 13 | ldd [hl],a 14 | ldd [hl],a 15 | ld hl, $FFFD 16 | 17 | ld a, $10 18 | nop 19 | nop 20 | ld a,[hl] 21 | 22 | push af 23 | 24 | ;the value expected is $2000 25 | -------------------------------------------------------------------------------- /script/run_gearboysim.sh: -------------------------------------------------------------------------------- 1 | make clean && time make SIMFLAGS="-DREG_B=0 -DREG_IF=8\'he1 -DREG_TAC=8\'hf8 -DREG_C=19 -DREG_D=0 -DREG_E=216 -DREG_H=1 -DREG_L=77 -DREG_A=1 -DREG_SPL=254 -DREG_SPH=255 -DSKIP_BIOS -DENABLE_INSN_TRACE -DENABLE_CPU_LOG -DCARTRIGDE_DUMP_PATH='\"../tests/cpu_instrs/individual/test_02.dump\"' -DSTOP_AFTER_INSN_COUNT=800000 -DLY_OVERRIDE_PATH='\"ly_values.txt\"'" && vimdiff pgb_trace.dump ../../../tools/Gearboy/platforms/linux/Gearboy/gearboy.dump 2 | -------------------------------------------------------------------------------- /tests/asm/README: -------------------------------------------------------------------------------- 1 | 2 | #Compile the file 3 | rgbasm -o test_INCr_b.obj test_INCr_b.asm 4 | rgblink -m test_INCr_b.map -n test_INCr_b.sym -o test_INCr_b.gb test_INCr_b.obj 5 | hexdump -v test_INCr_b.gb > test_INCr_b.dump 6 | 7 | #format the dump file into single byte and remove the address column 8 | vim ../tests/asm/test_INCr_b.dump 9 | 10 | 11 | #Run the simulation 12 | cd ../../sim 13 | make clean && make SIMFLAGS="-DENABLE_CPU_LOG -DLOAD_CARTRIDGE_FROM_FILE -DCARTRIGDE_DUMP_PATH='\"../tests/asm/test_INCr_b.dump\"' -DSKIP_BIOS" 14 | -------------------------------------------------------------------------------- /script/create_dump_from_hex.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | use strict; 3 | 4 | die "\nUsage: create_dump_from_hex.pl input_file output_file\n" if ($#ARGV + 1 != 2); 5 | die "\n File not found $ARGV[0]\n" if (! -e $ARGV[0]); 6 | my $dump_temp = "temp.dump"; 7 | #Dont read the last line because that is just the last address 8 | `hexdump -v $ARGV[0] | head --lines=-1 > $dump_temp`; 9 | 10 | open my $hexfile, $dump_temp or die "Could not open $dump_temp: $!"; 11 | open my $dumpfile, '>', $ARGV[1] or die "Could not open $ARGV[1]: $!"; 12 | 13 | while( my $line = <$hexfile>) { 14 | $line =~ s/^....... //g ; 15 | $line =~ s/(..)(..) (..)(..)/$2 $1 $4 $3/g; 16 | print $dumpfile $line; 17 | } 18 | 19 | close $hexfile; 20 | -------------------------------------------------------------------------------- /sim/Makefile: -------------------------------------------------------------------------------- 1 | 2 | VERILOGEX = .v # Verilog file extension 3 | 4 | # testbench path TESTBENCH is passed from the command line 5 | SCENEPATH = 6 | TESTBENCH = tb_simple_dzcpu 7 | TESTBENCHPATH = ../tb/${TESTBENCH}$(VERILOGEX) 8 | SOURCEPATH = ../rtl 9 | GPUCONFIGURATIONSCRIPT=../scripts/configure_gpu.pl 10 | INPUTCONFIGURATIONSCRIPT=../scripts/configure_params.pl 11 | #iverilog CONFIG 12 | VERILOG_CMD = iverilog 13 | 14 | # VVP (iverilog runtime engine) 15 | VVP_CMD = vvp 16 | 17 | #Simulation Vars 18 | SIMDIR = . 19 | DUMPTYPE = none 20 | #Viewer 21 | WAVEFORM_VIEWER = gtkwave # Waveform viewer executable 22 | SIMFLAGS = -DSTOP_AFTER_FIRST_FRAME -DLCD_SCXY_DISABLED -DENABLE_CPU_LOG -DENABLE_GPU_LOG 23 | 24 | 25 | all: compile run 26 | 27 | 28 | testbench_checktestbench_check: 29 | ifeq ($(strip $(TESTBENCH)),) 30 | @echo "TESTBENCH not set. Use TESTBENCH=value to set it." 31 | @exit 2 32 | endif 33 | 34 | 35 | 36 | check: 37 | $(VERILOG_CMD) -t null $(FILES) 38 | 39 | # Setup up project directory 40 | new : 41 | echo "Setting up project ${PROJECT}" 42 | mkdir rtl testbench simulation 43 | 44 | 45 | compile : 46 | 47 | 48 | $(VERILOG_CMD) $(SIMFLAGS) -o $(SIMDIR)/$(TESTBENCH) $(TESTBENCHPATH) $(SOURCEPATH)/* -I $(SOURCEPATH)/ -Wall 49 | 50 | 51 | run : 52 | $(VVP_CMD) ./$(TESTBENCH) -$(DUMPTYPE) $(VVP_FLAGS) 53 | 54 | view : 55 | $(WAVEFORM_VIEWER) $(SIMDIR)/$(TESTBENCH).vcd $(SIMDIR)/signals/$(TESTBENCH).gtkw 56 | 57 | clean : 58 | rm -f $(SIMDIR)/$(TESTBENCH) 59 | rm -f *.vcd *.log *.dump 60 | rm -f generated_frames/*.ppm 61 | -------------------------------------------------------------------------------- /sim/resources/tetris_oam_fe00_fe9f.dump: -------------------------------------------------------------------------------- 1 | 80 10 58 00 00 00 00 00 00 00 00 00 00 00 00 00 2 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 9 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 11 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 15 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 17 | ff 55 fe ff ef 00 00 f8 ff ff ff ff ff ff ff e0 18 | 80 bf 74 ff bf ff bf c3 ff bf ff ff bf ff bf ff 19 | ff 00 00 ff 77 fd f7 ff ff ff ff ff ff ff ff ff 20 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 21 | d3 81 00 00 90 00 c0 e4 e4 c4 00 00 ff ff ff ff 22 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 23 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 24 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 25 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 26 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 27 | 00 09 00 00 00 00 43 00 00 00 00 00 00 00 00 00 28 | 00 00 00 00 00 00 3e c0 e0 46 3e 28 3d 20 fd c9 29 | 37 1c 00 00 00 00 13 00 00 00 00 00 00 00 00 00 30 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 31 | 00 07 b8 00 00 00 00 00 00 00 00 00 00 00 00 00 32 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 09 33 | -------------------------------------------------------------------------------- /ucf/pgb_vga.ucf: -------------------------------------------------------------------------------- 1 | # UCF file for the Papilio DUO board 2 | 3 | ## Prohibit the automatic placement of pins that are connected to VCC or GND for configuration. 4 | CONFIG PROHIBIT=P144; 5 | CONFIG PROHIBIT=P69; 6 | CONFIG PROHIBIT=P60; 7 | 8 | NET iClock LOC="P94" | IOSTANDARD=LVTTL | PERIOD=31.25ns; # CLK 9 | NET iReset LOC="P116" | IOSTANDARD=LVTTL; # A0 10 | NET oVgaRed(0) LOC="P98" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D0 11 | NET oVgaRed(1) LOC="P95" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D1 12 | NET oVgaRed(2) LOC="P92" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D2 13 | NET oVgaRed(3) LOC="P87" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D3 14 | NET oVgaGreen(3) LOC="P84" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D4 15 | NET oVgaGreen(2) LOC="P82" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D5 16 | NET oVgaGreen(1) LOC="P80" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D6 17 | NET oVgaGreen(0) LOC="P78" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D7 18 | NET oVgaBlue(3) LOC="P74" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D8 19 | NET oVgaBlue(2) LOC="P66" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D9 20 | NET oVgaBlue(1) LOC="P61" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D10 21 | NET oVgaBlue(0) LOC="P51" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D13 22 | NET oVgaVsync LOC="P48" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D14 23 | NET oVgaHsync LOC="P39" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; # D15 24 | -------------------------------------------------------------------------------- /sim/resources/zelda_game_scene_1_oam_fe00_fe9f.dump: -------------------------------------------------------------------------------- 1 | 00 49 26 00 00 00 00 00 58 46 00 00 58 4e 02 00 2 | 00 00 00 00 00 00 00 00 00 97 a2 40 00 00 00 00 3 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4 | 50 78 58 00 50 80 5a 00 38 50 62 20 38 58 60 20 5 | 00 38 48 00 00 40 4a 00 00 00 00 00 00 00 00 00 6 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 9 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 11 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 15 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 | 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 17 | ff 00 7e ff f9 00 00 f8 ff ff ff ff ff ff ff f2 18 | 80 bf 27 ff bf ff bf 27 ff bf ff ff 9f ff bf ff 19 | ff 40 20 ff 77 ff f7 ff ff ff ff ff ff ff ff ff 20 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 21 | e3 c1 00 00 90 4f c0 e4 1c e4 80 06 ff ff ff ff 22 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 23 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 24 | ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff 25 | 40 30 28 af 4b 6e 08 f3 01 df 25 5e be ee 04 ae 26 | 00 00 00 00 08 00 00 00 46 58 00 00 00 00 03 46 27 | 58 00 00 00 04 00 38 00 00 07 70 00 00 00 00 0d 28 | 1c 00 00 58 00 00 00 00 0d 00 00 00 00 1c 00 1c 29 | 3e c0 e0 46 3e 28 3d 20 fd c9 00 00 00 50 40 00 30 | 00 00 01 00 00 00 00 00 00 00 00 47 00 00 00 00 31 | 9a 00 00 03 00 00 05 e4 00 54 05 3e 38 00 50 38 32 | 03 01 00 00 00 00 a3 10 81 00 54 54 00 00 00 01 33 | -------------------------------------------------------------------------------- /rtl/sound_controller_modules/tb_simple_mx.v: -------------------------------------------------------------------------------- 1 | //Dummy tb for sound mx. 2 | //Tb is only for debug this module. 3 | 4 | `timescale 1ns / 1ps 5 | `include "aDefinitions.v" 6 | `include "collaterals.v" 7 | `include "SoundControllerMX.v" 8 | `include "SoundControllerOSC1.v" 9 | `include "SoundControllerOSC2.v" 10 | 11 | module tb; 12 | 13 | reg clk; 14 | wire clk131k; 15 | wire clk262k; 16 | reg rst; 17 | 18 | wire [4:0] right, left; 19 | reg [7:0] nr50, nr51; 20 | wire [4:0] wOut1, wOut2, wOut3, wOut4; 21 | 22 | always begin 23 | #`CLOCK_CYCLE clk = ~clk; 24 | end 25 | 26 | osc2 o2 27 | ( 28 | .iClock(clk), 29 | .iReset(rst), 30 | .oOut131k(clk131k), 31 | .oOut262k(clk262k) 32 | ); 33 | 34 | SoundCtrlMX # () smx1 ( 35 | .iClock(clk), 36 | .iReset(rst), 37 | .iOsc262k(clk262k), 38 | .iNR50(nr50), 39 | .iNR51(nr51), 40 | .iOut1(wOut1), 41 | .iOut2(wOut2), 42 | .iOut3(wOut3), 43 | .iOut4(wOut4), 44 | 45 | .oSO1(left), 46 | .oSO2(right) 47 | ); 48 | 49 | assign wOut1 = 5'hA; 50 | assign wOut2 = 5'hB; 51 | assign wOut3 = 5'hC; 52 | assign wOut4 = 5'hD; 53 | 54 | integer i; 55 | 56 | initial begin 57 | $dumpfile("dump_sound_mx.vcd"); 58 | $dumpvars(); 59 | $display("tiempo \t left \t right"); 60 | $monitor ("%0d \t %0d \t %0d",$time, left, right); 61 | clk = 0; 62 | rst = 1'b0; 63 | #10 rst = 1'b1; 64 | 65 | //test1 66 | ///* 67 | nr50 = 8'h77; // max volume. 68 | nr51 = 8'hFF; // enable channels. 69 | //*/ 70 | 71 | repeat (2) @ (negedge clk); 72 | rst = 1'b0; 73 | 74 | #50_000; 75 | 76 | $finish; 77 | end 78 | 79 | endmodule 80 | -------------------------------------------------------------------------------- /rtl/aDefinitions.v: -------------------------------------------------------------------------------- 1 | /********************************************************************************** 2 | Theaia, Ray Cast Programable graphic Processing Unit. 3 | Copyright (C) 2009 Diego Valverde (diego.valverde.g@gmail.com) 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | 19 | ***********************************************************************************/ 20 | 21 | 22 | //Verilog provides a `default_nettype none compiler directive. When 23 | //this directive is set, implicit data types are disabled, which will make any 24 | //undeclared signal name a syntax error.This is very usefull to avoid annoying 25 | //automatic 1 bit long wire declaration where you don't want them to be! 26 | `default_nettype none 27 | 28 | //The clock cycle 29 | `define CLOCK_CYCLE 5 30 | `define CLOCK_PERIOD 10 31 | 32 | 33 | //The next section defines the length of the registers, buses and other structures, 34 | //do not change this valued unless you really know what you are doing (seriously!) 35 | `define WIDTH 8 36 | `define LONG_WIDTH 16 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /tb/tb_simple_io.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | `include "io.v" 4 | `include "Defintions.v" 5 | 6 | module tb_simple_io; 7 | 8 | // Inputs 9 | reg Clock; 10 | reg Reset; 11 | 12 | // Outputs 13 | wire [5:0] oP; 14 | wire oIE; 15 | 16 | reg [5:0] rBotcode; 17 | 18 | // Instantiate the Unit Under Test (UUT) 19 | io ionew ( 20 | .Clock(Clock), 21 | .Reset(Reset), 22 | 23 | .iP(rBotcode), 24 | .oP(oP), 25 | .oIE(oIE) 26 | ); 27 | 28 | always 29 | begin 30 | #5 Clock = ! Clock; 31 | 32 | end 33 | 34 | initial begin 35 | $display("Starting GameBoy IO Test\n"); 36 | 37 | $dumpfile("tb_simple_io.vcd"); 38 | $dumpvars(0,tb_simple_io); 39 | 40 | // Initialize Inputs 41 | Clock = 0; 42 | Reset = 0; 43 | 44 | rBotcode = `NOBOT; 45 | 46 | // Wait 100 ns for global reset to finish 47 | #10; 48 | Reset = 1; 49 | #10 50 | Reset = 0; 51 | $display("Reset ready at time %dns", $time); 52 | #10 53 | rBotcode = `NOBOT; 54 | $display("No button pressed at time %dns", $time); 55 | 56 | #10 57 | rBotcode = `A; 58 | #10 59 | rBotcode = `NOBOT; 60 | #10 61 | rBotcode = `B; 62 | #10 63 | rBotcode = `START; 64 | #10 65 | rBotcode = `SELECT; 66 | #10 67 | rBotcode = `UP; 68 | #10 69 | rBotcode = `DOWN; 70 | #10 71 | rBotcode = `LEFT; 72 | #10 73 | rBotcode = `RIGHT; 74 | 75 | // #10 76 | // rBotcode = `A; 77 | // #10 78 | // rBotcode = `NOBOT; 79 | // #10 80 | // rBotcode = `B; 81 | // #10 82 | // rBotcode = `B & `DOWN; 83 | 84 | #100 85 | rBotcode = `NOBOT; 86 | $display("No button pressed at time %dns", $time); 87 | 88 | // All done 89 | #100 90 | $finish(); 91 | 92 | end 93 | 94 | endmodule 95 | -------------------------------------------------------------------------------- /rtl/sound_controller_modules/SoundControllerOSC2.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // pGB, yet another FPGA fully functional and super fun GB classic clone! 4 | // Copyright (C) 2015-2016 Diego Valverde (diego.valverde.g@gmail.com) 5 | // 6 | // This program is free software; you can redistribute it and/or 7 | // modify it under the terms of the GNU General Public License 8 | // as published by the Free Software Foundation; either version 2 9 | // of the License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program; if not, write to the Free Software 18 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | // 20 | //////////////////////////////////////////////////////////////////////////////////// 21 | // Sound module, channel 1. Squate waves with variable timer, frequency, envelope functions and frequency sweep. 22 | //////////////////////////////////////////////////////////////////////////////////// 23 | 24 | module osc2 25 | ( 26 | input wire iClock, 27 | input wire iReset, 28 | output wire oOut131k, 29 | output wire oOut262k 30 | ); 31 | 32 | reg [4:0] rOscCounter; // log2(4194204/131072*2) = log2(16)= 4. Last bit corresponds to the output. 33 | 34 | 35 | always @ (posedge iClock) begin 36 | if (iReset) begin 37 | rOscCounter <= 0; 38 | end 39 | else begin 40 | rOscCounter <= rOscCounter+1; 41 | end 42 | end 43 | 44 | assign oOut131k = rOscCounter[4]; 45 | assign oOut262k = rOscCounter[3]; 46 | 47 | endmodule -------------------------------------------------------------------------------- /rtl/sound_controller_modules/SoundControllerOSC1.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // pGB, yet another FPGA fully functional and super fun GB classic clone! 4 | // Copyright (C) 2015-2016 Diego Valverde (diego.valverde.g@gmail.com) 5 | // 6 | // This program is free software; you can redistribute it and/or 7 | // modify it under the terms of the GNU General Public License 8 | // as published by the Free Software Foundation; either version 2 9 | // of the License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program; if not, write to the Free Software 18 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | // 20 | //////////////////////////////////////////////////////////////////////////////////// 21 | // Sound module, channel 1. Squate waves with variable timer, frequency, envelope functions and frequency sweep. 22 | //////////////////////////////////////////////////////////////////////////////////// 23 | 24 | module osc1 25 | ( 26 | input wire iClock, 27 | input wire iReset, 28 | output wire oOut64, 29 | output wire oOut128, 30 | output wire oOut256 31 | ); 32 | 33 | reg [16:0] rOscCounter; // log2(4194204/256) = log2(4194204)= 14. Last bit correspond to the output. 34 | 35 | 36 | always @ (posedge iClock) begin 37 | if (iReset) begin 38 | rOscCounter <= 0; 39 | end 40 | else begin 41 | rOscCounter <= rOscCounter+1; 42 | end 43 | end 44 | 45 | assign oOut64 = rOscCounter[15]; 46 | assign oOut128 = rOscCounter[14]; 47 | assign oOut256 = rOscCounter[13]; 48 | 49 | endmodule -------------------------------------------------------------------------------- /ucf/pgb_lcd.ucf: -------------------------------------------------------------------------------- 1 | # UCF file for the Papilio DUO board 2 | 3 | ## Prohibit the automatic placement of pins that are connected to VCC or GND for configuration. 4 | CONFIG PROHIBIT=P144; 5 | CONFIG PROHIBIT=P69; 6 | CONFIG PROHIBIT=P60; 7 | 8 | NET iClock LOC="P94" | IOSTANDARD=LVTTL | PERIOD=31.25ns; # CLK 9 | NET iReset LOC="P116" | IOSTANDARD=LVTTL; # A0 10 | NET oLCD_D(0) LOC="P100" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 0 11 | NET oLCD_D(1) LOC="P101" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 1 12 | NET oLCD_D(2) LOC="P102" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 2 13 | NET oLCD_D(3) LOC="P103" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 3 14 | NET oLCD_D(4) LOC="P104" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 4 15 | NET oLCD_D(5) LOC="P105" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 5 16 | NET oLCD_D(6) LOC="P106" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 6 17 | NET oLCD_D(7) LOC="P107" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 7 18 | NET oLCD_D(8) LOC="P108" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 8 19 | NET oLCD_D(9) LOC="P109" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 9 20 | NET oLCD_D(10) LOC="P110" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 10 21 | NET oLCD_D(11) LOC="P111" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 11 22 | NET oLCD_D(12) LOC="P112" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 12 23 | NET oLCD_D(13) LOC="P113" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 13 24 | NET oLCD_D(14) LOC="P114" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DATA 14 25 | NET oLCD_RD(15) LOC="P115" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD RD 26 | NET oLCD_WR(16) LOC="P116" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD W/R 27 | NET oLCD_DC(17) LOC="P117" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD DC 28 | NET oLCD_CS(18) LOC="P118" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=FAST; #LCD CS 29 | -------------------------------------------------------------------------------- /rtl/sound_controller_modules/tb_simple_channel2.v: -------------------------------------------------------------------------------- 1 | //Dummy tb for sound channel 4. 2 | //Tb is only for debug this module. 3 | 4 | `timescale 1ns / 1ps 5 | `include "aDefinitions.v" 6 | `include "collaterals.v" 7 | `include "SoundControllerChannel2.v" 8 | `include "SoundControllerOSC1.v" 9 | `include "SoundControllerOSC2.v" 10 | 11 | module tb; 12 | 13 | reg clk; 14 | wire clk64; 15 | wire clk256; 16 | wire clk131k; 17 | wire clk262k; 18 | reg rst; 19 | wire [4:0] out; 20 | 21 | reg [7:0] nr20; 22 | reg [7:0] nr21; 23 | reg [7:0] nr22; 24 | reg [7:0] nr23; 25 | reg [7:0] nr24; 26 | 27 | always begin 28 | #`CLOCK_CYCLE clk = ~clk; 29 | end 30 | 31 | osc1 o1 32 | ( 33 | .iClock(clk), 34 | .iReset(rst), 35 | .oOut64(clk64), 36 | .oOut256(clk256) 37 | ); 38 | 39 | osc2 o2 40 | ( 41 | .iClock(clk), 42 | .iReset(rst), 43 | .oOut131k(clk131k), 44 | .oOut262k(clk262k) 45 | ); 46 | 47 | 48 | SoundCtrlChannel2 # () scc2 ( 49 | .iClock(clk), 50 | .iReset(rst), 51 | .iOsc64(clk64), 52 | .iOsc256(clk256), 53 | .iOsc262k(clk262k), 54 | .iNR21(nr21), 55 | .iNR22(nr22), 56 | .iNR23(nr23), 57 | .iNR24(nr24), 58 | .oOut(out) 59 | ); 60 | 61 | initial begin 62 | $dumpfile("dump_sound_channel2.vcd"); 63 | $dumpvars(); 64 | $display("tiempo \t\t out2"); 65 | $monitor ("%0d \t\t %0d",$time, out); 66 | clk = 0; 67 | rst = 1'b0; 68 | #10 rst = 1'b1; 69 | 70 | 71 | //test1 72 | /* 73 | nr21 = 8'h03; // length = $03 = 03. 74 | nr22 = 8'hF4; // attenuate envelope, step time = 3. initial value = $F = 15. 75 | nr23 = 8'hBC; // low fre = $BC. 76 | nr24 = 8'h43; // high freq = $3, freq = $3BC = 956. timer enabled. 77 | */ 78 | 79 | //test2 80 | /* 81 | nr21 = 8'h50; // length = $1F = 31. 82 | nr22 = 8'h1C; // amplify envelope, step time = 7. initial value = $2 = 2. 83 | nr23 = 8'hBC; // low freq = $BC. 84 | nr24 = 8'h03; // high freq = $3 , freq = $3BC = 956. time disabled. 85 | */ 86 | 87 | repeat (2) @ (negedge clk); 88 | rst = 1'b0; 89 | #50_000_000; 90 | 91 | $finish; 92 | end 93 | 94 | endmodule -------------------------------------------------------------------------------- /rtl/sound_controller_modules/tb_simple_channel4.v: -------------------------------------------------------------------------------- 1 | //Dummy tb for sound channel 4. 2 | //Tb is only for debug this module. 3 | 4 | `timescale 1ns / 1ps 5 | `include "aDefinitions.v" 6 | `include "collaterals.v" 7 | `include "SoundControllerChannel4.v" 8 | `include "SoundControllerOSC1.v" 9 | `include "SoundControllerOSC2.v" 10 | 11 | module tb; 12 | 13 | reg clk; 14 | wire clk64; 15 | wire clk256; 16 | wire clk131k; 17 | wire clk262k; 18 | reg rst; 19 | wire [4:0] out; 20 | 21 | reg [7:0] nr41; 22 | reg [7:0] nr42; 23 | reg [7:0] nr43; 24 | reg [7:0] nr44; 25 | 26 | 27 | always begin 28 | #`CLOCK_CYCLE clk = ~clk; 29 | end 30 | 31 | osc1 o1 32 | ( 33 | .iClock(clk), 34 | .iReset(rst), 35 | .oOut64(clk64), 36 | .oOut256(clk256) 37 | ); 38 | 39 | osc2 o2 40 | ( 41 | .iClock(clk), 42 | .iReset(rst), 43 | .oOut131k(clk131k), 44 | .oOut262k(clk262k) 45 | ); 46 | 47 | 48 | SoundCtrlChannel4 # () scc2 ( 49 | .iClock(clk), 50 | .iReset(rst), 51 | .iOsc64(clk64), 52 | .iOsc256(clk256), 53 | .iNR41(nr41), 54 | .iNR42(nr42), 55 | .iNR43(nr43), 56 | .iNR44(nr44), 57 | .oOut(out) 58 | ); 59 | 60 | integer i; 61 | 62 | initial begin 63 | // $dumpfile("dump_sound_channel4.vcd"); 64 | // $dumpvars(); 65 | // $display("tiempo \t\t out4"); 66 | // $monitor ("%0d \t\t %0d",$time, out); 67 | clk = 0; 68 | rst = 1'b0; 69 | @(negedge clk) rst = 1'b1; 70 | 71 | //test1 72 | /* 73 | nr41 = 8'h03; // length = $XX, timer disabled 74 | nr42 = 8'hF4; // attenuate envelope, step time = 7. initial value = $F = 15. 75 | nr43 = 8'h52; // div ratio = 3. lfrs = 15 stages , shifts = 3 76 | nr44 = 8'h40; // timer disabled. 77 | */ 78 | 79 | //test2 80 | ///* 81 | nr41 = 8'h00; // length = $XX, timer disabled 82 | nr42 = 8'h1C; // amplify envelope, step time = 7. initial value = $2 = 2. 83 | nr43 = 8'h52; // div ratio = 3. lfrs = 7 stages , shifts = 3 84 | nr44 = 8'h00; // timer disabled. 85 | //*/ 86 | 87 | repeat (2) @ (negedge clk); 88 | rst = 1'b0; 89 | // #50_000_000; 90 | for ( i = 0; i < 10000; i = i+1) begin 91 | #5120 $display ("%0d, ", out); 92 | end 93 | 94 | $finish; 95 | end 96 | 97 | endmodule 98 | -------------------------------------------------------------------------------- /rtl/interrupts.v: -------------------------------------------------------------------------------- 1 | module interrupt_controller 2 | ( 3 | input wire iClock, 4 | input wire iReset, 5 | 6 | input wire iMcuWe, 7 | input wire [3:0] iMcuRegSelect, //control register select comes from cpu 8 | input wire [7:0] iMcuWriteData, //what does the cpu want to write 9 | 10 | output wire[7:0] oInterruptEnableRegister, 11 | output wire[7:0] oInterruptFlag, 12 | 13 | 14 | input wire [7:0] iInterruptRequest, 15 | output reg [7:0] oInterruptResquestPending 16 | ); 17 | 18 | 19 | 20 | 21 | //////////////////////////////////////////////// 22 | // 23 | // Register 0xFFFF: IE. Interrupt Enable register 24 | // reset to 0 whenever written to 25 | // 26 | // Bit 0: V-Blank Interrupt Enable (INT 40h) (1=Enable) 27 | // Bit 1: LCD STAT Interrupt Enable (INT 48h) (1=Enable) 28 | // Bit 2: Timer Interrupt Enable (INT 50h) (1=Enable) 29 | // Bit 3: Serial Interrupt Enable (INT 58h) (1=Enable) 30 | // Bit 4: Joypad Interrupt Enable (INT 60h) (1=Enable) 31 | //////////////////////////////////////////////// 32 | 33 | wire wWeInterrutpRegister; 34 | assign wWeInterrutpRegister = (iMcuWe & iMcuRegSelect == 4'h0) ? 1'b1 : 1'b0; 35 | FFD_POSEDGE_SYNCRONOUS_RESET # ( 8 )FF_IE( 36 | iClock, iReset , wWeInterrutpRegister , iMcuWriteData, oInterruptEnableRegister ); 37 | 38 | //////////////////////////////////////////////// 39 | // 40 | // Register 0xFF0F: IF. Interrupt Flag 41 | // Bit 0: V-Blank Interrupt Request (INT 40h) (1=Request) 42 | // Bit 1: LCD STAT Interrupt Request (INT 48h) (1=Request) 43 | // Bit 2: Timer Interrupt Request (INT 50h) (1=Request) 44 | // Bit 3: Serial Interrupt Request (INT 58h) (1=Request) 45 | // Bit 4: Joypad Interrupt Request (INT 60h) (1=Request) 46 | //////////////////////////////////////////////// 47 | 48 | wire wWeInterruptFlag; 49 | assign wWeInterruptFlag = (iMcuWe & iMcuRegSelect == 4'hf) ? 1'b1: 1'b0; 50 | FFD_POSEDGE_SYNCRONOUS_RESET_INIT # ( 8 )FF_IF( 51 | iClock, iReset | wWeInterruptFlag , |iInterruptRequest , iMcuWriteData, iInterruptRequest, oInterruptFlag ); 52 | 53 | 54 | wire [7:0] wPendingInterrupts; 55 | assign wPendingInterrupts = oInterruptFlag & oInterruptEnableRegister; 56 | 57 | 58 | always @ (*) 59 | begin 60 | case (wPendingInterrupts) 61 | 8'h1: oInterruptResquestPending = 8'b00000001; //VBLANK 62 | 8'h2: oInterruptResquestPending = 8'b00000010; //LCDSTAT 63 | 8'h4: oInterruptResquestPending = 8'b00000100; //TIMER 64 | 8'h8: oInterruptResquestPending = 8'b00001000; //SERIAL 65 | 8'h10: oInterruptResquestPending = 8'b00010000; //JOYPAD 66 | default: oInterruptResquestPending = 8'b0; 67 | endcase 68 | end 69 | 70 | endmodule 71 | -------------------------------------------------------------------------------- /rtl/sound_controller_modules/tb_simple_channel3.v: -------------------------------------------------------------------------------- 1 | //Dummy tb for sound channel 4. 2 | //Tb is only for debug this module. 3 | 4 | `timescale 1ns / 1ps 5 | `include "aDefinitions.v" 6 | `include "collaterals.v" 7 | `include "SoundControllerChannel3.v" 8 | `include "SoundControllerOSC1.v" 9 | `include "SoundControllerOSC2.v" 10 | 11 | module tb; 12 | 13 | reg clk; 14 | wire clk256; 15 | wire clk262k; 16 | reg rst; 17 | wire [4:0] out; 18 | 19 | reg [7:0] nr30; 20 | reg [7:0] nr31; 21 | reg [7:0] nr32; 22 | reg [7:0] nr33; 23 | reg [7:0] nr34; 24 | 25 | always begin 26 | #`CLOCK_CYCLE clk = ~clk; 27 | end 28 | 29 | osc1 o1 30 | ( 31 | .iClock(clk), 32 | .iReset(rst), 33 | .oOut256(clk256) 34 | ); 35 | 36 | osc2 o2 37 | ( 38 | .iClock(clk), 39 | .iReset(rst), 40 | .oOut262k(clk262k) 41 | ); 42 | 43 | SoundCtrlChannel3 # () scc3 ( 44 | .iClock(clk), 45 | .iReset(rst), 46 | .iOsc256(clk256), 47 | .iOsc262k(clk262k), 48 | .iNR30(nr30), 49 | .iNR31(nr31), 50 | .iNR32(nr32), 51 | .iNR33(nr33), 52 | .iNR34(nr34), 53 | .oOut(out) 54 | ); 55 | 56 | integer i; 57 | 58 | initial begin 59 | // $dumpfile("dump_sound_channel3.vcd"); 60 | // $dumpvars(); 61 | // $display("tiempo \t\t out3"); 62 | // $monitor ("%0d \t\t %0d",$time, out); 63 | clk = 0; 64 | rst = 1'b0; 65 | #10 rst = 1'b1; 66 | 67 | //test1 68 | ///* 69 | nr30 = 8'h80; 70 | nr31 = 8'h8A; 71 | nr32 = 8'h20; 72 | nr33 = 8'hBC; 73 | nr34 = 8'h43; // timer mode 74 | 75 | repeat (2) @ (negedge clk); 76 | rst = 1'b0; 77 | 78 | for ( i = 0; i < 5000; i = i+1) begin 79 | #5120 $display ("%0d, ", out); 80 | end 81 | 82 | nr30 = 8'h80; 83 | nr31 = 8'h00; 84 | nr32 = 8'h40; // A = A/2 85 | nr33 = 8'hBC; // Lower frequency 86 | nr34 = 8'hC2; // timed mode 87 | 88 | repeat (2) @ (negedge clk); 89 | nr34 = 8'h02; // timed mode 90 | 91 | for ( i = 0; i < 5000; i = i+1) begin 92 | #5120 $display ("%0d, ", out); 93 | end 94 | 95 | //#25_000_000; // 596ms, dmg_clock 96 | //*/ 97 | 98 | //test2 99 | /* 100 | nr30 = 8'h80; 101 | nr31 = 8'h8A; // L2 102 | nr32 = 8'h20; 103 | nr33 = 8'hBC; 104 | nr34 = 8'h43; // timer mode 105 | 106 | repeat (2) @ (negedge clk); 107 | rst = 1'b0; 108 | #25_000_000; 109 | 110 | nr30 = 8'h80; 111 | nr31 = 8'h00; // L2 112 | nr32 = 8'h60; // A = A/4 113 | nr33 = 8'hBC; // Lower frequency 114 | nr34 = 8'hC2; 115 | 116 | repeat (2) @ (negedge clk); 117 | nr34 = 8'h02; // continuous mode 118 | #25_000_000; 119 | */ 120 | 121 | $finish; 122 | end 123 | 124 | endmodule 125 | -------------------------------------------------------------------------------- /cad/papiGB.scad: -------------------------------------------------------------------------------- 1 | 2 | //All distances are in milimeters! 3 | 4 | 5 | case_w=140; 6 | case_h=case_w*0.5714; 7 | case_thickness=case_w/70; 8 | case_depth = case_w*0.12; 9 | 10 | //--------------------------------------------------------------------------------- 11 | module papiGB_case_top() 12 | { 13 | 14 | //Let's start by setting some basic sizes 15 | 16 | 17 | lcd_w= case_w*0.535; 18 | lcd_h= case_h*0.6875; 19 | 20 | lcd_x = (case_w-lcd_w)/2; 21 | lcd_y = (case_h-lcd_h)/2; 22 | pad_diameter = case_w/14; 23 | button_diameter =case_w/28; 24 | 25 | 26 | pad_pos = [ lcd_x/2, (2*case_h)/3, 0]; 27 | 28 | button_a_pos = [ case_w - (case_w - lcd_w)/5, (7*case_h)/10, 0]; 29 | button_b_pos = [ case_w - (case_w - lcd_w)/3, (5*case_h)/10, 0]; 30 | 31 | button_start_pos = [ lcd_x/4, (2*case_h)/10, 0]; 32 | button_select_pos = [ lcd_x/4, (3*case_h)/10, 0]; 33 | 34 | speaker_hole_0 = [ case_w - (case_w - lcd_w)/2.75, (2*case_h)/10, 0]; 35 | 36 | speaker_hole_1 = [ case_w - (case_w - lcd_w)/2.5, (2.3*case_h)/10, 0]; 37 | 38 | speaker_hole_2 = [ case_w - (case_w - lcd_w)/2.5, (2.6*case_h)/10, 0]; 39 | 40 | speaker_hole_3 = [ case_w - (case_w - lcd_w)/2.75, (2.9*case_h)/10, 0]; 41 | 42 | 43 | difference() 44 | { 45 | //Create the enclosure body 46 | color("LightGray") square([case_w,case_h]); 47 | 48 | 49 | //Create the hole to place the LCD 7.5mm x 5.5mm 50 | translate([lcd_x, lcd_y, 0]) square([lcd_w, lcd_h ]); 51 | 52 | 53 | //Create the hole to place the joystick 54 | translate(pad_pos) scale(pad_diameter) circle( $fn=8 ); 55 | 56 | //Place the A button 57 | translate(button_a_pos) scale(button_diameter) circle( $fn=16 ); 58 | 59 | //Place the B button 60 | translate(button_b_pos) scale(button_diameter) circle( $fn=16 ); 61 | 62 | //Place the start button 63 | translate(button_start_pos) scale(button_diameter) square([3,1]); 64 | 65 | //Place the select button 66 | translate(button_select_pos) scale(button_diameter) square([3,1]); 67 | 68 | //Place the speaker holes 69 | translate(speaker_hole_0) scale(button_diameter) square([3,0.20]); 70 | translate(speaker_hole_1) scale(button_diameter) square([4,0.20]); 71 | translate(speaker_hole_2) scale(button_diameter) square([4,0.20]); 72 | translate(speaker_hole_3) scale(button_diameter) square([3,0.20]); 73 | 74 | 75 | }; 76 | }; 77 | //--------------------------------------------------------------------------------- 78 | module papiGB_case_side() 79 | { 80 | 81 | 82 | 83 | difference() 84 | { 85 | // cubeX(size=[case_w,case_h,case_depth],radius=10,center=true ); 86 | 87 | cube(size=[case_w,case_h,case_depth]); 88 | translate( [case_thickness,case_thickness,-1] ) 89 | cube(size=[case_w-2*case_thickness,case_h-2*case_thickness,case_depth+case_thickness]); 90 | }; 91 | } 92 | //--------------------------------------------------------------------------------- 93 | //Instantiate the case 94 | papiGB_case_top(); 95 | translate([0,0,-case_depth]) papiGB_case_side(); 96 | 97 | -------------------------------------------------------------------------------- /script/check_bios_log.py: -------------------------------------------------------------------------------- 1 | import re 2 | from sys import argv 3 | 4 | reg_names = ['SP', 'B', 'C', 'D', 'E', 'H', 'L', 'A', 'Flags'] 5 | # PC SP B C D E H L A Flags 6 | # 0x0000 LD SP, $0xFFFE 7 | bios_checker = {'00000003': ['fffe', '*', '*', '*', '*', '*', '*', '*', '*'], 8 | # 0x0003 XOR A 9 | '00000004': ['*', '*', '*', '*', '*', '*', '*', '00', '*'], 10 | # 0x000C LD HL, $0xFF26 # load 0xFF26 to HL 11 | '0000000f': ['*', '*', '*', '*', '*', 'ff', '26', '*', '*'], 12 | # 0x000F LD C, $0x11 # load 0x11 to C 13 | '00000011': ['*', '*', '11', '*', '*', '*', '*', '*', '*'], 14 | # 0x0011 LD A, $0x80 # load 0x80 to A 15 | '00000013': ['*', '*', '*', '*', '*', '*', '*', '80', '*'], 16 | # 0x0013 LD (HL-), A # load A [HL], HL-- 17 | '00000015': ['*', '*', '*', '*', '*', 'ff', '25', '*', '*'], 18 | # 0x0015 INC C # increment C register 19 | '00000016': ['*', '*', '12', '*', '*', '*', '*', '*', '*'], 20 | # 0x0016 LD A, $0xF3 # load 0xF3 to A 21 | '00000018': ['*', '*', '*', '*', '*', '*', '*', 'f3', '*'], 22 | # 0x001A LD A, $0x77 # load 0x77 to A 23 | '0000001c': ['*', '*', '*', '*', '*', '*', '*', '77', '*'], 24 | # 0x001D LD A, $0xFC # A represents the color number mappings 25 | '0000001f': ['*', '*', '*', '*', '*', '*', '*', 'fc', '*'], 26 | # 0x0021 LD DE, $0x0104 # pointer to Nintendo Logo 27 | '00000024': ['*', '*', '*', '01', '04', '*', '*', '*', '*'], 28 | # 0x0024 LD HL, $0x8010 # pointer to Video RAM 29 | '00000027': ['*', '*', '*', '*', '*', '80', '10', '*', '*'], 30 | # 0x0027 LD A, (DE) # load next byte from Nintendo Logo 31 | '00000028': ['*', '*', '*', '*', '*', '*', '*', 'ce', '*'], 32 | # 0x0028 CALL $0x0095 # decompress, scale 33 | # 0x0095 LD C, A # load A to C 34 | '00000096': ['*', '*', 'ce', '*', '*', '*', '*', 'ce', '*'], 35 | # 0x0096 LD B, $0x4 # 36 | '00000098': ['*', '04', '*', '*', '*', '*', '*', '*', '*'], 37 | # 0x0099 RL C # rotate left register C through carry flag 38 | '0000009b': ['*', '*', '9c', '*', '*', '*', '*', '*', '00010000'], 39 | } 40 | 41 | 42 | script, filename = argv 43 | 44 | with open(filename, "r") as file: 45 | for line in file: 46 | if (not re.match("^\[regs\]", line)): 47 | continue 48 | 49 | regs = re.split("\s+", line) 50 | pc = regs[1] 51 | regs = regs[2:] 52 | 53 | if (pc not in bios_checker): 54 | continue 55 | 56 | print(line) 57 | for reg, value, name in zip(regs, bios_checker[pc], reg_names): 58 | if (value == '*'): 59 | continue 60 | 61 | print(("pc {0}. {1} {2} found {3}").format(pc, name, value, reg)) 62 | if (value != reg): 63 | raise Exception(("Register mismatch\n")) 64 | -------------------------------------------------------------------------------- /rtl/sound_controller_modules/tb_simple_channel1.v: -------------------------------------------------------------------------------- 1 | //Dummy tb for sound channel 1. 2 | //Tb is only for debug this module. 3 | 4 | `timescale 1ns / 1ps 5 | `include "aDefinitions.v" 6 | `include "collaterals.v" 7 | `include "SoundControllerChannel1.v" 8 | `include "SoundControllerOSC1.v" 9 | `include "SoundControllerOSC2.v" 10 | 11 | module tb; 12 | 13 | reg clk; 14 | wire clk64; 15 | wire clk128; 16 | wire clk256; 17 | wire clk131k; 18 | wire clk262k; 19 | reg rst; 20 | wire [4:0] out; 21 | 22 | reg [7:0] nr10; 23 | reg [7:0] nr11; 24 | reg [7:0] nr12; 25 | reg [7:0] nr13; 26 | reg [7:0] nr14; 27 | 28 | always begin 29 | #`CLOCK_CYCLE clk = ~clk; 30 | end 31 | 32 | osc1 o1 33 | ( 34 | .iClock(clk), 35 | .iReset(rst), 36 | .oOut64(clk64), 37 | .oOut128(clk128), 38 | .oOut256(clk256) 39 | ); 40 | 41 | osc2 o2 42 | ( 43 | .iClock(clk), 44 | .iReset(rst), 45 | .oOut131k(clk131k), 46 | .oOut262k(clk262k) 47 | ); 48 | 49 | SoundCtrlChannel1 # () scc1 ( 50 | .iClock(clk), 51 | .iReset(rst), 52 | .iOsc64(clk64), 53 | .iOsc128(clk128), 54 | .iOsc256(clk256), 55 | .iOsc262k(clk262k), 56 | .iNR10(nr10), 57 | .iNR11(nr11), 58 | .iNR12(nr12), 59 | .iNR13(nr13), 60 | .iNR14(nr14), 61 | .oOut(out) 62 | ); 63 | 64 | 65 | integer i; 66 | 67 | initial begin 68 | //$dumpfile("dump_sound_channel1.vcd"); 69 | //$dumpvars(); 70 | //$display("tiempo \t\t out1"); 71 | //$monitor ("%0d \t\t %0d",$time, out); 72 | clk = 0; 73 | rst = 1'b0; 74 | #10 rst = 1'b1; 75 | 76 | //test1 77 | ///* 78 | nr10 = 8'h00; // disable sweep control. 79 | nr11 = 8'h1F; // length = $1F = 31. 80 | nr12 = 8'hF4; // attenuate envelope, step time = 4. initial value = $F = 15. 81 | nr13 = 8'hBC; // low fre = $BC. 82 | nr14 = 8'h03; // high freq = $3, freq = $3BC = 956. timer disabled. 83 | //*/ 84 | 85 | //test2 86 | /* 87 | nr10 = 8'h00; // disable sweep control 88 | nr11 = 8'h01; // length = $01 = 01. 89 | nr12 = 8'h1C; // amplify envelope, step time = 7. initial value = $2 = 2. 90 | nr13 = 8'hBC; // low freq = $BC. 91 | nr14 = 8'h43; // high freq = $3 , freq = $3BC = 956. time enabled. 92 | */ 93 | 94 | //test3 95 | /* 96 | nr10 = 8'h59; // subtraction sweep, n= 1. sweep time = 3. 97 | nr11 = 8'h1F; // length = $1F = 31. 98 | nr12 = 8'hF0; // disable envelope, step time = 7. initial value = $F = 15. 99 | nr13 = 8'hD0; // low freq = $0D 100 | nr14 = 8'h07; // high freq = $7, freq = $70D = 1805. timer disabled. 101 | */ 102 | 103 | //test4 104 | /* 105 | nr10 = 8'h51; // addition sweep, n = 1. sweep time = 3. 106 | nr11 = 8'h1F; // length = $1F = 31 107 | nr12 = 8'hF0; // disable envelope, step time = 3. initial value = $2 = 2. 108 | nr13 = 8'h30; // low freq = $30. 109 | nr14 = 8'h00; // high freq = $0 , freq = $030 = 48. timer disabled. 110 | */ 111 | 112 | repeat (2) @ (negedge clk); 113 | rst = 1'b0; 114 | 115 | for ( i = 0; i < 10000; i = i+1) begin 116 | #5120 $display ("%0d, ", out); 117 | end 118 | // #50_000_000; 119 | 120 | $finish; 121 | end 122 | 123 | endmodule 124 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![alt text](https://travis-ci.org/diegovalverde/papiGB.svg?branch=master) 2 | 3 | # papiGB 4 | Game Boy Classic fully functional FPGA implementation from scratch 5 | 6 | ###Requirements 7 | 8 | `sudo apt-get install iverilog gtkwave` 9 | 10 | 11 | ##Compiling code 12 | `cd sim/` 13 | 14 | `make compile` 15 | 16 | ##Running a simulation 17 | 18 | `cd sim/` 19 | 20 | `make run` 21 | 22 | Once the simulation completes, the following ASCII files are generated under the sim/ folder: 23 | 24 | * pgb_cpu.log : Z80 macro instructions and their corresponding micro-code flows 25 | * pgb_gpu.log: GPU micro code dump 26 | * generated_frames/*.ppm : PPM representation of the video buffer frames at the time the simulation ended. (Open it with gimp) 27 | * papi_vram_8000_8fff.dump : Memory dump for the Tile set region 0 28 | * papi_vram_9800_9bff.dump : Memory dump for the Tile map region 0 29 | * tb_simple_dzcpu : Simulation testbench executable 30 | 31 | Simulations will not automatically generate a VCD dump file. 32 | To generate a VCD dump do: 33 | 34 | `make DUMPTYPE=vcd` 35 | 36 | ##Simulation Options 37 | To control additional simulation options, use the SIMFLAGS flag. Valid values are: 38 | 39 | * ``-DSTOP_AFTER_FIRST_FRAME`` : The simulation will stop once the first frame has been generated under the sim/generated_frames/ folder 40 | * ``-DENABLE_CPU_LOG`` : Enables pgb_cpu.log generation (enabled by default) 41 | * ``-DENABLE_GPU_LOG`` : Enables pgb_cpu.log generation (enabled by default) 42 | * ``-DCARTRIGDE_DUMP_PATH`` : When LOAD_CARTRIDGE_FROM_FILE is set, then this flag specifies the path to the dump file 43 | * ``-DSKIP_BIOS`` : Skips the BIOS code, first 256 instructions, effectively jumping directly to 0x100 44 | * ``-DDISABLE_CPU``: Disables the CPU from running 45 | * ``-DVMEM_DUMP_PATH``: When LOAD_VMEM_DUMP is set, then this flag specifies the path to the VMEME dump file. 46 | * ``-DSIMULATION_TIME_OUT``: Specify a simulation timeout in nanoseconds 47 | Example: 48 | 49 | The following command will stop the simulation after the first frame, will generate GPU log, but will not generate CPU log. 50 | 51 | `make SIMFLAGS="-DSTOP_AFTER_FIRST_FRAME -DENABLE_GPU_LOG"` 52 | 53 | The following command will simulate RTL using a cartrigde file: 54 | 55 | `make SIMFLAGS=" -DCARTRIGDE_DUMP_PATH='\"resources/tetris.dump\"'"` 56 | 57 | The following command will disable the CPU and load VMEM data from a dump file: 58 | 59 | `make SIMFLAGS="-DDISABLE_CPU -DVMEM_DUMP_PATH='\"resources/tetris_vmem_8000_9fff.dump\"' -DENABLE_GPU_LOG -DSTOP_AFTER_FIRST_FRAME"` 60 | 61 | 62 | ##Looking at simulation results 63 | 64 | `cd sim/` 65 | 66 | `make view` 67 | 68 | ##Cleaning up simulation files. 69 | This also erases the vcd and the log files! 70 | 71 | `make clean` 72 | 73 | ##Installing a game boy assembly 74 | 75 | RGBDS is a great gameboy assembly (https://www.anjbe.name/rgbds/) 76 | 77 | To install it do: 78 | 79 | `git clone https://github.com/bentley/rgbds/` 80 | 81 | `cd rgbds` 82 | 83 | `sudo apt-get install bison flex` 84 | 85 | `make` 86 | 87 | `sudo make install` 88 | 89 | To compile an assebly program called test_INCr_b.asm do: 90 | 91 | `rgbasm -o test_INCr_b.obj test_INCr_b.asm` 92 | 93 | `rgblink -m test_INCr_b.map -n test_INCr_b.sym -o test_INCr_b.gb test_INCr_b.obj` 94 | 95 | The use hexdump to get the ASCII hex dump to load into the RTL simulation: 96 | 97 | `hexdump -v test_INCr_b.gb > test_INCr_b.hex` 98 | 99 | 100 | -------------------------------------------------------------------------------- /rtl/sound_controller_modules/SoundControllerMX.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // pGB, yet another FPGA fully functional and super fun GB classic clone! 4 | // Copyright (C) 2015-2016 Diego Valverde (diego.valverde.g@gmail.com) 5 | // 6 | // This program is free software; you can redistribute it and/or 7 | // modify it under the terms of the GNU General Public License 8 | // as published by the Free Software Foundation; either version 2 9 | // of the License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program; if not, write to the Free Software 18 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | // 20 | //////////////////////////////////////////////////////////////////////////////////// 21 | // Sound module, channel 2. Squate waves with variable timmer, configurable frequency and envelope functions. 22 | //////////////////////////////////////////////////////////////////////////////////// 23 | 24 | module SoundCtrlMX //parameters 25 | ( 26 | input wire iClock, //CPU CLOCK, 4194304Hz 27 | input wire iReset, 28 | input wire iOsc262k, //OSC2 clock 131072Hz 29 | 30 | input wire [4:0] iOut1, // Channel 1. 31 | input wire [4:0] iOut2, // Channel 2. 32 | input wire [4:0] iOut3, // Channel 3. 33 | input wire [4:0] iOut4, // Channel 4. 34 | 35 | input wire [7:0] iNR50, // Left/Right enable + Left/Right volume. 36 | input wire [7:0] iNR51, // Enable channel 1/2/3/4 in Left/Right. 37 | 38 | output reg [4:0] oSO1, // Left channel. 39 | output reg [4:0] oSO2, // Right channel. 40 | 41 | output wire [1:0] oChSel, 42 | output wire oChClk 43 | ); 44 | 45 | reg [7:0] rNR50, rNR51; 46 | reg [4:0] rSO1_PRE, rSO2_PRE; 47 | reg rSer_clk; // 8kHz clock, used for serializer. 48 | reg [1:0] rSer_sel; // Indicates which channel data were sent. 49 | 50 | 51 | //Registers load 52 | always @ (posedge iClock) begin 53 | if (iReset) begin 54 | rNR50 <= iNR50; 55 | rNR51 <= iNR51; 56 | rSer_sel <= 2'b0; 57 | rSer_clk <= 1'b0; 58 | 59 | rSO1_PRE <= 5'd15; 60 | rSO2_PRE <= 5'd15; 61 | 62 | end 63 | end 64 | 65 | //Serializer 66 | always @ (posedge iOsc262k) begin 67 | rSer_clk <= ~rSer_clk; 68 | rSer_sel <= (~rSer_clk) ? rSer_sel + 1 : rSer_sel; 69 | end 70 | 71 | //Volume control 72 | always @ (*) begin 73 | 74 | case (rSer_sel) 75 | 2'd0: begin 76 | rSO1_PRE = (rNR51[0]) ? iOut1 : 5'd15; 77 | rSO2_PRE = (rNR51[4]) ? iOut1 : 5'd15; 78 | end 79 | 2'd1: begin 80 | rSO1_PRE = (rNR51[1]) ? iOut2 : 5'd15; 81 | rSO2_PRE = (rNR51[5]) ? iOut2 : 5'd15; 82 | end 83 | 2'd2: begin 84 | rSO1_PRE = (rNR51[2]) ? iOut3 : 5'd15; 85 | rSO2_PRE = (rNR51[6]) ? iOut3 : 5'd15; 86 | end 87 | 2'd3: begin 88 | rSO1_PRE = (rNR51[3]) ? iOut4 : 5'd15; 89 | rSO2_PRE = (rNR51[7]) ? iOut4 : 5'd15; 90 | end 91 | default: begin 92 | rSO1_PRE = 5'dX; 93 | rSO2_PRE = 5'dX; 94 | end 95 | endcase 96 | 97 | oSO1 = rSO1_PRE >> (3'd7-rNR50[2:0]); 98 | oSO2 = rSO1_PRE >> (3'd7-rNR50[6:4]); 99 | 100 | end 101 | 102 | assign oChSel = rSer_sel; 103 | assign oChClk = rSer_clk; 104 | 105 | endmodule 106 | -------------------------------------------------------------------------------- /rtl/io.v: -------------------------------------------------------------------------------- 1 | 2 | `timescale 1ns / 1ps 3 | 4 | `include "collaterals.v" 5 | 6 | module io 7 | ( 8 | input wire Clock, 9 | input wire Reset, 10 | input wire [5:0] iP, //Pressed button 11 | output wire [5:0] oP, //[5:4] most be triggered before [3:0] 12 | output wire oIE //Enable interruption $FFFF 13 | ); 14 | 15 | wire [5:0] wiPlast; 16 | wire [5:0] woPlast; 17 | wire [5:0] wXnorAresult; 18 | wire [5:0] wXnorBresult; 19 | wire [5:0] wXnorCresult; 20 | wire [5:0] wMuxAresult; 21 | wire [5:0] wMuxBresult; 22 | 23 | reg [5:0] rP; 24 | `ifdef PRESS_A_KEY_AFTER 25 | FFD_POSEDGE_SYNCRONOUS_RESET # ( 6 ) FFD_oHack 26 | ( 27 | .Clock(Clock), 28 | .Reset(Reset), 29 | .Enable(1'b1), 30 | .D(6'b111101), 31 | .Q(oP) 32 | ); 33 | `else 34 | assign oP = rP; 35 | `endif 36 | 37 | FFD_POSEDGE_SYNCRONOUS_RESET # ( 6 ) FFD_oP 38 | ( 39 | .Clock(Clock), 40 | .Reset(Reset), 41 | .Enable(1'b1), 42 | .D(oP), 43 | .Q(woPlast) 44 | ); 45 | 46 | FFD_POSEDGE_SYNCRONOUS_RESET # ( 6 ) FFD2_iP 47 | ( 48 | .Clock(Clock), 49 | .Reset(Reset), 50 | .Enable(1'b1), 51 | .D(iP), 52 | .Q(wiPlast) 53 | ); 54 | 55 | XNOR # ( 6 ) XOR1 56 | ( 57 | .inA(iP), 58 | .inB(woPlast), 59 | .out(wXnorAresult) 60 | ); 61 | 62 | XNOR # ( 6 ) XNOR2 63 | ( 64 | .inA(iP), 65 | .inB(wiPlast), 66 | .out(wXnorBresult) 67 | ); 68 | 69 | MUX2 # ( 6 ) MUX1 70 | ( 71 | .select(&iP), 72 | .inA(wXnorAresult), 73 | .inB(iP), 74 | .out(wMuxAresult) 75 | ); 76 | 77 | // assign wMuxBresult = (woPlast == iP) ? iP : wMuxAresult; 78 | MUX2 # ( 6 ) MUX2 79 | ( 80 | .select(&wXnorAresult), 81 | .inA(wMuxAresult), 82 | .inB(iP), 83 | .out(wMuxBresult) 84 | ); 85 | 86 | // assign oIE = (&oP == 0) ? 1 : 0; 87 | MUX2 # ( 1 ) MUX3 88 | ( 89 | .select(&oP), 90 | .inA(1), 91 | .inB(0), 92 | .out(oIE) 93 | ); 94 | 95 | 96 | always @ ( * ) 97 | begin 98 | case (wMuxBresult) 99 | // one button is pressed. Or two buttons pressed with diferrent ending and type. Ex. Left + Start. Or juest A. 100 | 6'b101110, 6'b101101, 6'b101011, 6'b100111, 6'b011110, 6'b011101, 6'b011011, 6'b010111: 101 | begin 102 | `ifdef JOYPAD_TOGGLE_PRESSED_KEY 103 | rP <= wMuxBresult; 104 | `else 105 | if (&wXnorBresult == 0) 106 | rP <= wMuxBresult; 107 | else 108 | rP <= woPlast; 109 | `endif 110 | end 111 | 112 | 113 | // two buttons pressed with the same ending. Ex A + Right (10 1110 + 01 1110) 114 | 6'b011111,6'b101111: 115 | begin 116 | `ifdef JOYPAD_TOGGLE_PRESSED_KEY 117 | rP <= wMuxBresult; 118 | `else 119 | if (&wXnorBresult == 0) 120 | rP <= {wMuxBresult[5:4],woPlast[3:0]}; 121 | else 122 | rP <= woPlast; 123 | `endif 124 | end 125 | 126 | 127 | // two buttons pressed with the same type. Ex. Up + Down. A + B 128 | 6'b111110,6'b111101,6'b111011,6'b110111: 129 | begin 130 | `ifdef JOYPAD_TOGGLE_PRESSED_KEY 131 | rP <= wMuxBresult; 132 | `else 133 | if (&wXnorBresult == 0) 134 | rP <= {woPlast[5:4],wMuxBresult[3:0]}; 135 | else 136 | rP <= woPlast; 137 | `endif 138 | end 139 | 140 | default: 141 | begin 142 | $display("Default %dns",$time); 143 | rP <= 6'b111111; 144 | end 145 | 146 | endcase 147 | end 148 | 149 | endmodule 150 | -------------------------------------------------------------------------------- /sim/reference/bios_vram_9800_9bff.dump: -------------------------------------------------------------------------------- 1 | 2 | 00009800 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 3 | 00009810 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4 | 00009820 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5 | 00009830 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6 | 00009840 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 7 | 00009850 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 8 | 00009860 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 9 | 00009870 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 10 | 00009880 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 11 | 00009890 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 12 | 000098a0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 13 | 000098b0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 14 | 000098c0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 15 | 000098d0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 16 | 000098e0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 17 | 000098f0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 18 | 00009900 : 00 00 00 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 19 | 00009910 : 19 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 | 00009920 : 00 00 00 00 0d 0e 0f 10 11 12 13 14 15 16 17 18 21 | 00009930 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 22 | 00009940 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 23 | 00009950 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 24 | 00009960 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 25 | 00009970 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 26 | 00009980 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 27 | 00009990 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 28 | 000099a0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 29 | 000099b0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 30 | 000099c0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 31 | 000099d0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 32 | 000099e0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 33 | 000099f0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 34 | 00009a00 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 35 | 00009a10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 | 00009a20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 37 | 00009a30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 38 | 00009a40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 39 | 00009a50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 | 00009a60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 41 | 00009a70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 42 | 00009a80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 43 | 00009a90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 44 | 00009aa0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 45 | 00009ab0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 46 | 00009ac0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 47 | 00009ad0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 48 | 00009ae0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 49 | 00009af0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 50 | 00009b00 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 51 | 00009b10 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 52 | 00009b20 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 53 | 00009b30 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 54 | 00009b40 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 | 00009b50 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 56 | 00009b60 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 57 | 00009b70 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 58 | 00009b80 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 59 | 00009b90 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 60 | 00009ba0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 61 | 00009bb0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 62 | 00009bc0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 63 | 00009bd0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 64 | 00009be0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 65 | 00009bf0 : 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -------------------------------------------------------------------------------- /rtl/gpu_definitions.v: -------------------------------------------------------------------------------- 1 | //`timescale 1ns / 1ps 2 | //////////////////////////////////////////////////////////////////////////////////// 3 | // 4 | // pGB, yet another FPGA fully functional and super fun GB classic clone! 5 | // Copyright (C) 2015-2016 Diego Valverde (diego.valverde.g@gmail.com) 6 | // 7 | // This program is free software; you can redistribute it and/or 8 | // modify it under the terms of the GNU General Public License 9 | // as published by the Free Software Foundation; either version 2 10 | // of the License, or (at your option) any later version. 11 | // 12 | // This program is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | // GNU General Public License for more details. 16 | // 17 | // You should have received a copy of the GNU General Public License 18 | // along with this program; if not, write to the Free Software 19 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | // 21 | //////////////////////////////////////////////////////////////////////////////////// 22 | 23 | 24 | 25 | `ifndef GPU_DEFINITIONS_V 26 | `define GPU_DEFINITIONS_V 27 | 28 | `define GPU_UOP_SZ 23 29 | `define GPU_OP_RNG 22:18 30 | `define GPU_DST_RNG 17:12 31 | `define GPU_S1_RNG 11:6 32 | `define GPU_S0_RNG 5:0 33 | `define GPU_LIT_RNG 9:0 34 | 35 | `define GPU_S1_RNG_SEL_BIT 11 36 | `define GPU_S1_RNG_H 10:6 37 | `define GPU_S1_RNG_L 9:6 38 | 39 | `define GPU_S0_RNG_SEL_BIT 5 40 | `define GPU_S0_RNG_H 4:0 41 | `define GPU_S0_RNG_L 3:0 42 | 43 | 44 | 45 | `define SPRITE_COLOR_TRANSPARENT 2'b0 46 | `define SCANLINE_VRAM_READ 12'd3 47 | 48 | 49 | //Operations 50 | `define gnop 5'd0 51 | `define gwrl 5'd1 52 | `define gwrr 5'd2 53 | `define gadd 5'd3 54 | `define gsub 5'd4 55 | `define gaddl 5'd5 56 | `define gjnz 5'd6 57 | `define gwfbuffer 5'd7 58 | `define gsubl 5'd8 59 | `define grvmem 5'd9 60 | `define gshl 5'd10 61 | `define ggoto 5'd11 62 | `define gjz 5'd12 63 | `define gand 5'd13 64 | `define gsprtt 5'd14 //Test if sprite is within (or partially in) current tile rectangle 65 | `define ginfbaddr 5'd16 //Increment the FrameBuffer write pointer 66 | `define gwx 5'd17 67 | `define gwy 5'd18 68 | //Registers 69 | `define gnull 6'd0 70 | 71 | `define lcdc 6'd0 72 | `define state 6'd1 73 | `define scx 6'd2 74 | `define scy 6'd3 75 | `define ly 6'd4 76 | `define lyc 6'd5 77 | `define dma 6'd6 78 | `define bgp 6'd7 79 | `define obp0 6'd8 80 | `define obp1 6'd9 81 | `define wx 6'd10 82 | `define wy 6'd11 83 | `define vmem_addr 6'd12 84 | `define bh 6'd13 85 | `define bl 6'd14 86 | `define fbuffer_addr 6'd15 87 | `define cur_tile 6'd16 88 | `define sprite_current_row_offset 6'd17 89 | `define sprite_x_coord 6'd18 90 | `define sprite_y_coord 6'd19 91 | `define tile_row 6'd20 92 | `define sh 6'd21 //Sprite MSByte 93 | `define sl 6'd22 //Sprite MSByte 94 | `define r0 6'd23 95 | `define r1 6'd24 96 | `define r2 6'd25 97 | `define r3 6'd26 98 | `define r4 6'd27 99 | `define r5 6'd28 100 | `define r6 6'd29 101 | `define WinTile 6'd30 102 | `define sprite_info 6'd31 103 | `define bgmoffset 6'd32 104 | `define bgtoffset 6'd33 105 | `define vmem_data 6'd34 106 | `define bg_row_offset 6'd35 107 | `define ly_mod_8 6'd36 108 | `define r8191 6'd37 109 | `define oam_offset 6'd38 110 | `define vmem_data_shl_4 6'd39 111 | `define scy_shl_5__plus_scx 6'd40 112 | `define scy_tile_row_offset 6'd41 113 | `define IsThisTileWin 6'd42 114 | `define Win_index 6'd43 115 | `define Winmoffset 6'd44 116 | `define Window_render 6'd23 //save window render in r0 117 | //Jump labels 118 | `define get_next_sprite 18'd51 119 | `define skip_the_sprites 18'd54 //remember to change during testing of new uop 120 | `define skip_the_window 18'd84 121 | `define render_window 18'd68 122 | `define initialize_window 18'd66 123 | `endif 124 | -------------------------------------------------------------------------------- /rtl/sound_controller_modules/SoundControllerChannel2.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // pGB, yet another FPGA fully functional and super fun GB classic clone! 4 | // Copyright (C) 2015-2016 Diego Valverde (diego.valverde.g@gmail.com) 5 | // 6 | // This program is free software; you can redistribute it and/or 7 | // modify it under the terms of the GNU General Public License 8 | // as published by the Free Software Foundation; either version 2 9 | // of the License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program; if not, write to the Free Software 18 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | // 20 | //////////////////////////////////////////////////////////////////////////////////// 21 | // Sound module, channel 2. Squate waves with variable timmer, configurable frequency and envelope functions. 22 | //////////////////////////////////////////////////////////////////////////////////// 23 | 24 | 25 | module SoundCtrlChannel2 //parameters 26 | ( 27 | input wire iClock, //CPU CLOCK, 4194304Hz 28 | input wire iReset, 29 | input wire iOsc64, //OSC1 clock 64Hz 30 | input wire iOsc256, //OSC1 clock 256Hz 31 | input wire iOsc262k, //OSC2 clock 131072Hz 32 | 33 | input wire [7:0] iNR21, 34 | input wire [7:0] iNR22, 35 | input wire [7:0] iNR23, 36 | input wire [7:0] iNR24, 37 | 38 | output reg [4:0] oOut, 39 | output wire oOnFlag 40 | ); 41 | 42 | reg [5:0] rLength; 43 | reg [19:0] rLengthCounter; 44 | reg [1:0] rDutyCycle; 45 | reg rTimedMode; 46 | reg rLengthComplete; // Channe disable. 47 | 48 | reg rTone; 49 | reg [10:0] rSoundFrequency; 50 | reg [10:0] rSoundFrequencyCounter; 51 | 52 | reg [3:0] rStep; 53 | reg [18:0] rStepTime; 54 | reg [18:0] rStepCounter; 55 | reg [3:0] rInitialValue; 56 | reg rEvelopeMode; 57 | 58 | wire [4:0] up_value, down_value; 59 | 60 | // register load 61 | always @(posedge iClock) begin 62 | if (iReset || iNR24[7]) begin // Register reload and counters restart. 63 | 64 | rLength <= iNR21[5:0]; 65 | rLengthCounter <= 64-iNR21[5:0]; // Decrements to zero then load rLength. 66 | rLengthComplete <= 0; // Disables channel when is asserted. 67 | rDutyCycle <= iNR21[7:6]; 68 | rTimedMode <= iNR24[6]; 69 | 70 | rStepTime <= iNR22[2:0]; 71 | rStepCounter <= iNR22[2:0]; // Decrements to zero then load rStepTime. 72 | rEvelopeMode <= iNR22[3]; 73 | rInitialValue <= iNR22[7:4]; 74 | rStep <= iNR22[7:4]; 75 | 76 | rTone <= 0; 77 | rSoundFrequency[7:0] <= iNR23[7:0]; 78 | rSoundFrequency[10:8] <= iNR24[2:0]; 79 | rSoundFrequencyCounter <= 2048-{iNR24[2:0],iNR23[7:0]}; 80 | 81 | end 82 | end 83 | 84 | // step gen: generates the output amplitud value. 85 | always @(posedge iOsc64) begin 86 | if (rStepTime != 0) begin // Check if channel is enabled. 87 | if (rStepCounter ==1 ) begin 88 | rStepCounter <= rStepTime; // Reset counter. 89 | if(rEvelopeMode) begin // Envelope mode. 90 | rStep <= ((rStep == 4'hF) ? rStep : rStep+1); //INCREASES ONLY IF STEP IF LOWER THAN TOP VALUE 91 | end 92 | else begin 93 | rStep <= ((rStep == 4'h0) ? rStep : rStep-1); //DECREASES ONLY IF STEP IF LOWER THAN BOTTOM VALUE 94 | end 95 | end 96 | else begin 97 | rStepCounter <= rStepCounter-1; 98 | end 99 | end 100 | end 101 | 102 | // tone gen: generates the frecuency of the output. 103 | always @(posedge iOsc262k) begin 104 | if (rSoundFrequencyCounter ==0) begin 105 | rSoundFrequencyCounter <= 2048-rSoundFrequency; 106 | rTone <= ~rTone; 107 | end 108 | else begin 109 | rSoundFrequencyCounter <= rSoundFrequencyCounter-1; 110 | end 111 | end 112 | 113 | 114 | // timmer: enable or disable channel output. 115 | always @(posedge iOsc256) begin 116 | if (rLengthCounter == 0) begin 117 | rLengthCounter <= 64-rLength; 118 | rLengthComplete <= rTimedMode; // Disable channel only if timmer is enabled. 119 | end 120 | else begin 121 | rLengthCounter <= rLengthCounter-1; 122 | end 123 | end 124 | 125 | //re-map mux 126 | assign up_value = 5'd15 + rStep; 127 | assign down_value = 5'd15 - rStep; 128 | 129 | always @(posedge iClock) begin 130 | if (rLengthComplete) begin 131 | oOut[4:0] <= 5'd15; 132 | end 133 | else begin 134 | if (rTone) begin 135 | oOut[4:0] <= up_value[4:0]; 136 | end 137 | else begin 138 | oOut[4:0] <= down_value[4:0]; 139 | end 140 | end 141 | end 142 | 143 | assign oOnFlag = rLengthComplete; 144 | endmodule 145 | -------------------------------------------------------------------------------- /rtl/VgaController.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | //The papilio logic start wing has 4096 color depth. 3 | //Each color R,G and B is 4 bits. 4 | //The VGA section of the LogicStart Shield uses 12 resistors to implement 5 | // 4096 color depth. VGA video is analog in nature so there needs to be 6 | // some way to vary the RGB (Red, Green, and Blue) signals between 0V and 7 | //.7V. For each RGB signal the shade, or intensity, of the color is 8 | // controlled by varying the voltage of the pin between 0 and .7V. 9 | //The finer control you have over the voltage the more colors you 10 | //can create. For the LogicStart Shield we are able to control 4 11 | // Red, 4 Green, and 4 Blue bits which allows us to generate 16 12 | //different voltage levels between 0 and .7V for Red and Green and Blue. 13 | //If we add all three colors together we have 12 bit video which gives 14 | //us (2^12=4096) the possibility of 4096 colors. 15 | 16 | module VgaController 17 | ( 18 | input wire Clock, 19 | input wire Reset, 20 | output wire [3:0] oVgaRed,oVgaGreen,oVgaBlue, 21 | output wire oVgaVsync, //Polarity of horizontal sync pulse is negative. 22 | output wire oVgaHsync, //Polarity of vertical sync pulse is negative. 23 | output wire [15:0] oRow,oCol 24 | 25 | ); 26 | 27 | wire wHSync,wVSync,wPolarity_V,wPolarity_H; 28 | 29 | 30 | 31 | //The Papilio Duo clock is 32Mhz. We will create a 64Mhz to trick 32 | //the VGA into thinking that we are XGA 1024x768@60 Hz (pixel clock 65.0 MHz) 33 | 34 | 35 | //`define XGA_1280x1024_60Hz 36 | //`define XGA_1024x768_60Hz 37 | `ifdef XGA_1024x768_60Hz 38 | //http://tinyvga.com/vga-timing/1024x768@60Hz 39 | parameter HSYNC_VISIBLE_AREA = 1024; 40 | parameter HSYNC_FRONT_PORCH = 24; 41 | parameter HSYNC_PULSE = 136; 42 | parameter HSYN_BACK_PORCH = 48; 43 | parameter HORIZONTAL_LINE = 1344; 44 | 45 | 46 | parameter VSYNC_VISIBLE_AREA = 768; 47 | parameter VSYNC_FRONT_PORCH = 3; 48 | parameter VSYNC_PULSE = 6; 49 | parameter VSYN_BACK_PORCH = 38; 50 | parameter VERTICAL_LINE = 806; 51 | 52 | //65.0Mhz = 32Mhz*27/8 = 66Mhz 53 | parameter CLK_M = 31; 54 | parameter CLK_D = 15; 55 | 56 | assign wPolarity_V = 1'b0; 57 | assign wPolarity_H = 1'b0; 58 | 59 | `elsif XGA_1280x1024_60Hz 60 | //http://tinyvga.com/vga-timing/1280x1024@60Hz 61 | //Tested in a Dell LCD Monitor from LICIT and also in my home LCD Monitor 62 | 63 | parameter HSYNC_VISIBLE_AREA = 1280; 64 | parameter HSYNC_FRONT_PORCH = 48; 65 | parameter HSYNC_PULSE = 112; 66 | parameter HSYNC_BACK_PORCH = 248; 67 | parameter HORIZONTAL_LINE = 1688; 68 | 69 | 70 | parameter VSYNC_VISIBLE_AREA = 1024; 71 | parameter VSYNC_FRONT_PORCH = 1; 72 | parameter VSYNC_PULSE = 3; 73 | parameter VSYNC_BACK_PORCH = 38; 74 | parameter VERTICAL_LINE = 1066; 75 | 76 | //108.0Mhz = 32Mhz*27/8 77 | parameter CLK_M = 27; 78 | parameter CLK_D = 8; 79 | 80 | assign wPolarity_V = 1'b0; 81 | assign wPolarity_H = 1'b0; 82 | 83 | 84 | `else 85 | 86 | //http://tinyvga.com/vga-timing/640x480@60Hz 87 | //Works fine on LICIT LCD Dell monitor 88 | parameter HSYNC_VISIBLE_AREA = 640; 89 | parameter HSYNC_FRONT_PORCH = 16; 90 | parameter HSYNC_PULSE = 96; 91 | parameter HSYNC_BACK_PORCH = 48; 92 | parameter HORIZONTAL_LINE = 800; 93 | 94 | 95 | parameter VSYNC_VISIBLE_AREA = 480; 96 | parameter VSYNC_FRONT_PORCH = 10; 97 | parameter VSYNC_PULSE = 2; 98 | parameter VSYN_BACK_PORCH = 33; 99 | parameter VERTICAL_LINE = 525; 100 | 101 | //25.175Mhz = 32Mhz*27/28 = 25.14Mhz 102 | parameter CLK_M = 25; 103 | parameter CLK_D = 32; 104 | 105 | assign wPolarity_V = 1'b0; 106 | assign wPolarity_H = 1'b0; 107 | 108 | 109 | `endif 110 | 111 | wire wClockVga,wHCountEnd,wVCountEnd; 112 | wire [15:0] wHCount,wVCount; 113 | wire wPllLocked,wPsDone; 114 | 115 | 116 | `ifdef XILINX_IP 117 | DCM_SP 118 | # 119 | ( 120 | .CLKFX_MULTIPLY(CLK_M), //Values range from 2..32 121 | .CLKFX_DIVIDE(CLK_D) //Values range from 1..32 122 | 123 | ) 124 | ClockVga 125 | ( 126 | .CLKIN(Clock), //32Mhz 127 | .CLKFB(wClockVga), //Feed back 128 | .RST( Reset ), //Global reset 129 | .PSEN(1'b0), //Disable variable phase shift. Ignore inputs to phase shifter 130 | .LOCKED(wPllLocked), //Use this signal to make sure PLL is locked 131 | .PSDONE(wPsDone), //I am not really using this one 132 | .CLKFX(wClockVga) //FCLKFX = FCLKIN * CLKFX_MULTIPLY / CLKFX_DIVIDE 133 | 134 | ); 135 | `else 136 | assign wClockVga = Clock; 137 | assign wPllLocked = 1'b1; 138 | `endif 139 | assign wHCountEnd = (wHCount == HORIZONTAL_LINE-1)? 1'b1 : 1'b0; 140 | assign wVCountEnd = (wVCount == VERTICAL_LINE-1) ? 1'b1 : 1'b0; 141 | 142 | UPCOUNTER_POSEDGE # (.SIZE(16)) HCOUNT 143 | ( 144 | .Clock(wClockVga), 145 | .Reset(Reset | ~wPllLocked | wHCountEnd), 146 | .Initial(16'b0), 147 | .Enable(wPllLocked), 148 | .Q(wHCount) 149 | ); 150 | 151 | UPCOUNTER_POSEDGE # (.SIZE(16)) VCOUNT 152 | ( 153 | .Clock(wClockVga), 154 | .Reset(Reset | ~wPllLocked | wVCountEnd ), 155 | .Initial( 16'b0 ), 156 | .Enable(wHCountEnd), 157 | .Q(wVCount) 158 | ); 159 | 160 | assign wVSync = 161 | ( 162 | wVCount >= (VSYNC_VISIBLE_AREA + VSYNC_FRONT_PORCH ) && 163 | wVCount <= (VSYNC_VISIBLE_AREA + VSYNC_FRONT_PORCH + VSYNC_PULSE ) 164 | ) ? 1'b1 : 1'b0; 165 | 166 | assign wHSync = 167 | ( 168 | wHCount >= (HSYNC_VISIBLE_AREA + HSYNC_FRONT_PORCH ) && 169 | wHCount <= (HSYNC_VISIBLE_AREA + HSYNC_FRONT_PORCH + HSYNC_PULSE ) 170 | ) ? 1'b1 : 1'b0; 171 | 172 | 173 | assign oVgaVsync = (wPolarity_V == 1'b1) ? wVSync : ~wVSync ; 174 | assign oVgaHsync = (wPolarity_H == 1'b1) ? wHSync : ~wHSync ; 175 | 176 | 177 | 178 | wire[3:0] wColorR, wColorG, wColorB; 179 | assign wColorR = (wHCount < (HSYNC_VISIBLE_AREA/2)) ? 4'b1111 : 4'b0000; 180 | assign wColorG = (wVCount < (VSYNC_VISIBLE_AREA/2)) ? 4'b1111 : 4'b0000; 181 | assign wColorB = (wHCount >= (HSYNC_VISIBLE_AREA/2) && wVCount < (VSYNC_VISIBLE_AREA/2)) ? 4'b1111: 4'b0000; 182 | 183 | assign {oVgaRed,oVgaGreen,oVgaBlue} = (wHCount < HSYNC_VISIBLE_AREA && wVCount < VSYNC_VISIBLE_AREA) ? 184 | {wColorR,wColorG,wColorB} : //display color 185 | {4'b1111,4'b0,4'b0}; //black 186 | 187 | assign oCol = wHCount; 188 | assign oRow = wVCount; 189 | 190 | endmodule 191 | -------------------------------------------------------------------------------- /doc/papiGB_design_document.md: -------------------------------------------------------------------------------- 1 | Game-Boy-FL.png 2 | 3 | Welcome to papiGB! 4 | =================== 5 | 6 | 7 | **papiGB** is an open source project intended to replicate the behavior of the original Nintendo Game Boy. 8 | This guide is intended to walk you through the different parts of the system, providing an overview to understand and contribute to individual project blocks. 9 | papiGB project is hosted on github, this document has been created using StackEdit . 10 | 11 | ---------- 12 | 13 | ## Table of contents 14 | 15 | [TOC] 16 | 17 | Why writing RTL design from scratch? 18 | ------------------------------------------------------ 19 | In a word: **because it is lots of fun** ! 20 | 21 | Besides, nothing compared to the bragging right of playing your favorite game and knowing that deep inside you understand every single signal, and clock, every multiplexer and Flip Flop such allowing Samus to make that next jump! 22 | 23 | ![enter image description here](https://i.kinja-img.com/gawker-media/image/upload/s--Xg20nBOw--/c_fit,fl_progressive,q_80,w_636/18j155mo6qfwspng.png) 24 | 25 | Submitting issues and getting help 26 | ------------------------------------------------- 27 | 28 | Installing the project 29 | ------------------------------ 30 | ### Project dependencies and recommended tool chain 31 | 32 | ### Cloning the repository 33 | 34 | ### Running your first simulation and checking results 35 | 36 | 37 | > **Note:** 38 | 39 | > - Make clean deletes all of the log files under the **/sim** folder, you may want to create a backup if you really need those for later. 40 | 41 | 42 | 43 | Project directory structure 44 | ------------------------------------- 45 | 46 | **papiGB** stores the design and simularton files a series of directories. 47 | 48 | - rtl/ : 49 | - tb/ : 50 | - doc/ : 51 | - sim/ : 52 | - scripts/ : 53 | - tests/ : 54 | - /asm/ : 55 | 56 | Simulation Flags 57 | ------------------------ 58 | It's possible to customize a simulation through the simulation flag, these are described below. 59 | 60 | Flag | Description 61 | ---- | ----------- 62 | STOP\_AFTER\_FIRST\_FRAME | When this flag is ON the CPU raises the flag `rSimulationDone` for stop the simulation after the first frame is completed. 63 | ENABLE\_CPU\_LOG | When this flag is ON generates a log file named "pgb\_cpu.log" that records CPU's state at the beginning of a new flow. 64 | ENABLE\_GPU\_LOG | When this flag is ON generates a log file named "pgb\_gpu.log" that records GPU's state when it is activated. 65 | ENABLE\_SOUND\_TRACE | When this flag is ON generates a dump file named "pgb\_sound\_trace.dump" 66 | VMEM\_DUMP\_PATH | Loads into the Video Memory the file indicated. 67 | OAM\_DUMP\_PATH | Loads into the OAM Memory the file indicated. 68 | START\_DUMP\_INSN | Indicates the first instruction that is recorded in the file pgb\_cpu.log. 69 | SKIP\_BIOS | When this flag is ON the CPU skips bios's data and starts reading cartridge's data. 70 | REG\_TAC | Sets an initial value on register TAC. 71 | REG\_IF | Sets an initial value on register IF. 72 | REG\_A | Sets an initial value on register A. 73 | REG\_F | Sets an initial value on register F. 74 | REG\_B | Sets an initial value on register B. 75 | REG\_C | Sets an initial value on register C. 76 | REG\_H | Sets an initial value on register H. 77 | REG\_L | Sets an initial value on register L. 78 | REG\_D | Sets an initial value on register D. 79 | REG\_E | Sets an initial value on register E. 80 | REG\_SPL | Sets an initial value on the low part of register SP. 81 | REG\_SPH | Sets an initial value on the high part of register SP. 82 | REG\_LCDC | Sets an initial value on register LCDC. 83 | REG\_BGP | Sets an initial value on register BGP. 84 | REG\_DIFF | Sets an initial value for a parameter of register DIV. 85 | DISABLE\_CPU | When this flag is ON the CPU is disabled and the GPU is forced to start. 86 | SIMULATION\_TIME\_OUT | The simulation stops after the time indicated. 87 | CPU\_TRACE\_WORK\_MEMORY | When this flag is ON records the memory used in pgb\_cpu.log. 88 | -------- | -------------- 89 | 90 | Running a simulation 91 | ------------------------------ 92 | 93 | In order to run a simulation the **Makefile** under the sim folder is used. 94 | 95 | ### Using the **Makefile** SIMFLAGS 96 | 97 | The **Makefile** SIMFLAGS allows you to set the values of many flags in order to change the behavior of the simulation. the -DSIMFLAGS consists of a string which the make command passes to the icarus RTL simulator. 98 | For example, the following make invocation will set the CPU register B=0 at the beginning of the simulation: 99 | > $ make SIMFLAGS=" -DREG_B=0" 100 | 101 | 102 | - -R 103 | 104 | The CPU: **dzCPU!** 105 | --------------------------- 106 | 107 | The original GB CPU was an 8bit Sharp LR35902, which is sort of a Z80 108 | processor specially modified by Nintendo. Essentially, Nintendo took some 109 | opcodes out of the instruction set and added some opcodes of their own. The 110 | Z80 is very similar to an 8080 processor from the early 90s, in the sense 111 | that it has a CISC instruction set. In other words, it features lots of 112 | complex instructions, and each individual instruction does lots of things. 113 | Furthermore, decoding the Z80 instruction set may be a challenging task since 114 | the instruction width varies from single BYTE instruction up to 5 BYTE 115 | instructions. Also instructions take multiple clock cycles to execute and the 116 | time to fetch data from main memory (SRAM) adds additional latency to 117 | individual Z80 instructions. 118 | The dZCPU! uses a micro-code approach to mimic the original Z80 CISC 119 | instruction set. The following diagram illustrates the overall processor 120 | architecture. 121 | 122 | **Insert drawing here ** 123 | 124 | Figure 1 shows the basic blocks of the dZCPU!. Essentially, each time a Z80 125 | macro insn is fetched from the MMU, the index to a mirco-code is obtained 126 | from an uCode Look-up-table block. The ucode flow corresponding to that macro 127 | instruction is executed and the next macro instruction is fetched. -------------------------------------------------------------------------------- /rtl/sound_controller_modules/SoundControllerChannel1.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // pGB, yet another FPGA fully functional and super fun GB classic clone! 4 | // Copyright (C) 2015-2016 Diego Valverde (diego.valverde.g@gmail.com) 5 | // 6 | // This program is free software; you can redistribute it and/or 7 | // modify it under the terms of the GNU General Public License 8 | // as published by the Free Software Foundation; either version 2 9 | // of the License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program; if not, write to the Free Software 18 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | // 20 | //////////////////////////////////////////////////////////////////////////////////// 21 | // Sound module, channel 1. Squate waves with variable timmer, configurable frequency and envelope functions. 22 | //////////////////////////////////////////////////////////////////////////////////// 23 | 24 | 25 | module SoundCtrlChannel1 //parameters 26 | ( 27 | input wire iClock, //CPU CLOCK, 4194304Hz 28 | input wire iReset, 29 | input wire iOsc64, //OSC1 clock 64Hz 30 | input wire iOsc256, //OSC1 clock 256Hz 31 | input wire iOsc128, //OSC1 clock 128Hz 32 | input wire iOsc262k, //OSC2 clock 131072Hz 33 | 34 | input wire [7:0] iNR10, 35 | input wire [7:0] iNR11, 36 | input wire [7:0] iNR12, 37 | input wire [7:0] iNR13, 38 | input wire [7:0] iNR14, 39 | 40 | output reg [4:0] oOut, 41 | output wire oOnFlag 42 | ); 43 | 44 | 45 | reg [2:0] rSweepShifts; 46 | reg rSweepMode; 47 | reg [2:0] rSweepTime; 48 | reg [17:0] rSweepCounter; 49 | reg [11:0] rSoundFrequencyNew; 50 | 51 | 52 | reg [5:0] rLength; 53 | reg [19:0] rLengthCounter; 54 | reg [1:0] rDutyCycle; 55 | reg rTimedMode; 56 | reg rLengthComplete; // Channe disable. 57 | 58 | reg rTone; 59 | reg [10:0] rSoundFrequency; 60 | reg [10:0] rSoundFrequencyCounter; 61 | 62 | 63 | reg [3:0] rStep; 64 | reg [18:0] rStepTime; 65 | reg [18:0] rStepCounter; 66 | reg [3:0] rInitialValue; 67 | reg rEvelopeMode; 68 | 69 | wire [4:0] up_value, down_value; 70 | 71 | // register load 72 | always @(posedge iClock) begin 73 | if (iReset || iNR14[7]) begin // Register reload and counters restart. 74 | 75 | rLength <= iNR11[5:0]; 76 | rLengthCounter <= 64-iNR11[5:0]; // Decrements to zero then load rLength. 77 | rLengthComplete <= 0; // Disables channel when is asserted. 78 | rDutyCycle <= iNR11[7:6]; 79 | rTimedMode <= iNR14[6]; 80 | 81 | rStepTime <= iNR12[2:0]; 82 | rStepCounter <= iNR12[2:0]; // Decrements to zero then load rStepTime. 83 | rEvelopeMode <= iNR12[3]; 84 | rInitialValue <= iNR12[7:4]; 85 | rStep <= iNR12[7:4]; 86 | 87 | rTone <= 0; 88 | rSoundFrequency[10:0] <= 2048-{iNR14[2:0],iNR13[7:0]}; 89 | rSoundFrequencyCounter[10:0] <= 2048-{iNR14[2:0],iNR13[7:0]}; 90 | 91 | rSoundFrequencyNew <= 2048-{iNR14[2:0],iNR13[7:0]}; 92 | 93 | //FREQUENCY SWEEP REGISTERS 94 | rSweepShifts <= iNR10[2:0]; 95 | rSweepMode <= iNR10[3]; 96 | rSweepTime <= iNR10[6:4]; 97 | rSweepCounter <= iNR10[6:4]; 98 | 99 | end 100 | end 101 | 102 | // step gen: generates the output amplitud value. 103 | always @(posedge iOsc64) begin 104 | if (rStepTime != 0) begin // Check if channels step function is enabled. 105 | if (rStepCounter ==1 ) begin 106 | rStepCounter <= rStepTime; // Reset counter. 107 | if(rEvelopeMode) begin // Envelope mode. 108 | rStep <= ((rStep == 4'hF) ? rStep : rStep+1); //INCREASES ONLY IF STEP IF LOWER THAN TOP VALUE 109 | end 110 | else begin 111 | rStep <= ((rStep == 4'h0) ? rStep : rStep-1); //DECREASES ONLY IF STEP IF LOWER THAN BOTTOM VALUE 112 | end 113 | end 114 | else begin 115 | rStepCounter <= rStepCounter-1; 116 | end 117 | end 118 | end 119 | 120 | // tone gen: generates the frecuency of the output. 121 | always @(posedge iOsc262k) begin 122 | if (rSoundFrequencyCounter ==0) begin 123 | rSoundFrequencyCounter <= rSoundFrequency; 124 | rTone <= ~rTone; 125 | end 126 | else begin 127 | rSoundFrequencyCounter <= rSoundFrequencyCounter-1; 128 | end 129 | end 130 | 131 | // sweep gen: generates the frequency sweep 132 | always @(posedge iOsc128) begin //128Hz 133 | 134 | if (rSweepCounter ==1 && rSweepShifts != 0 && rSweepTime > 0) begin // calucates new frequency 135 | if (rSweepMode) begin 136 | rSoundFrequencyNew <= rSoundFrequency + (rSoundFrequency >> rSweepShifts); 137 | end 138 | else begin 139 | rSoundFrequencyNew <= rSoundFrequency - (rSoundFrequency >> rSweepShifts); 140 | end 141 | end 142 | 143 | if (rSweepCounter ==0 && rSweepTime > 0) begin // set new frequency counter 144 | if (rSoundFrequencyNew == 1 && rSoundFrequency == 1) begin // frequency is more than 131072 145 | rLengthComplete = 1'b1 ; 146 | end 147 | else if (rSoundFrequencyNew <= 2047) begin // frequency is more than 131072 148 | rSoundFrequency <= rSoundFrequencyNew; 149 | end 150 | rSweepCounter <= rSweepTime; 151 | end 152 | 153 | else begin 154 | rSweepCounter = rSweepCounter-1; 155 | end 156 | end 157 | 158 | // timmer: enable or disable channel output. 159 | always @(posedge iOsc256) begin 160 | if (rLengthCounter == 0) begin 161 | rLengthCounter <= 64-rLength; 162 | rLengthComplete <= (rTimedMode || rLengthComplete); // Disable channel only if timmer is enabled. 163 | end 164 | else begin 165 | rLengthCounter <= rLengthCounter-1; 166 | end 167 | end 168 | 169 | //re-map mux 170 | assign up_value = 5'd15 + rStep; 171 | assign down_value = 5'd15 - rStep; 172 | 173 | always @(posedge iClock) begin 174 | if (rLengthComplete) begin 175 | oOut[4:0] <= 5'd15; 176 | end 177 | else begin 178 | if (rTone) begin 179 | oOut[4:0] <= up_value[4:0]; 180 | end 181 | else begin 182 | oOut[4:0] <= down_value[4:0]; 183 | end 184 | end 185 | end 186 | 187 | assign oOnFlag = rLengthComplete; 188 | 189 | endmodule 190 | -------------------------------------------------------------------------------- /sim/signals/tb_simple_dzcpu.gtkw: -------------------------------------------------------------------------------- 1 | [*] 2 | [*] GTKWave Analyzer v3.3.66 (w)1999-2015 BSI 3 | [*] Sun Aug 21 04:24:36 2016 4 | [*] 5 | [dumpfile] "/home/diego/workspace/projects/papiGB/sim/tb_simple_dzcpu.vcd" 6 | [dumpfile_mtime] "Sun Aug 21 01:21:13 2016" 7 | [dumpfile_size] 265149706 8 | [savefile] "/home/diego/workspace/projects/papiGB/sim/signals/tb_simple_dzcpu.gtkw" 9 | [timestart] 12098558900 10 | [size] 1366 744 11 | [pos] -1 -1 12 | *-15.674738 12098645000 111600 1875031400 1876195000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 13 | [treeopen] tb_simple_dzcpu. 14 | [treeopen] tb_simple_dzcpu.uut. 15 | [sst_width] 256 16 | [signals_width] 418 17 | [sst_expanded] 1 18 | [sst_vpaned_height] 211 19 | @28 20 | tb_simple_dzcpu.uut.iClock 21 | tb_simple_dzcpu.uut.iReset 22 | @200 23 | -dzCPU 24 | @800200 25 | -TIMERS 26 | @25 27 | tb_simple_dzcpu.uut.TIMERS.rMTime[7:0] 28 | @28 29 | tb_simple_dzcpu.uut.TIMERS.iMcuWe 30 | tb_simple_dzcpu.uut.TIMERS.iBranchTaken 31 | tb_simple_dzcpu.uut.TIMERS.iInterrupt 32 | tb_simple_dzcpu.uut.TIMERS.iEof 33 | @22 34 | tb_simple_dzcpu.uut.TIMERS.iOpcode[7:0] 35 | @24 36 | tb_simple_dzcpu.uut.TIMERS.wClockIncrement[2:0] 37 | @28 38 | tb_simple_dzcpu.uut.TIMERS.rIncTimer 39 | @22 40 | [color] 2 41 | tb_simple_dzcpu.uut.TIMERS.rCurrentState[7:0] 42 | tb_simple_dzcpu.uut.TIMERS.iMcuWriteData[7:0] 43 | tb_simple_dzcpu.uut.TIMERS.iMcuRegSelect[3:0] 44 | @1000200 45 | -TIMERS 46 | @c00200 47 | -INTERRUPT 48 | @28 49 | tb_simple_dzcpu.uut.INTERRUPTS.iClock 50 | tb_simple_dzcpu.uut.INTERRUPTS.iMcuWe 51 | @22 52 | tb_simple_dzcpu.uut.INTERRUPTS.iMcuRegSelect[3:0] 53 | tb_simple_dzcpu.uut.INTERRUPTS.iMcuWriteData[7:0] 54 | tb_simple_dzcpu.uut.INTERRUPTS.oInterruptResquestPending[7:0] 55 | @1401200 56 | -INTERRUPT 57 | @800200 58 | -dzCPU 59 | @200 60 | -interrupts 61 | @c00022 62 | tb_simple_dzcpu.uut.DZCPU.iInterruptRequests[3:0] 63 | @28 64 | (0)tb_simple_dzcpu.uut.DZCPU.iInterruptRequests[3:0] 65 | (1)tb_simple_dzcpu.uut.DZCPU.iInterruptRequests[3:0] 66 | (2)tb_simple_dzcpu.uut.DZCPU.iInterruptRequests[3:0] 67 | (3)tb_simple_dzcpu.uut.DZCPU.iInterruptRequests[3:0] 68 | @1401200 69 | -group_end 70 | @28 71 | tb_simple_dzcpu.uut.DZCPU.wInterruptRoutineJumpDetected 72 | @22 73 | tb_simple_dzcpu.uut.DZCPU.wPc[15:0] 74 | tb_simple_dzcpu.uut.DZCPU.oMCUAddr[15:0] 75 | tb_simple_dzcpu.uut.DZCPU.iMCUData[7:0] 76 | tb_simple_dzcpu.uut.DZCPU.wNextFlow[9:0] 77 | @24 78 | tb_simple_dzcpu.uut.DZCPU.wuOpFlowIdx[9:0] 79 | @22 80 | tb_simple_dzcpu.uut.DZCPU.wInterruptRequestBitMaps_pre[3:0] 81 | tb_simple_dzcpu.uut.DZCPU.wInterruptRequestBitMap[3:0] 82 | tb_simple_dzcpu.uut.DZCPU.wInterruptVectorAddress[15:0] 83 | @24 84 | tb_simple_dzcpu.uut.DZCPU.wIsCBFlow 85 | @200 86 | -cpu 87 | @22 88 | tb_simple_dzcpu.uut.DZCPU.wuOpFlowIdx[9:0] 89 | @28 90 | tb_simple_dzcpu.uut.DZCPU.wTimerTick 91 | @2024 92 | ^1 /home/diego/workspace/projects/papiGB/sim/signals/dzcpu_states 93 | tb_simple_dzcpu.uut.DZCPU.rCurrentState[7:0] 94 | @22 95 | tb_simple_dzcpu.uut.DZCPU.iMCUData[7:0] 96 | tb_simple_dzcpu.uut.DZCPU.oMCUData[7:0] 97 | @28 98 | tb_simple_dzcpu.uut.DZCPU.oMCUwe 99 | @22 100 | tb_simple_dzcpu.uut.DZCPU.oMCUAddr[15:0] 101 | tb_simple_dzcpu.uut.DZCPU.wPc[15:0] 102 | @28 103 | tb_simple_dzcpu.uut.DZCPU.wJcbDetected 104 | @2024 105 | ^2 /home/diego/workspace/projects/papiGB/sim/signals/dzcpu_uop_cmd 106 | tb_simple_dzcpu.uut.DZCPU.wuCmd[4:0] 107 | @28 108 | tb_simple_dzcpu.uut.DZCPU.wIPC 109 | [color] 6 110 | tb_simple_dzcpu.uut.DZCPU.wEof 111 | [color] 3 112 | tb_simple_dzcpu.uut.DZCPU.rFlowEnable 113 | tb_simple_dzcpu.uut.DZCPU.wZ 114 | @22 115 | tb_simple_dzcpu.uut.DZCPU.wRegData[15:0] 116 | @c00028 117 | tb_simple_dzcpu.uut.DZCPU.wBitMask[7:0] 118 | @28 119 | (0)tb_simple_dzcpu.uut.DZCPU.wBitMask[7:0] 120 | (1)tb_simple_dzcpu.uut.DZCPU.wBitMask[7:0] 121 | (2)tb_simple_dzcpu.uut.DZCPU.wBitMask[7:0] 122 | (3)tb_simple_dzcpu.uut.DZCPU.wBitMask[7:0] 123 | (4)tb_simple_dzcpu.uut.DZCPU.wBitMask[7:0] 124 | (5)tb_simple_dzcpu.uut.DZCPU.wBitMask[7:0] 125 | (6)tb_simple_dzcpu.uut.DZCPU.wBitMask[7:0] 126 | (7)tb_simple_dzcpu.uut.DZCPU.wBitMask[7:0] 127 | @1401200 128 | -group_end 129 | @22 130 | [color] 5 131 | tb_simple_dzcpu.uut.DZCPU.rUopDstRegData[15:0] 132 | @200 133 | -Registers 134 | @2024 135 | ^3 /home/diego/workspace/projects/papiGB/sim/signals/dzcpu_reg_select 136 | tb_simple_dzcpu.uut.DZCPU.wUopSrc[15:0] 137 | @28 138 | tb_simple_dzcpu.uut.DZCPU.rRegWe 139 | @22 140 | tb_simple_dzcpu.uut.DZCPU.wFlags[7:0] 141 | tb_simple_dzcpu.uut.DZCPU.wSpH[7:0] 142 | tb_simple_dzcpu.uut.DZCPU.wSpL[7:0] 143 | tb_simple_dzcpu.uut.DZCPU.wB[7:0] 144 | tb_simple_dzcpu.uut.DZCPU.wC[7:0] 145 | tb_simple_dzcpu.uut.DZCPU.wD[7:0] 146 | tb_simple_dzcpu.uut.DZCPU.wE[7:0] 147 | @c00022 148 | tb_simple_dzcpu.uut.DZCPU.wH[7:0] 149 | @28 150 | (0)tb_simple_dzcpu.uut.DZCPU.wH[7:0] 151 | (1)tb_simple_dzcpu.uut.DZCPU.wH[7:0] 152 | (2)tb_simple_dzcpu.uut.DZCPU.wH[7:0] 153 | (3)tb_simple_dzcpu.uut.DZCPU.wH[7:0] 154 | (4)tb_simple_dzcpu.uut.DZCPU.wH[7:0] 155 | (5)tb_simple_dzcpu.uut.DZCPU.wH[7:0] 156 | (6)tb_simple_dzcpu.uut.DZCPU.wH[7:0] 157 | (7)tb_simple_dzcpu.uut.DZCPU.wH[7:0] 158 | @1401200 159 | -group_end 160 | @22 161 | tb_simple_dzcpu.uut.DZCPU.wL[7:0] 162 | tb_simple_dzcpu.uut.DZCPU.wA[7:0] 163 | tb_simple_dzcpu.uut.DZCPU.wX8[7:0] 164 | tb_simple_dzcpu.uut.DZCPU.wX16[15:0] 165 | @1000200 166 | -dzCPU 167 | @800200 168 | -MMU 169 | @22 170 | tb_simple_dzcpu.uut.MMU.iInterruptRequest[7:0] 171 | tb_simple_dzcpu.uut.MMU.iInterruptFlag[7:0] 172 | tb_simple_dzcpu.uut.MMU.iInterruptEnable[7:0] 173 | @2024 174 | ^4 /home/diego/workspace/projects/papiGB/sim/signals/mmu_cpu_gpu_sel 175 | tb_simple_dzcpu.uut.MMU.wCPU_GPU_Sel 176 | @28 177 | tb_simple_dzcpu.uut.MMU.iCpuReadRequest 178 | tb_simple_dzcpu.uut.MMU.iGpuReadRequest 179 | @22 180 | tb_simple_dzcpu.uut.MMU.iCpuAddr[15:0] 181 | tb_simple_dzcpu.uut.MMU.wRegMapBootStapRom[7:0] 182 | tb_simple_dzcpu.uut.MMU.wReadCartridgeBank0[7:0] 183 | tb_simple_dzcpu.uut.MMU.wCartridgeDataBank0[7:0] 184 | @28 185 | tb_simple_dzcpu.uut.MMU.wInBios 186 | @22 187 | tb_simple_dzcpu.uut.MMU.oCpuData[7:0] 188 | tb_simple_dzcpu.uut.MMU.iGpuAddr[15:0] 189 | tb_simple_dzcpu.uut.MMU.oGpuVmemReadData[7:0] 190 | tb_simple_dzcpu.uut.MMU.wVmemReadAddr[15:0] 191 | tb_simple_dzcpu.uut.MMU.wOAMData[7:0] 192 | tb_simple_dzcpu.uut.MMU.wReadVmem[7:0] 193 | tb_simple_dzcpu.uut.MMU.wAddr[15:0] 194 | @28 195 | tb_simple_dzcpu.uut.MMU.wWeVRam 196 | tb_simple_dzcpu.uut.MMU.wWeZeroPage 197 | tb_simple_dzcpu.uut.MMU.wInBios 198 | tb_simple_dzcpu.uut.MMU.wInCartridgeBank0 199 | @1000200 200 | -MMU 201 | @c00200 202 | -GPU 203 | @28 204 | tb_simple_dzcpu.uut.GPU.iClock 205 | tb_simple_dzcpu.uut.GPU.iReset 206 | tb_simple_dzcpu.uut.GPU.wZ 207 | tb_simple_dzcpu.uut.GPU.wGpuActive 208 | @24 209 | tb_simple_dzcpu.uut.GPU.wIp[7:0] 210 | @22 211 | tb_simple_dzcpu.uut.GPU.wOp0[15:0] 212 | tb_simple_dzcpu.uut.GPU.wOp1[15:0] 213 | @800200 214 | -tb_simple_dzcpu.uut.GPU.wUop 215 | @1401200 216 | -group_end 217 | -group_end 218 | [pattern_trace] 1 219 | [pattern_trace] 0 220 | -------------------------------------------------------------------------------- /rtl/sound_controller_modules/SoundControllerChannel3.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // pGB, yet another FPGA fully functional and super fun GB classic clone! 4 | // Copyright (C) 2015-2016 Diego Valverde (diego.valverde.g@gmail.com) 5 | // 6 | // This program is free software; you can redistribute it and/or 7 | // modify it under the terms of the GNU General Public License 8 | // as published by the Free Software Foundation; either version 2 9 | // of the License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program; if not, write to the Free Software 18 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | // 20 | //////////////////////////////////////////////////////////////////////////////////// 21 | // Sound module, channel 3. Squate waves with variable timmer, configurable frequency and envelope functions. 22 | //////////////////////////////////////////////////////////////////////////////////// 23 | 24 | 25 | module SoundCtrlChannel3 //parameters 26 | ( 27 | input wire iClock, //CPU CLOCK, 4194304Hz 28 | input wire iReset, 29 | input wire iOsc256, //OSC1 clock 256Hz 30 | input wire iOsc262k, //OSC2 clock 131072Hz 31 | 32 | input wire [7:0] iNR30, 33 | input wire [7:0] iNR31, 34 | input wire [7:0] iNR32, 35 | input wire [7:0] iNR33, 36 | input wire [7:0] iNR34, 37 | 38 | output reg [4:0] oOut, 39 | output wire oOnFlag 40 | ); 41 | 42 | 43 | reg [8:0] rLength; 44 | reg [19:0] rLengthCounter; 45 | reg rTimedMode; 46 | reg rLengthComplete; // Channe disable. 47 | 48 | reg rTone; 49 | reg [10:0] rSoundFrequency; 50 | reg [10:0] rSoundFrequencyCounter; 51 | 52 | reg rChannelEnable; 53 | reg [1:0] rOutLevel; 54 | reg [3:0] rStep; 55 | reg [3:0] rStepScaled; 56 | 57 | wire [4:0] up_value, down_value; 58 | 59 | reg [4:0] rWaveRamIndex; 60 | reg rWaveRamHnL; 61 | 62 | reg [7:0] iWaveRam [0:31]; // Wave samples Ram 64 samples of 4 bits 63 | 64 | // triangular waveform 65 | ///* 66 | always @ (posedge iClock) begin 67 | if (iReset) begin 68 | iWaveRam[0]=8'h01; 69 | iWaveRam[1]=8'h23; 70 | iWaveRam[2]=8'h45; 71 | iWaveRam[3]=8'h67; 72 | iWaveRam[4]=8'h89; 73 | iWaveRam[5]=8'hAB; 74 | iWaveRam[6]=8'hCD; 75 | iWaveRam[7]=8'hEF; 76 | iWaveRam[8]=8'hED; 77 | iWaveRam[9]=8'hCB; 78 | iWaveRam[10]=8'hA9; 79 | iWaveRam[11]=8'h87; 80 | iWaveRam[12]=8'h65; 81 | iWaveRam[13]=8'h43; 82 | iWaveRam[14]=8'h21; 83 | iWaveRam[15]=8'h00; 84 | iWaveRam[16]=8'h01; 85 | iWaveRam[17]=8'h23; 86 | iWaveRam[18]=8'h45; 87 | iWaveRam[19]=8'h67; 88 | iWaveRam[20]=8'h89; 89 | iWaveRam[21]=8'hAB; 90 | iWaveRam[22]=8'hCD; 91 | iWaveRam[23]=8'hEF; 92 | iWaveRam[24]=8'hED; 93 | iWaveRam[25]=8'hCB; 94 | iWaveRam[26]=8'hA9; 95 | iWaveRam[27]=8'h87; 96 | iWaveRam[28]=8'h65; 97 | iWaveRam[29]=8'h43; 98 | iWaveRam[30]=8'h21; 99 | iWaveRam[31]=8'h00; 100 | end 101 | end 102 | //*/ 103 | 104 | // sawtooth waveform 105 | /* 106 | always @ (posedge iClock) begin 107 | if (iReset) begin 108 | iWaveRam[0]=8'hFE; 109 | iWaveRam[1]=8'hDC; 110 | iWaveRam[2]=8'hBA; 111 | iWaveRam[3]=8'h98; 112 | iWaveRam[4]=8'h76; 113 | iWaveRam[5]=8'h54; 114 | iWaveRam[6]=8'h32; 115 | iWaveRam[7]=8'h10; 116 | iWaveRam[8]=8'hFE; 117 | iWaveRam[9]=8'hDC; 118 | iWaveRam[10]=8'hBA; 119 | iWaveRam[11]=8'h98; 120 | iWaveRam[12]=8'h76; 121 | iWaveRam[13]=8'h54; 122 | iWaveRam[14]=8'h32; 123 | iWaveRam[15]=8'h10; 124 | iWaveRam[16]=8'hFE; 125 | iWaveRam[17]=8'hDC; 126 | iWaveRam[18]=8'hBA; 127 | iWaveRam[19]=8'h98; 128 | iWaveRam[20]=8'h76; 129 | iWaveRam[21]=8'h54; 130 | iWaveRam[22]=8'h32; 131 | iWaveRam[23]=8'h10; 132 | iWaveRam[24]=8'hFE; 133 | iWaveRam[25]=8'hDC; 134 | iWaveRam[26]=8'hBA; 135 | iWaveRam[27]=8'h98; 136 | iWaveRam[28]=8'h76; 137 | iWaveRam[29]=8'h54; 138 | iWaveRam[30]=8'h32; 139 | iWaveRam[31]=8'h10; 140 | end 141 | end 142 | */ 143 | 144 | // register load 145 | always @(posedge iClock) begin 146 | if (iReset || iNR34[7]) begin // Register reload and counters restart. 147 | 148 | rChannelEnable <= iNR30[7]; 149 | 150 | rLength <= iNR31[7:0]; 151 | rLengthCounter <= 256 - iNR31[7:0]; // Decrements to zero then load rLength. 152 | rLengthComplete <= 0; // Disables channel when is asserted. 153 | 154 | rTimedMode <= iNR34[6]; 155 | 156 | rOutLevel <= iNR32[6:5]; 157 | rStep <= iWaveRam[0][3:0]; 158 | rWaveRamIndex <= 0; 159 | rWaveRamHnL <= 1; // Indicates if low or high part have been read. 160 | 161 | rTone <= 0; 162 | rSoundFrequency[10:0] <= 2048-{iNR34[2:0],iNR33[7:0]}; 163 | rSoundFrequencyCounter <= 2048-{iNR34[2:0],iNR33[7:0]}; 164 | 165 | end 166 | end 167 | 168 | // wave ram reader 169 | always @ (posedge rTone) begin 170 | if (rChannelEnable) begin 171 | if (~rWaveRamHnL) begin 172 | rStep <= iWaveRam[rWaveRamIndex][7:4]; 173 | rWaveRamHnL <= ~rWaveRamHnL; 174 | end 175 | else begin 176 | rStep <= iWaveRam[rWaveRamIndex][3:0]; 177 | rWaveRamHnL <= ~rWaveRamHnL; 178 | 179 | if (rWaveRamIndex == 5'd31) begin 180 | rWaveRamIndex <= rWaveRamIndex+1; 181 | rLengthComplete <= rTimedMode; 182 | end 183 | else begin 184 | rWaveRamIndex <= rWaveRamIndex+1; 185 | end 186 | end 187 | end 188 | else begin 189 | rStep <= 4'b0; 190 | end 191 | end 192 | 193 | // tone gen: generates the frecuency of the output. 194 | always @(posedge iOsc262k) begin 195 | if (rSoundFrequencyCounter ==0) begin 196 | rSoundFrequencyCounter <= rSoundFrequency; 197 | rTone <= ~rTone; 198 | end 199 | else begin 200 | rSoundFrequencyCounter <= rSoundFrequencyCounter-1; 201 | end 202 | end 203 | 204 | 205 | // timmer: enable or disable channel output. 206 | always @(posedge iOsc256) begin 207 | if (rLengthCounter == 0) begin 208 | rLengthCounter <= 256-rLength; 209 | rLengthComplete <= rTimedMode; // Disable channel only if timmer is enabled. 210 | end 211 | else begin 212 | rLengthCounter <= rLengthCounter-1; 213 | end 214 | end 215 | 216 | //re-map mux 217 | assign up_value = 5'd15 + rStepScaled; 218 | assign down_value = 5'd15 - rStepScaled; 219 | 220 | always @(posedge iClock) begin 221 | if (rLengthComplete) begin 222 | oOut[4:0] <= 5'd15; 223 | end 224 | else begin 225 | if (rTone) begin 226 | oOut[4:0] <= up_value[4:0]; 227 | end 228 | else begin 229 | oOut[4:0] <= down_value[4:0]; 230 | end 231 | end 232 | end 233 | 234 | 235 | // output level manager 236 | always @ (rOutLevel or rStep) begin 237 | case (rOutLevel[1:0]) 238 | 2'd0: rStepScaled = 0; 239 | 2'd1: rStepScaled = rStep; 240 | 2'd2: rStepScaled = rStep >> 1; 241 | 2'd3: rStepScaled = rStep >> 2; 242 | endcase 243 | end 244 | 245 | assign oOnFlag = rLengthComplete; 246 | 247 | endmodule 248 | -------------------------------------------------------------------------------- /rtl/pGB.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | `include "aDefinitions.v" 3 | 4 | //////////////////////////////////////////////////////////////////////////////////// 5 | // 6 | // pGB, yet another FPGA fully functional and super fun GB classic clone! 7 | // Copyright (C) 2015-2016 Diego Valverde (diego.valverde.g@gmail.com) 8 | // 9 | // This program is free software; you can redistribute it and/or 10 | // modify it under the terms of the GNU General Public License 11 | // as published by the Free Software Foundation; either version 2 12 | // of the License, or (at your option) any later version. 13 | // 14 | // This program is distributed in the hope that it will be useful, 15 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | // GNU General Public License for more details. 18 | // 19 | // You should have received a copy of the GNU General Public License 20 | // along with this program; if not, write to the Free Software 21 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 | // 23 | //////////////////////////////////////////////////////////////////////////////////// 24 | module pGB 25 | ( 26 | 27 | input wire iClock, 28 | 29 | `ifdef VGA_ENABLED 30 | output wire [3:0] oVgaRed, 31 | output wire [3:0] oVgaGreen, 32 | output wire [3:0] oVgaBlue, 33 | output wire oVgaHsync, 34 | output wire oVgaVsync, 35 | `endif 36 | 37 | //IO input ports 38 | //ASCII IMAGE BUTTON MATRIX 39 | input wire [5:0] iButtonRegister, //Pressed button 40 | 41 | 42 | `ifndef XILINX_IP 43 | output wire oFrameBufferWe, 44 | output wire [15:0] oFrameBufferData, 45 | output wire [15:0] oFrameBufferAddr, 46 | 47 | `endif 48 | 49 | input wire iReset 50 | ); 51 | 52 | wire [15:0] wdZCPU_2_MMU_Addr, wGPU_2_MCU_Addr; 53 | wire [7:0] wdZCPU_2_MMU_WriteData, wMMU_ReadData; 54 | wire wdZCPU_2_MMU_We, wdZCPU_2_MMU_ReadRequest; 55 | 56 | wire[7:0] wGPU_2_MCU_LCDC; 57 | wire[7:0] wGPU_2_MCU_STAT; 58 | wire[7:0] wGPU_2_MCU_SCY; 59 | wire[7:0] wGPU_2_MCU_SCX; 60 | wire[7:0] wGPU_2_MCU_LY; 61 | wire[7:0] wGPU_2_MCU_LYC; 62 | wire[7:0] wGPU_2_MCU_DMA; 63 | wire[7:0] wGPU_2_MCU_BGP; 64 | wire[7:0] wGPU_2_MCU_OBP0; 65 | wire[7:0] wGPU_2_MCU_OBP1; 66 | wire[7:0] wGPU_2_MCU_WY; 67 | wire[7:0] wGPU_2_MCU_WX, wMMU_RegData, wMMU_2_GPU_VmemReadData; 68 | wire[7:0] wButtonRegister; 69 | wire[7:0] wCurrentZ80Insn; 70 | wire[15:0] wGpuAddr; 71 | wire [2:0] wMMU_RegWe; 72 | wire[3:0] wMMU_RegSelect, wMCU_2_TIMER_RegSelect; 73 | wire wGPU_2_MCU_ReadRequest, wMCU_2_TIMER_We; 74 | wire wIOInterruptTrigger, wdZCPU_Eof, wdZCPU_BranchTaken, wDZCPU_2_Timer_IntDetected; 75 | wire [7:0] wInterruptRequest,wInt_2_MMU_InterruptFlag, wInt_2_MMU_IntEnable; 76 | wire wInterrupt0x50; 77 | 78 | dzcpu DZCPU 79 | ( 80 | .iClock( iClock ), 81 | .iReset( iReset ), 82 | .iMCUData( wMMU_ReadData ), 83 | .oMCUAddr( wdZCPU_2_MMU_Addr ), 84 | .oMCUwe( wdZCPU_2_MMU_We ), 85 | .oMCUData( wdZCPU_2_MMU_WriteData ), 86 | .oMcuReadRequest( wdZCPU_2_MMU_ReadRequest ), 87 | .oCurrentZ80Insn( wCurrentZ80Insn ), 88 | .oEof( wdZCPU_Eof ), 89 | .iInterruptRequests( wInterruptRequest ), 90 | .oInterruptJump( wDZCPU_2_Timer_IntDetected ), 91 | .oBranchTaken( wdZCPU_BranchTaken ), 92 | .iJoypad(wButtonRegister[5:0]) 93 | ); 94 | 95 | 96 | interrupt_controller INTERRUPTS 97 | ( 98 | .iClock(iClock ), 99 | .iReset( iReset ), 100 | 101 | .iMcuWe( wMMU_RegWe[2] ), 102 | .iMcuRegSelect(wMMU_RegSelect ), //control register select comes from cpu 103 | .iMcuWriteData( wMMU_RegData ), //what does the cpu want to write 104 | 105 | .oInterruptEnableRegister( wInt_2_MMU_IntEnable ), 106 | .oInterruptFlag( wInt_2_MMU_InterruptFlag), 107 | 108 | 109 | .iInterruptRequest( {5'b0, wInterrupt0x50, 2'b0} ), 110 | .oInterruptResquestPending( wInterruptRequest ) 111 | ); 112 | 113 | timers TIMERS 114 | ( 115 | .iClock( iClock ), 116 | .iReset( iReset ), 117 | .iOpcode( wCurrentZ80Insn ), 118 | .iBranchTaken( wdZCPU_BranchTaken ), 119 | .iEof( wdZCPU_Eof ), 120 | .iMcuWe( wMMU_RegWe[1] ), 121 | .iMcuRegSelect( wMMU_RegSelect ), 122 | .iInterrupt( wDZCPU_2_Timer_IntDetected ), 123 | .iMcuWriteData( wMMU_RegData ), 124 | 125 | //output wire oInterrupt0x50 126 | .oInterrupt0x50( wInterrupt0x50 ) 127 | 128 | ); 129 | 130 | assign wButtonRegister[7:6] = 2'b0; 131 | //IO unit is in charge of marshalling the GameBoy push butons 132 | io IO 133 | ( 134 | .Clock( iClock ), 135 | .Reset( iReset ), 136 | .iP( iButtonRegister ), 137 | .oP( wButtonRegister[5:0] ), 138 | .oIE( wIOInterruptTrigger ) 139 | 140 | ); 141 | 142 | 143 | mmu MMU 144 | ( 145 | .iClock( iClock ), 146 | .iReset( iReset ), 147 | 148 | //CPU 149 | .iCpuReadRequest( wdZCPU_2_MMU_ReadRequest ), 150 | .iGpuReadRequest( wGPU_2_MCU_ReadRequest ), 151 | .iCpuAddr( wdZCPU_2_MMU_Addr ), 152 | .iCpuWe( wdZCPU_2_MMU_We ), 153 | .iCpuData( wdZCPU_2_MMU_WriteData ), 154 | .oCpuData( wMMU_ReadData ), 155 | 156 | //GPU 157 | .oGpuVmemReadData( wMMU_2_GPU_VmemReadData ), 158 | .iGpuAddr( wGPU_2_MCU_Addr ), 159 | .oRegData( wMMU_RegData ), 160 | .oRegSelect( wMMU_RegSelect ), 161 | .oRegWe( wMMU_RegWe ), 162 | 163 | .iGPU_LCDC( wGPU_2_MCU_LCDC ), 164 | .iGPU_STAT( wGPU_2_MCU_STAT ), 165 | .iGPU_SCY( wGPU_2_MCU_SCY ), 166 | .iGPU_SCX( wGPU_2_MCU_SCX ), 167 | .iGPU_LY( wGPU_2_MCU_LY ), 168 | .iGPU_LYC( wGPU_2_MCU_LYC ), 169 | .iGPU_DMA( wGPU_2_MCU_DMA ), 170 | .iGPU_BGP( wGPU_2_MCU_BGP ), 171 | .iGPU_OBP0( wGPU_2_MCU_OBP0 ), 172 | .iGPU_OBP1( wGPU_2_MCU_OBP1 ), 173 | .iGPU_WY( wGPU_2_MCU_WY ), 174 | .iGPU_WX( wGPU_2_MCU_WX ), 175 | 176 | .iInterruptEnable( wInt_2_MMU_IntEnable ), 177 | .iInterruptFlag( wInt_2_MMU_InterruptFlag ), 178 | 179 | //IO 180 | .iButtonRegister( wButtonRegister ) 181 | ); 182 | 183 | 184 | `ifdef VGA_ENABLED 185 | 186 | wire [15:0] wFramBufferWriteData, wVgaFBReadData, wVgaFBReadData_Pre, wFrameBufferReadAddress, wFramBufferWriteAddress; 187 | wire [15:0] wVgaRow, wVgaCol; 188 | wire [3:0] wVgaR, wVgaG, wVgaB; 189 | wire [9:0] wVgaFBReadAddr; 190 | wire [1:0] wVgaColor2Bits; 191 | wire wFramBufferWe; 192 | 193 | RAM_SINGLE_READ_PORT # ( .DATA_WIDTH(16), .ADDR_WIDTH(10), .MEM_SIZE(8192) ) FBUFFER 194 | ( 195 | .Clock( iClock ), //TODO: Should we use graphic clock here? 196 | .iWriteEnable( wFramBufferWe ), 197 | //.iReadAddress0( {3'b0,wFrameBufferReadAddress[15:3]} ), //Divide by 8 198 | .iReadAddress0( wFrameBufferReadAddress ), //Divide by 8 199 | .iWriteAddress( wFramBufferWriteAddress ), 200 | .iDataIn( wFramBufferWriteData ), 201 | .oDataOut0( wVgaFBReadData_Pre ) 202 | 203 | ); 204 | 205 | assign wFrameBufferReadAddress = (wVgaRow << 5) + (wVgaCol >> 3); 206 | 207 | MUXFULLPARALELL_3SEL_GENERIC # (2) MUX_COLOR ( 208 | .Sel( wVgaCol[2:0] ), 209 | .I7( wVgaFBReadData_Pre[1:0]), 210 | .I6( wVgaFBReadData_Pre[3:2]), 211 | .I5( wVgaFBReadData_Pre[5:4]), 212 | .I4( wVgaFBReadData_Pre[7:6]) , 213 | .I3( wVgaFBReadData_Pre[9:8]), 214 | .I2( wVgaFBReadData_Pre[11:10]), 215 | .I1( wVgaFBReadData_Pre[13:12]), 216 | .I0( wVgaFBReadData_Pre[15:14]) , 217 | .O( wVgaColor2Bits ) 218 | ); 219 | 220 | wire [3:0] wRed,wGreen,wBlue; 221 | MUXFULLPARALELL_2SEL_GENERIC # (12) MUX_COLOR_OUT ( 222 | .Sel( wVgaColor2Bits ), 223 | .I0( {4'b0000, 4'b0000, 4'b0000 } ), 224 | .I1( {4'b1111, 4'b0000, 4'b0000 } ), 225 | .I2( {4'b0000, 4'b1111, 4'b0000 } ), 226 | .I3( {4'b0000, 4'b0000, 4'b1111 }) , 227 | .O( {wRed,wGreen,wBlue} ) 228 | ); 229 | 230 | 231 | 232 | assign oVgaRed = ( wVgaRow >= 16'd255 || wVgaCol >= 255 ) ? 4'b0111 : wRed; 233 | assign oVgaGreen = ( wVgaRow >= 16'd255 || wVgaCol >= 255 ) ? 4'b0111 : wGreen; 234 | assign oVgaBlue = ( wVgaRow >= 16'd255 || wVgaCol >= 255 ) ? 4'b0111 : wBlue; 235 | 236 | 237 | VgaController VGA 238 | ( 239 | .Clock(iClock), 240 | .Reset(iReset), 241 | .oVgaVsync( oVgaVsync ), 242 | .oVgaHsync( oVgaHsync ), 243 | /*.oVgaRed( oVgaRed ), 244 | .oVgaGreen( oVgaGreen ), 245 | .oVgaBlue( oVgaBlue ),*/ 246 | .oRow( wVgaRow ), 247 | .oCol( wVgaCol ) 248 | 249 | ); 250 | 251 | `ifndef XILINX_IP 252 | assign oFrameBufferAddr = wFramBufferWriteAddress; 253 | assign oFrameBufferData = wFramBufferWriteData; 254 | assign oFrameBufferWe = wFramBufferWe; 255 | `endif 256 | 257 | `endif 258 | 259 | gpu GPU 260 | ( 261 | .iClock( iClock ), 262 | .iReset( iReset ), 263 | `ifndef VGA_ENABLED 264 | .oFramBufferWe( oFrameBufferWe ), 265 | .oFramBufferData( oFrameBufferData ), 266 | .oFramBufferAddr( oFrameBufferAddr ), 267 | `else 268 | .oFramBufferWe( wFramBufferWe ), 269 | .oFramBufferData( wFramBufferWriteData ), 270 | .oFramBufferAddr( wFramBufferWriteAddress ), 271 | 272 | `endif 273 | .oMcuAddr( wGPU_2_MCU_Addr ), 274 | .oMcuReadRequest( wGPU_2_MCU_ReadRequest ), 275 | .iMcuRegSelect( wMMU_RegSelect), 276 | .iMcuWriteData( wMMU_RegData ), 277 | .iMcuReadData( wMMU_2_GPU_VmemReadData ), 278 | .iMcuWe( wMMU_RegWe[0] ), 279 | .oSTAT( wGPU_2_MCU_STAT ), 280 | .oLCDC( wGPU_2_MCU_LCDC ), 281 | .oSCY( wGPU_2_MCU_SCY ), 282 | .oSCX( wGPU_2_MCU_SCX ), 283 | .oLY( wGPU_2_MCU_LY ), 284 | .oLYC( wGPU_2_MCU_LYC ), 285 | .oDMA( wGPU_2_MCU_DMA ), 286 | .oBGP( wGPU_2_MCU_BGP ), 287 | .oOBP0( wGPU_2_MCU_OBP0 ), 288 | .oOBP1( wGPU_2_MCU_OBP1 ), 289 | .oWY( wGPU_2_MCU_WY ), 290 | .oWX( wGPU_2_MCU_WX ) 291 | ); 292 | 293 | endmodule 294 | -------------------------------------------------------------------------------- /rtl/bios.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | //////////////////////////////////////////////////////////////////////////////////// 3 | // 4 | // pGB, yet another FPGA fully functional and super fun GB classic clone! 5 | // Copyright (C) 2015-2016 Diego Valverde (diego.valverde.g@gmail.com) 6 | // 7 | // This program is free software; you can redistribute it and/or 8 | // modify it under the terms of the GNU General Public License 9 | // as published by the Free Software Foundation; either version 2 10 | // of the License, or (at your option) any later version. 11 | // 12 | // This program is distributed in the hope that it will be useful, 13 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 14 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 | // GNU General Public License for more details. 16 | // 17 | // You should have received a copy of the GNU General Public License 18 | // along with this program; if not, write to the Free Software 19 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 | // 21 | //////////////////////////////////////////////////////////////////////////////////// 22 | 23 | module bios 24 | ( 25 | input wire iClock, 26 | input wire [7:0] iAddr, 27 | output reg [7:0] oData 28 | ); 29 | 30 | 31 | always @ ( posedge iClock ) 32 | begin 33 | case ( iAddr ) 34 | 8'd0: oData = 8'h31; 35 | 8'd1: oData = 8'hFE; 36 | 8'd2 : oData = 8'hFF; 37 | 8'd3 : oData = 8'hAF; 38 | 8'd4 : oData = 8'h21; 39 | 8'd5 : oData = 8'hFF; 40 | 8'd6 : oData = 8'h9F; 41 | 8'd7 : oData = 8'h32; 42 | 8'd8 : oData = 8'hCB; 43 | 8'd9 : oData = 8'h7C; 44 | 8'd10 : oData = 8'h20; 45 | 8'd11 : oData = 8'hFB; 46 | 8'd12 : oData = 8'h21; 47 | 8'd13 : oData = 8'h26; 48 | 8'd14 : oData = 8'hFF; 49 | 8'd15 : oData = 8'h0E; 50 | 8'd16 : oData = 8'h11; 51 | 8'd17 : oData = 8'h3E; 52 | 8'd18 : oData = 8'h80; 53 | 8'd19 : oData = 8'h32; 54 | 8'd20 : oData = 8'hE2; 55 | 8'd21 : oData = 8'h0C; 56 | 8'd22 : oData = 8'h3E; 57 | 8'd23 : oData = 8'hF3; 58 | 8'd24 : oData = 8'hE2; 59 | 8'd25 : oData = 8'h32; 60 | 8'd26 : oData = 8'h3E; 61 | 8'd27 : oData = 8'h77; 62 | 8'd28 : oData = 8'h77; 63 | 8'd29 : oData = 8'h3E; 64 | 8'd30 : oData = 8'hFC; 65 | 8'd31 : oData = 8'hE0; 66 | 8'd32 : oData = 8'h47; 67 | 8'd33 : oData = 8'h11; 68 | 8'd34 : oData = 8'h04; 69 | 8'd35 : oData = 8'h01; 70 | 8'd36 : oData = 8'h21; 71 | 8'd37 : oData = 8'h10; 72 | 8'd38 : oData = 8'h80; 73 | 8'd39 : oData = 8'h1A; 74 | 8'd40 : oData = 8'hCD; 75 | 8'd41 : oData = 8'h95; 76 | 8'd42 : oData = 8'h00; 77 | 8'd43 : oData = 8'hCD; 78 | 8'd44 : oData = 8'h96; 79 | 8'd45 : oData = 8'h00; 80 | 8'd46 : oData = 8'h13; 81 | 8'd47 : oData = 8'h7B; 82 | 8'd48 : oData = 8'hFE; 83 | 8'd49 : oData = 8'h34; 84 | 8'd50 : oData = 8'h20; 85 | 8'd51 : oData = 8'hF3; 86 | 8'd52 : oData = 8'h11; 87 | 8'd53 : oData = 8'hD8; 88 | 8'd54 : oData = 8'h00; 89 | 8'd55 : oData = 8'h06; 90 | 8'd56 : oData = 8'h08; 91 | 8'd57 : oData = 8'h1A; 92 | 8'd58 : oData = 8'h13; 93 | 8'd59 : oData = 8'h22; 94 | 8'd60 : oData = 8'h23; 95 | 8'd61 : oData = 8'h05; 96 | 8'd62 : oData = 8'h20; 97 | 8'd63 : oData = 8'hF9; 98 | 8'd64 : oData = 8'h3E; 99 | 8'd65 : oData = 8'h19; 100 | 8'd66 : oData = 8'hEA; 101 | 8'd67 : oData = 8'h10; 102 | 8'd68 : oData = 8'h99; 103 | 8'd69 : oData = 8'h21; 104 | 8'd70 : oData = 8'h2F; 105 | 8'd71 : oData = 8'h99; 106 | 8'd72 : oData = 8'h0E; 107 | 8'd73 : oData = 8'h0C; 108 | 8'd74 : oData = 8'h3D; 109 | 8'd75 : oData = 8'h28; 110 | 8'd76 : oData = 8'h08; 111 | 8'd77 : oData = 8'h32; 112 | 8'd78 : oData = 8'h0D; 113 | 8'd79 : oData = 8'h20; 114 | 8'd80 : oData = 8'hF9; 115 | 8'd81 : oData = 8'h2E; 116 | 8'd82 : oData = 8'h0F; 117 | 8'd83 : oData = 8'h18; 118 | 8'd84 : oData = 8'hF3; 119 | 8'd85 : oData = 8'h67; 120 | 8'd86 : oData = 8'h3E; 121 | 8'd87 : oData = 8'h64; 122 | 8'd88 : oData = 8'h57; 123 | 8'd89 : oData = 8'hE0; 124 | 8'd90 : oData = 8'h42; 125 | 8'd91 : oData = 8'h3E; 126 | 8'd92 : oData = 8'h91; 127 | 8'd93 : oData = 8'hE0; 128 | 8'd94 : oData = 8'h40; 129 | 8'd95 : oData = 8'h04; 130 | 8'd96 : oData = 8'h1E; 131 | 8'd97 : oData = 8'h02; 132 | 8'd98 : oData = 8'h0E; 133 | 8'd99 : oData = 8'h0C; 134 | 8'd100 : oData = 8'hF0; 135 | 8'd101 : oData = 8'h44; 136 | 8'd102 : oData = 8'hFE; 137 | 8'd103 : oData = 8'h90; 138 | 8'd104 : oData = 8'h20; 139 | 8'd105 : oData = 8'hFA; 140 | 8'd106 : oData = 8'h0D; 141 | 8'd107 : oData = 8'h20; 142 | 8'd108 : oData = 8'hF7; 143 | 8'd109 : oData = 8'h1D; 144 | 8'd110 : oData = 8'h20; 145 | 8'd111 : oData = 8'hF2; 146 | 8'd112 : oData = 8'h0E; 147 | 8'd113 : oData = 8'h13; 148 | 8'd114 : oData = 8'h24; 149 | 8'd115 : oData = 8'h7C; 150 | 8'd116 : oData = 8'h1E; 151 | 8'd117 : oData = 8'h83; 152 | 8'd118 : oData = 8'hFE; 153 | 8'd119 : oData = 8'h62; 154 | 8'd120 : oData = 8'h28; 155 | 8'd121 : oData = 8'h06; 156 | 8'd122 : oData = 8'h1E; 157 | 8'd123 : oData = 8'hC1; 158 | 8'd124 : oData = 8'hFE; 159 | 8'd125 : oData = 8'h64; 160 | 8'd126 : oData = 8'h20; 161 | 8'd127 : oData = 8'h06; 162 | 8'd128 : oData = 8'h7B; 163 | 8'd129 : oData = 8'hE2; 164 | 8'd130 : oData = 8'h0C; 165 | 8'd131 : oData = 8'h3E; 166 | 8'd132 : oData = 8'h87; 167 | 8'd133 : oData = 8'hF2; 168 | 8'd134 : oData = 8'hF0; 169 | 8'd135 : oData = 8'h42; 170 | 8'd136 : oData = 8'h90; 171 | 8'd137 : oData = 8'hE0; 172 | 8'd138 : oData = 8'h42; 173 | 8'd139 : oData = 8'h15; 174 | 8'd140 : oData = 8'h20; 175 | 8'd141 : oData = 8'hD2; 176 | 8'd142 : oData = 8'h05; 177 | 8'd143 : oData = 8'h20; 178 | 8'd144 : oData = 8'h4F; 179 | 8'd145 : oData = 8'h16; 180 | 8'd146 : oData = 8'h20; 181 | 8'd147 : oData = 8'h18; 182 | 8'd148 : oData = 8'hCB; 183 | 8'd149 : oData = 8'h4F; 184 | 8'd150 : oData = 8'h06; 185 | 8'd151 : oData = 8'h04; 186 | 8'd152 : oData = 8'hC5; 187 | 8'd153 : oData = 8'hCB; 188 | 8'd154 : oData = 8'h11; 189 | 8'd155 : oData = 8'h17; 190 | 8'd156 : oData = 8'hC1; 191 | 8'd157 : oData = 8'hCB; 192 | 8'd158 : oData = 8'h11; 193 | 8'd159 : oData = 8'h17; 194 | 8'd160 : oData = 8'h05; 195 | 8'd161 : oData = 8'h20; 196 | 8'd162 : oData = 8'hF5; 197 | 8'd163 : oData = 8'h22; 198 | 8'd164 : oData = 8'h23; 199 | 8'd165 : oData = 8'h22; 200 | 8'd166 : oData = 8'h23; 201 | 8'd167 : oData = 8'hC9; 202 | 8'd168 : oData = 8'hCE; 203 | 8'd169 : oData = 8'hED; 204 | 8'd170 : oData = 8'h66; 205 | 8'd171 : oData = 8'h66; 206 | 8'd172 : oData = 8'hCC; 207 | 8'd173 : oData = 8'h0D; 208 | 8'd174 : oData = 8'h00; 209 | 8'd175 : oData = 8'h0B; 210 | 8'd176 : oData = 8'h03; 211 | 8'd177 : oData = 8'h73; 212 | 8'd178 : oData = 8'h00; 213 | 8'd179 : oData = 8'h83; 214 | 8'd180 : oData = 8'h00; 215 | 8'd181 : oData = 8'h0C; 216 | 8'd182 : oData = 8'h00; 217 | 8'd183 : oData = 8'h0D; 218 | 8'd184 : oData = 8'h00; 219 | 8'd185 : oData = 8'h08; 220 | 8'd186 : oData = 8'h11; 221 | 8'd187 : oData = 8'h1F; 222 | 8'd188 : oData = 8'h88; 223 | 8'd189 : oData = 8'h89; 224 | 8'd190 : oData = 8'h00; 225 | 8'd191 : oData = 8'h0E; 226 | 8'd192 : oData = 8'hDC; 227 | 8'd193 : oData = 8'hCC; 228 | 8'd194 : oData = 8'h6E; 229 | 8'd195 : oData = 8'hE6; 230 | 8'd196 : oData = 8'hDD; 231 | 8'd197 : oData = 8'hDD; 232 | 8'd198 : oData = 8'hD9; 233 | 8'd199 : oData = 8'h99; 234 | 8'd200 : oData = 8'hBB; 235 | 8'd201 : oData = 8'hBB; 236 | 8'd202 : oData = 8'h67; 237 | 8'd203 : oData = 8'h63; 238 | 8'd204 : oData = 8'h6E; 239 | 8'd205 : oData = 8'h0E; 240 | 8'd206 : oData = 8'hEC; 241 | 8'd207 : oData = 8'hCC; 242 | 8'd208 : oData = 8'hDD; 243 | 8'd209 : oData = 8'hDC; 244 | 8'd210 : oData = 8'h99; 245 | 8'd211 : oData = 8'h9F; 246 | 8'd212 : oData = 8'hBB; 247 | 8'd213 : oData = 8'hB9; 248 | 8'd214 : oData = 8'h33; 249 | 8'd215 : oData = 8'h3E; 250 | 8'd216 : oData = 8'h3c; 251 | 8'd217 : oData = 8'h42; 252 | 8'd218 : oData = 8'hB9; 253 | 8'd219 : oData = 8'hA5; 254 | 8'd220 : oData = 8'hB9; 255 | 8'd221 : oData = 8'hA5; 256 | 8'd222 : oData = 8'h42; 257 | 8'd223 : oData = 8'h3C; 258 | 8'd224 : oData = 8'h21; 259 | 8'd225 : oData = 8'h04; 260 | 8'd226 : oData = 8'h01; 261 | 8'd227 : oData = 8'h11; 262 | 8'd228 : oData = 8'hA8; 263 | 8'd229 : oData = 8'h00; 264 | 8'd230 : oData = 8'h1A; 265 | 8'd231 : oData = 8'h13; 266 | 8'd232 : oData = 8'hBE; 267 | 8'd233 : oData = 8'h20; 268 | 8'd234 : oData = 8'hFE; 269 | 8'd235 : oData = 8'h23; 270 | 8'd236 : oData = 8'h7D; 271 | 8'd237 : oData = 8'hFE; 272 | 8'd238 : oData = 8'h34; 273 | 8'd239 : oData = 8'h20; 274 | 8'd240 : oData = 8'hF5; 275 | 8'd241 : oData = 8'h06; 276 | 8'd242 : oData = 8'h19; 277 | 8'd243 : oData = 8'h78; 278 | 8'd244 : oData = 8'h86; 279 | 8'd245 : oData = 8'h23; 280 | 8'd246 : oData = 8'h05; 281 | 8'd247 : oData = 8'h20; 282 | 8'd248 : oData = 8'hFB; 283 | 8'd249 : oData = 8'h86; 284 | 8'd250 : oData = 8'h20; 285 | 8'd251 : oData = 8'hFE; 286 | 8'd252 : oData = 8'h3E; 287 | 8'd253 : oData = 8'h01; 288 | 8'd254 : oData = 8'hE0; 289 | 8'd255 : oData = 8'h50; 290 | default: 291 | oData = 8'h0; 292 | endcase 293 | end 294 | 295 | 296 | endmodule 297 | -------------------------------------------------------------------------------- /rtl/sound_controller_modules/SoundControllerChannel4.v: -------------------------------------------------------------------------------- 1 | //////////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // pGB, yet another FPGA fully functional and super fun GB classic clone! 4 | // Copyright (C) 2015-2016 Diego Valverde (diego.valverde.g@gmail.com) 5 | // 6 | // This program is free software; you can redistribute it and/or 7 | // modify it under the terms of the GNU General Public License 8 | // as published by the Free Software Foundation; either version 2 9 | // of the License, or (at your option) any later version. 10 | // 11 | // This program is distributed in the hope that it will be useful, 12 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | // GNU General Public License for more details. 15 | // 16 | // You should have received a copy of the GNU General Public License 17 | // along with this program; if not, write to the Free Software 18 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 19 | // 20 | //////////////////////////////////////////////////////////////////////////////////// 21 | // Sound module, channel 4. White noise generation module using LFSR. 22 | //////////////////////////////////////////////////////////////////////////////////// 23 | 24 | 25 | module SoundCtrlChannel4 //parameters 26 | ( 27 | input wire iClock, //CPU CLOCK, 4194304Hz 28 | input wire iReset, 29 | input wire iOsc64, //OSC1 clock 64Hz 30 | input wire iOsc256, //OSC1 clock 256Hz 31 | 32 | input wire [7:0] iNR41, 33 | input wire [7:0] iNR42, 34 | input wire [7:0] iNR43, 35 | input wire [7:0] iNR44, 36 | 37 | output reg [4:0] oOut, 38 | output wire oOnFlag 39 | ); 40 | 41 | 42 | reg [5:0] rLength; 43 | reg [19:0] rLengthCounter; 44 | reg rLengthComplete; // Channe disable. 45 | 46 | wire rTone; 47 | 48 | reg [3:0] rStep; 49 | reg [18:0] rStepTime; 50 | reg [18:0] rStepCounter; 51 | reg [3:0] rInitialValue; 52 | reg rEvelopeMode; 53 | 54 | reg [2:0] rDivRatioFreq; 55 | reg [3:0] rShiftClockFreq; 56 | 57 | reg rPolCoutSteps; 58 | 59 | reg rClkDiv; 60 | reg [5:0] rDivRatioCounter; 61 | 62 | reg rCountPre; 63 | reg [14:0] rShiftCounter; 64 | 65 | reg rTimedMode; 66 | 67 | wire [4:0] up_value, down_value; 68 | 69 | // register load 70 | always @(posedge iClock) begin 71 | if (iReset || iNR44[7]) begin // Register reload and counters restart. 72 | 73 | rLength <= iNR41[5:0]; 74 | rLengthCounter <= 64-iNR41[5:0]; // Decrements to zero then load rLength. 75 | rLengthComplete <= 0; // Disables channel when is asserted. 76 | 77 | rStepTime <= iNR42[2:0]; 78 | rStepCounter <= iNR42[2:0]; // Decrements to zero then load rStepTime. 79 | rEvelopeMode <= iNR42[3]; 80 | rInitialValue <= iNR42[7:4]; 81 | rStep <= iNR42[7:4]; 82 | 83 | rDivRatioFreq <= iNR43[2:0]; 84 | 85 | // rDivRatioCounter <= 6'd16; 86 | if (iNR43[2:0]==0) begin 87 | rDivRatioCounter[5:0] <= 6'd4; 88 | end 89 | else begin 90 | rDivRatioCounter[5:0] <= {iNR43[2:0],3'b0}; 91 | end 92 | 93 | // rDivRatioCounter <= (iNR43[2:0]==0) ? 6'd4 : (iNR43[2:0]<<3) ; // fcpu/8 94 | rClkDiv <= 0; 95 | 96 | rPolCoutSteps <= iNR43[3]; 97 | 98 | rShiftClockFreq <= iNR43[7:4]; 99 | rShiftCounter <= (iNR43[7:4] < 15) ? 1 << iNR43[7:4] : 1 << 14; 100 | rCountPre <= 0; 101 | 102 | rTimedMode <= iNR44[6]; 103 | end 104 | end 105 | 106 | // step gen: generates the output amplitud value. 107 | always @(posedge iOsc64) begin 108 | if (rStepTime != 0) begin // Check if channel is enabled. 109 | if (rStepCounter ==1 ) begin 110 | rStepCounter <= rStepTime; // Reset counter. 111 | if(rEvelopeMode) begin // Envelope mode. 112 | rStep <= ((rStep == 4'hF) ? rStep : rStep+1); //INCREASES ONLY IF STEP IF LOWER THAN TOP VALUE 113 | end 114 | else begin 115 | rStep <= ((rStep == 4'h0) ? rStep : rStep-1); //DECREASES ONLY IF STEP IF LOWER THAN BOTTOM VALUE 116 | end 117 | end 118 | else begin 119 | rStepCounter <= rStepCounter-1; 120 | end 121 | end 122 | end 123 | 124 | 125 | // clock divider 126 | always @(posedge iClock) begin 127 | if (rDivRatioCounter === 0) begin 128 | rClkDiv <= ~rClkDiv; 129 | 130 | if (rDivRatioFreq==0) begin 131 | rDivRatioCounter <= 6'd4; 132 | end 133 | else begin 134 | rDivRatioCounter <= {rDivRatioFreq,3'b0}; 135 | end 136 | // rDivRatioCounter <= 6'd16; 137 | // rDivRatioCounter <= (rDivRatioFreq==0) ? 6'd4 : (rDivRatioFreq<<3) ; // fcpu/8 138 | end 139 | else begin 140 | rDivRatioCounter <= rDivRatioCounter-1; 141 | end 142 | end 143 | 144 | // counter pre-scaler 145 | always @(posedge rClkDiv) begin 146 | if (rShiftCounter == 0) begin 147 | rCountPre <= ~rCountPre; 148 | rShiftCounter <= (rShiftClockFreq < 15) ? 1 << rShiftClockFreq : 1 << 14; 149 | end 150 | else begin 151 | rShiftCounter <= rShiftCounter-1; 152 | end 153 | end 154 | 155 | // white noise gen 156 | lfsr l0 ( 157 | .iClock(rCountPre), 158 | .iReset(iReset), 159 | .iStages(rPolCoutSteps), 160 | .oOut(rTone) 161 | ); 162 | 163 | 164 | // timmer: enable or disable channel output. 165 | always @(posedge iOsc256) begin 166 | if (rLengthCounter == 0) begin 167 | rLengthCounter <= 64-rLength; 168 | rLengthComplete <= rTimedMode; // Disable channel only if timmer is enabled. 169 | end 170 | else begin 171 | rLengthCounter <= rLengthCounter-1; 172 | end 173 | end 174 | 175 | //re-map mux 176 | assign up_value = 5'd15 + rStep; 177 | assign down_value = 5'd15 - rStep; 178 | 179 | always @(posedge iClock) begin 180 | if (rLengthComplete) begin 181 | oOut[4:0] <= 5'd15; 182 | end 183 | else begin 184 | if (rTone) begin 185 | oOut[4:0] <= up_value[4:0]; 186 | end 187 | else begin 188 | oOut[4:0] <= down_value[4:0]; 189 | end 190 | end 191 | end 192 | 193 | assign oOnFlag = rLengthComplete; 194 | endmodule 195 | 196 | // misc modules. 197 | 198 | module lfsr //parameters 199 | ( 200 | input wire iClock, 201 | input wire iReset, 202 | input wire iStages, 203 | output oOut 204 | ); 205 | 206 | //Stage conection wires. 207 | wire wS0S1, wS1S2, wS2S3, wS3S4, wS4S5, wS5S6, wS6S7, wS7S8; 208 | wire wS8S9, wS9S10, wS10S11, wS11S12, wS12S13, wS13S14, wS14S15, wS15S16; 209 | 210 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_0 ( 211 | .Clock(iClock), 212 | .Reset(iReset), 213 | .Enable(1), 214 | .iInitial(1), 215 | .D(oOut ^ wS6S7), 216 | .Q(wS0S1) 217 | ); 218 | 219 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_1 ( 220 | .Clock(iClock), 221 | .Reset(iReset), 222 | .Enable(1), 223 | .iInitial(1), 224 | .D(wS0S1), 225 | .Q(wS1S2) 226 | ); 227 | 228 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_2 ( 229 | .Clock(iClock), 230 | .Reset(iReset), 231 | .Enable(1), 232 | .iInitial(1), 233 | .D(wS1S2), 234 | .Q(wS2S3) 235 | ); 236 | 237 | 238 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_3 ( 239 | .Clock(iClock), 240 | .Reset(iReset), 241 | .Enable(1), 242 | .iInitial(1), 243 | .D(wS2S3), 244 | .Q(wS3S4) 245 | ); 246 | 247 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_4 ( 248 | .Clock(iClock), 249 | .Reset(iReset), 250 | .Enable(1), 251 | .iInitial(1), 252 | .D(wS3S4), 253 | .Q(wS4S5) 254 | ); 255 | 256 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_5 ( 257 | .Clock(iClock), 258 | .Reset(iReset), 259 | .Enable(1), 260 | .iInitial(1), 261 | .D(wS4S5), 262 | .Q(wS5S6) 263 | ); 264 | 265 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_6 ( 266 | .Clock(iClock), 267 | .Reset(iReset), 268 | .Enable(1), 269 | .iInitial(1), 270 | .D(wS5S6), 271 | .Q(wS6S7) 272 | ); 273 | 274 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_7 ( 275 | .Clock(iClock), 276 | .Reset(iReset), 277 | .Enable(1), 278 | .iInitial(1), 279 | .D(wS6S7), 280 | .Q(wS7S8) 281 | ); 282 | 283 | 284 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_8 ( 285 | .Clock(iClock), 286 | .Reset(iReset), 287 | .Enable(1), 288 | .iInitial(1), 289 | .D(wS7S8), 290 | .Q(wS8S9) 291 | ); 292 | 293 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_9 ( 294 | .Clock(iClock), 295 | .Reset(iReset), 296 | .Enable(1), 297 | .iInitial(1), 298 | .D(wS8S9), 299 | .Q(wS9S10) 300 | ); 301 | 302 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_10 ( 303 | .Clock(iClock), 304 | .Reset(iReset), 305 | .Enable(1), 306 | .iInitial(1), 307 | .D(wS9S10), 308 | .Q(wS10S11) 309 | ); 310 | 311 | 312 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_11 ( 313 | .Clock(iClock), 314 | .Reset(iReset), 315 | .Enable(1), 316 | .iInitial(1), 317 | .D(wS10S11), 318 | .Q(wS11S12) 319 | ); 320 | 321 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_12 ( 322 | .Clock(iClock), 323 | .Reset(iReset), 324 | .Enable(1), 325 | .iInitial(1), 326 | .D(wS11S12), 327 | .Q(wS12S13) 328 | ); 329 | 330 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_13 ( 331 | .Clock(iClock), 332 | .Reset(iReset), 333 | .Enable(1), 334 | .iInitial(1), 335 | .D(wS12S13), 336 | .Q(wS13S14) 337 | ); 338 | 339 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_14 ( 340 | .Clock(iClock), 341 | .Reset(iReset), 342 | .Enable(1), 343 | .iInitial(1), 344 | .D(wS13S14), 345 | .Q(wS14S15) 346 | ); 347 | 348 | FFD_POSEDGE_ASYNCRONOUS_RESET_INIT # ( 1 ) FF_CH4_15 ( 349 | .Clock(iClock), 350 | .Reset(iReset), 351 | .Enable(1), 352 | .iInitial(1), 353 | .D(wS14S15), 354 | .Q(wS15S16) 355 | ); 356 | 357 | assign oOut = (iStages) ? wS7S8 : wS15S16 ; 358 | endmodule 359 | -------------------------------------------------------------------------------- /rtl/gpu_ucode_rom.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | `include "gpu_definitions.v" 3 | //////////////////////////////////////////////////////////////////////////////////// 4 | // 5 | // pGB, yet another FPGA fully functional and super fun GB classic clone! 6 | // Copyright (C) 2015-2016 Diego Valverde (diego.valverde.g@gmail.com) 7 | // 8 | // This program is free software; you can redistribute it and/or 9 | // modify it under the terms of the GNU General Public License 10 | // as published by the Free Software Foundation; either version 2 11 | // of the License, or (at your option) any later version. 12 | // 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | // 18 | // You should have received a copy of the GNU General Public License 19 | // along with this program; if not, write to the Free Software 20 | // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 21 | // 22 | //////////////////////////////////////////////////////////////////////////////////// 23 | 24 | 25 | module gpu_ucode_rom 26 | ( 27 | input wire[7:0] iAddr, 28 | output reg [`GPU_UOP_SZ-1:0] oUop 29 | ); 30 | 31 | 32 | 33 | always @ ( iAddr ) 34 | begin 35 | case ( iAddr ) 36 | 37 | /* 38 | /////////////PSEUDO CODE FOR BETTER UNDERSTANDING//////////////////// 39 | 40 | state = SCANLINE_VRAM_READ 41 | cur_tile = 0 42 | 1: 43 | tile_row = 0 44 | 2: 45 | r2 = 32 46 | 3: 47 | 48 | vmem_addr = bgmoffset + cur_tile 49 | grvmem 50 | vmem_addr = bgtoffset + tile_row + vmem_data_shl_4 51 | grvmem 52 | 53 | bh = vmem_data 54 | vmem_addr++ 55 | grvmem 56 | bl = vmem_data 57 | gwfbuffer 58 | 59 | cur_tile++ 60 | r2-- 61 | if (r2 > 0) 62 | goto 3 63 | 64 | 65 | tile_row += 2; 66 | ly++ 67 | if (tile_row <= f) 68 | cur_tile -= 32 69 | goto 2; 70 | else 71 | goto 1 72 | 73 | 74 | */ 75 | /////////////////////////////////////////////////////////////////////////// 76 | //defines code for getting the first tile and applying color pallete to it 77 | 0: oUop = { `gnop, `gnull, `gnull, `gnull }; //always has to be a nop because of pc definition 78 | 1: oUop = { `gwrl, `state, `SCANLINE_VRAM_READ };// writes a literal to register state for cpu to know which state the GPU currently is 79 | 80 | //Frame buffer render main loop. Ie. current_tile = 0 81 | 2: oUop = { `gwrr, `cur_tile, `scy_shl_5__plus_scx, `gnull };//which tile am I on, (oScy >>3) <<5 + oScx) 82 | 3: oUop = { `gwrr, `WinTile, `Win_index, `gnull }; // set up window tile index 83 | //Next tile row loop 84 | 4: oUop = { `gwrr, `tile_row, `scy_tile_row_offset, `gnull}; // which tile row am I on 85 | // 86 | 5: oUop = { `gwrl, `r2, 12'd32 };//assign a literal to r2, 32 tiles 87 | 88 | //Current tile render loop 89 | 6: oUop = { `gadd, `vmem_addr, `bgmoffset, `cur_tile };// adds current tile with bg offset to get vmem adress to know where to read 90 | 7: oUop = { `grvmem, `gnull, `gnull, `gnull };//reads vmem and stores in vmem_data 91 | 8: oUop = { `gwrr, `r3, `vmem_addr, `gnull };// store vmem adress in r3 92 | 9: oUop = { `gadd, `r1,`vmem_data_shl_4, `tile_row };//add tile row with vmem data shifted left by 4 93 | 10: oUop = { `gadd, `vmem_addr, `r1, `bgtoffset };// get address for tile memory with r1 and BG tile offset 94 | 11: oUop = { `grvmem, `gnull, `gnull, `gnull };//read from tile memory stores in vmem data 95 | 12: oUop = { `gwrr, `bh, `vmem_data, `gnull };// save in BH for high byte 96 | 13: oUop = { `gaddl, `vmem_addr, 12'd1 };// get adress for BL adding one to current adress, reads next byte 97 | 14: oUop = { `grvmem, `gnull, `gnull, `gnull }; // save in vmem data 98 | 15: oUop = { `gwrr, `bl, `vmem_data, `gnull };//save in BL for low byte 99 | 16: oUop = { `gwfbuffer, `gnull,`gnull, `gnull};// BH and BL go through bg pallete and result gets saved in framebuffer 100 | 101 | /////////////////////////uCode for sprite loop///////////////////////////////////// 102 | 103 | 17: oUop = {`gwrl, `r6, 12'b10}; // set bit 2 as 1 for next oUopp 104 | 18: oUop = {`gand, `r3, `r6, `lcdc}; //and bitwise for r6 and lcdc[1] = 1 sprites are on 105 | 19: oUop = {`gjz,`skip_the_sprites}; 106 | 20: 107 | begin 108 | oUop = {`gwrl, `r6, 12'd0}; //we have a maximum of 40 sprites x= 39*4 because if 4 byte descriptors 109 | 110 | end 111 | 112 | 21: oUop = {`gadd, `vmem_addr, `r6, `oam_offset}; //get address of sprite 113 | 22: oUop = {`grvmem, `gnull, `gnull, `gnull}; //store vmem data loads first byte of sprite descriptor 114 | 23: oUop = {`gsubl, `vmem_data, 12'd0}; //Test to see if the sprite_y_coord is zero 115 | 24: oUop = {`gjz, `get_next_sprite}; //if y coord is zero jump to next sprite 116 | 25: oUop = {`gwrl,`r4 , 12'd16}; //Since the sprite_y_coord was no zero, we need to substract 16 in order to obtain the real sprite_y_coord 117 | 26: oUop = {`gsub,`sprite_y_coord ,`vmem_data,`r4}; //get y coord of the sprite 118 | 27: oUop = {`gaddl, `vmem_addr, 12'd1}; //get address for next byte of sprite descriptor 119 | 28: oUop = {`grvmem, `gnull,`gnull,`gnull}; 120 | 29: oUop = {`gsubl, `vmem_data, 12'd0}; //Test to see if the sprite_x_coord is zero 121 | 30: oUop = {`gjz, `get_next_sprite}; //if x coord is zero jump to next sprite 122 | 31: oUop = {`gwrl,`r4 , 12'd8}; 123 | 32: oUop = {`gsub, `sprite_x_coord ,`vmem_data ,`r4 }; //get x coord 124 | 33: oUop = {`gnop, `gnull, `gnull, `gnull}; //{`gsub, `r5, `tile_column, `vmem_data}; 125 | 34: oUop = {`gsprtt, `r4, `sprite_x_coord, `sprite_y_coord}; //Test if the sprite is in the current tile 126 | 35: oUop = {`gjz, `get_next_sprite}; 127 | //Fetch sprite tile number 128 | 36: oUop = {`gaddl, `vmem_addr, 12'd1};//get next byte sprite index 129 | 37: oUop = {`grvmem, `gnull,`gnull,`gnull}; 130 | 38: oUop = {`gadd, `r4 ,`vmem_data_shl_4, `tile_row };//`sprite_current_row_offset}; //define sprite tile index shifted by 4 to the left would get added with bgomffset for tile memory read 131 | 39: oUop = {`gaddl, `vmem_addr, 12'd1};//get next byte sprite options 132 | 40: oUop = {`grvmem, `gnull,`gnull,`gnull}; 133 | 41: oUop = {`gwrr, `sprite_info,`vmem_data}; //define `sprite_info bits are important for effects flips and flashes 134 | //TODO DEFINE LOGIC FOR SpriteOPTIONS (LA FLECHA DE TETRIS NO TIENE OPTIONS ENTONCES QUIERO PROBAR DIBUJARLA SIN HACER LA PARTE 135 | //DE OPTIONS) 136 | //GO read tile memory 137 | 138 | 42: oUop = {`gadd, `vmem_addr,`bgtoffset,`r4}; //by adding this two you get the address of the tile memory 139 | 43: oUop = {`grvmem,`gnull,`gnull,`gnull}; 140 | 44: oUop = {`gwrr, `sh, `vmem_data, `gnull}; //first tile high byte for current sprite 141 | 45: oUop = {`gaddl, `vmem_addr, 12'd1}; 142 | 46: oUop = {`grvmem, `gnull,`gnull,`gnull}; 143 | 47: oUop = {`gwrr, `sl,`vmem_data, `gnull}; //second tile low byte for current sprite 144 | 48: oUop = {`gnop, `gnull, `gnull, `gnull};//{`glsprtt, `gnull, `tile_row,`sprite_y_coord}; //test if sprite is in current row 145 | 49: oUop = {`gnop, `gnull, `gnull, `gnull};//{`gjz,`get_next_sprite}; 146 | //TODO LOGIC FOR BACKGROUND AND FOREGROUND display for sprites 147 | //sprite palette logic 148 | 50: oUop = {`gwfbuffer, `gnull,`gnull, `gnull};// SH and SL go through sprite palletes and result gets saved in framebuffer 149 | //get_next_sprite 150 | 51: oUop = {`gaddl,`r6, 12'd4}; 151 | 52: oUop = {`gsubl,`r6, 12'd156};//39*4 = 156 152 | 53: begin 153 | //$display("DRAW THE ARROW PLZ \n"); 154 | //oUop = {`gjnz, 15'd20}; // end of sprites go to next tile 155 | oUop = {`gwrr, `sprite_current_row_offset, `tile_row, `gnull}; //Each sprite row is 2Bytes (8 pixles). Increment the sprite row offset by 2 for next iteration 156 | // $finish(); 157 | end 158 | /***************End of ucode for sprite loop********************************/ 159 | 160 | /************** Start of ucode for window **********************************/ 161 | //skip_the_sprites 162 | 54: oUop = {`gwrl, `r6, 12'b00100001}; //set 1 on pos[5] of a temporal register 163 | 55: oUop = {`gand, `r3, `r6, `lcdc}; // and with lcdc and save in r3 164 | 56: oUop = {`gjz,`skip_the_window}; // if lcdc[5] and lcdc[0] not 1 then window display is off 165 | 57: oUop = {`gwx, `gnull, `gnull, `gnull}; 166 | 58: oUop = {`gjz,`skip_the_window}; 167 | 59: oUop = {`gwy, `gnull, `gnull, `gnull}; //check if wx and wy are on screen 168 | 60: //begin 169 | // $display("I would check for a window tile...if i had one !!!"); 170 | oUop = {`gjz,`skip_the_window}; 171 | //end 172 | ///////at this point ,window is on and wx and wy are inside screen//////////////// 173 | 61: oUop = {`gsubl, `IsThisTileWin, 12'b0 }; //first we ask if current tile is a window tile 174 | 62: oUop = {`gjnz,`initialize_window}; // if Isthistilewin is 0 background tile isn't inside of window 175 | 63: oUop = {`gsubl,`Window_render,12'b0}; 176 | 64: oUop = {`gjnz,`render_window}; 177 | 65: oUop = {`ggoto,`skip_the_window}; 178 | //initialize_window 179 | 66: oUop = {`gwrl,`r5, 12'b0}; 180 | 67: oUop = {`gwrl,`Window_render, 12'b1}; 181 | ///render_window 182 | 68: oUop = { `gadd, `vmem_addr, `Winmoffset, `r5 };//r5 is 0 so this would get the mem adress 9C00//{ `gadd, `vmem_addr, `Winmoffset, `WinTile }//this one is not working 183 | 69: oUop = { `grvmem, `gnull, `gnull, `gnull };//reads vmem and stores in vmem_data 184 | 70: oUop = { `gwrr, `r3, `vmem_addr, `gnull };// store vmem adress in r3 185 | 71: oUop = { `gadd, `r1,`vmem_data_shl_4, `tile_row };//add tile row with vmem data shifted left by 4 186 | 72: oUop = { `gadd, `vmem_addr, `r1, `bgtoffset };// get address for tile memory with r1 and BG tile offset which is the same for window 187 | 73: oUop = { `grvmem, `gnull, `gnull, `gnull };//read from tile memory stores in vmem data 188 | 74: oUop = { `gwrr, `bh, `vmem_data, `gnull };// save in BH for high byte 189 | 75: oUop = { `gaddl, `vmem_addr, 12'd1 };// get adress for BL adding one to current address, reads next byte 190 | 76: oUop = { `grvmem, `gnull, `gnull, `gnull }; // save in vmem data 191 | 77: oUop = { `gwrr, `bl, `vmem_data, `gnull };//save in BL for low byte 192 | 78: oUop = { `gwfbuffer, `gnull,`gnull, `gnull};// BH and BL go through bg pallete which work for window and result gets saved in framebuffer 193 | ///Update win tile index 194 | 79: oUop = {`gaddl, `r5, 12'd1};// add 1 to r5, take in account this has to be changed for r5 its actually used in most logic..dedicate a reg 195 | 80: oUop = { `gaddl, `WinTile, 12'd1 }; //set up WinTile register for next iteration 196 | 81: oUop = { `gsubl, `WinTile, 12'd255 }; // are we going out off screen boundaries 197 | 82: oUop = { `gjnz, `skip_the_window }; 198 | 83: oUop = { `gwrl, `Window_render, 12'd0 }; 199 | //////////////////////////////end of window ucode////////////////////////////////////////////////// 200 | //defines loop for getting the same row for the next tile// 201 | //skip_the_window 202 | 84: oUop = {`ginfbaddr, `gnull, `gnull, `gnull}; //Increment the framebuffer write pointer 203 | 85: oUop = {`gwrl, `sl, 12'd0}; 204 | 86: oUop = {`gwrl, `sh, 12'd0}; 205 | 87: oUop = { `gsubl, `r1, 12'd8191}; //limit 0x1FFF or d 8191 206 | 88: oUop = { `gsub, `r1, `fbuffer_addr, `r8191}; //Did we painted all of the 32x32 tiles? 207 | 89: oUop = { `gjz, 18'h2}; //Yes, ok restart the loop for next frame 208 | 90: oUop = { `gaddl, `r5, 12'd0 }; //increment window tile 209 | 91: oUop = { `gwrl,`sprite_current_row_offset, 12'd0}; //Reset the sprite roww offset to zero since we will start with a fresh tile now 210 | 92: oUop = { `gaddl, `cur_tile, 12'd1 }; //Time to take care of the next tile 211 | 93: oUop = { `gsubl, `r2, 12'd1 }; //Is this tile the last of the 2 tiles in a tile row? 212 | 94: oUop = { `gjnz , 18'd6}; //No, Keep rendering the remaining rows of the current tile line 213 | 95: oUop = { `gaddl, `tile_row, 12'd2 }; 214 | 96: oUop = { `gaddl , `ly, 12'd1 }; 215 | 97: oUop = { `gwrr, `r1, `tile_row, `gnull }; 216 | 98: oUop = { `gsubl, `r1, 12'h10 }; 217 | 99: oUop = { `gjz , 18'd4 }; //Move to next tile row 0 218 | 219 | //defines jump to next row of pixels 220 | 100: oUop = { `gsubl, `r5, 12'd32 }; 221 | 101: oUop = { `gsubl, `cur_tile, 12'd32 }; //Reset the tile index to the first tile index in the row of tiles, this is because we always start a a row of tiles from left to right (like a typewritting machine) 222 | 102: oUop = { `ggoto, 18'd5 }; //Move down one row 223 | 224 | endcase 225 | end 226 | 227 | endmodule 228 | --------------------------------------------------------------------------------