├── .gitignore ├── ISAVideo.pretty ├── graphics_gremlin.kicad_mod └── gremlin.kicad_mod ├── RAM.sch ├── README.md ├── SW ├── CGAVIDEO.COM ├── TDYKBD.COM └── TDYVIDEO.COM ├── bus_interface.sch ├── fab └── isavideo_rev2.zip ├── fp-info-cache ├── fp-lib-table ├── images └── gremlin.jpg ├── isabracket.stl ├── isavideo-cache.lib ├── isavideo.csv ├── isavideo.kicad_pcb ├── isavideo.pdf ├── isavideo.pro ├── isavideo.sch ├── power.sch ├── verilog ├── Makefile ├── README.md ├── UM6845R.v ├── cga.hex ├── cga.v ├── cga_attrib.v ├── cga_composite.v ├── cga_pixel.v ├── cga_scandoubler.v ├── cga_sequencer.v ├── cga_top.v ├── cga_vgaport.v ├── cga_vram.v ├── gremlin.pcf ├── is61_tester.v ├── is61c5128_t.v ├── isavideo.binm ├── isavideo_t.v ├── jtopl │ ├── LICENSE │ ├── README.md │ ├── doc │ │ ├── Makefile │ │ ├── Y8950 app notes.pdf │ │ ├── Y8950 datasheet.pdf │ │ ├── YM2413.pdf │ │ ├── YM3812 datasheet.pdf │ │ ├── Yamaha YM3812 Application Manual.pdf │ │ ├── lfo_count.cc │ │ ├── notes.ods │ │ ├── opl3.c │ │ ├── opl3.h │ │ ├── opll.c │ │ ├── opll.h │ │ ├── opll_patches.c │ │ └── ym2413 app notes.pdf │ ├── hdl │ │ ├── common.yaml │ │ ├── jt2413.v │ │ ├── jt2413.yaml │ │ ├── jt26.qip │ │ ├── jt26.yaml │ │ ├── jtopl.v │ │ ├── jtopl.yaml │ │ ├── jtopl2.qip │ │ ├── jtopl2.v │ │ ├── jtopl2.yaml │ │ ├── jtopl_acc.v │ │ ├── jtopl_csr.v │ │ ├── jtopl_div.v │ │ ├── jtopl_eg.v │ │ ├── jtopl_eg_cnt.v │ │ ├── jtopl_eg_comb.v │ │ ├── jtopl_eg_ctrl.v │ │ ├── jtopl_eg_final.v │ │ ├── jtopl_eg_pure.v │ │ ├── jtopl_eg_step.v │ │ ├── jtopl_exprom.v │ │ ├── jtopl_lfo.v │ │ ├── jtopl_logsin.v │ │ ├── jtopl_mmr.v │ │ ├── jtopl_noise.v │ │ ├── jtopl_op.v │ │ ├── jtopl_pg.v │ │ ├── jtopl_pg_comb.v │ │ ├── jtopl_pg_inc.v │ │ ├── jtopl_pg_rhy.v │ │ ├── jtopl_pg_sum.v │ │ ├── jtopl_pm.v │ │ ├── jtopl_reg.v │ │ ├── jtopl_reg_ch.v │ │ ├── jtopl_sh.v │ │ ├── jtopl_sh_rst.v │ │ ├── jtopl_single_acc.v │ │ ├── jtopl_slot_cnt.v │ │ ├── jtopl_timers.v │ │ ├── jtopll.yaml │ │ ├── jtopll_mmr.v │ │ └── jtopll_reg.v │ └── ver │ │ ├── jtopl_eg │ │ ├── sweep.cpp │ │ ├── sweep.sh │ │ └── sweep.v │ │ ├── jtopl_eg_comb_tb │ │ ├── README │ │ ├── sim.sh │ │ ├── test.cpp │ │ ├── test.v │ │ └── tests │ │ │ └── attack.tst │ │ └── verilator │ │ ├── VGMParser.cpp │ │ ├── VGMParser.hpp │ │ ├── WaveWritter.cpp │ │ ├── WaveWritter.hpp │ │ ├── feature.hpp │ │ ├── mmr.lut │ │ ├── sim.sh │ │ ├── test.cpp │ │ └── tests │ │ ├── am.jtt │ │ ├── fb.jtt │ │ ├── fnum.jtt │ │ ├── keycode.jtt │ │ ├── ksl1.jtt │ │ ├── ksl2.jtt │ │ ├── ksl3.jtt │ │ ├── mod.jtt │ │ ├── noteG.jtt │ │ ├── perc.jtt │ │ ├── rates.jtt │ │ ├── slots.jtt │ │ ├── slots_mod.jtt │ │ ├── timers.jtt │ │ ├── tl.jtt │ │ ├── tone.jtt │ │ ├── tone_w1.jtt │ │ ├── tone_w2.jtt │ │ ├── tone_w3.jtt │ │ └── vib.jtt ├── mda.hex ├── mda.v ├── mda70_top.v ├── mda_attrib.v ├── mda_pixel.v ├── mda_sequencer.v ├── mda_top.v ├── mda_vgaport.v ├── mda_vram.v ├── saa1099.v ├── sound.v └── sound_top.v └── vga_dac.sch /.gitignore: -------------------------------------------------------------------------------- 1 | *.bak 2 | *.kicad_pcb-bak 3 | *.xml 4 | *.net 5 | *.gbr 6 | *.drl 7 | *.zip 8 | -------------------------------------------------------------------------------- /ISAVideo.pretty/gremlin.kicad_mod: -------------------------------------------------------------------------------- 1 | (module LOGO (layer F.Cu) 2 | (at 0 0) 3 | (fp_text reference "G***" (at 0 0) (layer F.SilkS) hide 4 | (effects (font (thickness 0.3))) 5 | ) 6 | (fp_text value "LOGO" (at 0.75 0) (layer F.SilkS) hide 7 | (effects (font (thickness 0.3))) 8 | ) 9 | (fp_poly (pts (xy -4.394200 -3.708400) (xy -3.733800 -3.708400) (xy -3.733800 -3.048000) (xy -3.048000 -3.048000) (xy -3.048000 -2.362200) (xy -2.362200 -2.362200) (xy -2.362200 -3.048000) (xy 2.362200 -3.048000) 10 | (xy 2.362200 -2.362200) (xy 3.048000 -2.362200) (xy 3.048000 -3.048000) (xy 3.733800 -3.048000) (xy 3.733800 -3.708400) (xy 4.394200 -3.708400) (xy 4.394200 -4.394200) (xy 5.080000 -4.394200) 11 | (xy 5.080000 -2.362200) (xy 4.394200 -2.362200) (xy 4.394200 -1.016000) (xy 3.733800 -1.016000) (xy 3.733800 3.073400) (xy 3.048000 3.073400) (xy 3.048000 3.733800) (xy 2.362200 3.733800) 12 | (xy 2.362200 4.419600) (xy -2.362200 4.419600) (xy -2.362200 3.733800) (xy -3.048000 3.733800) (xy -3.048000 3.073400) (xy -3.733800 3.073400) (xy -3.733800 1.701800) (xy -3.048000 1.701800) 13 | (xy -3.048000 2.387600) (xy -1.701800 2.387600) (xy -1.701800 3.073400) (xy -1.016000 3.073400) (xy -1.016000 2.387600) (xy 1.016000 2.387600) (xy 1.016000 3.073400) (xy 1.701800 3.073400) 14 | (xy 1.701800 2.387600) (xy 3.048000 2.387600) (xy 3.048000 1.701800) (xy -3.048000 1.701800) (xy -3.733800 1.701800) (xy -3.733800 0.355600) (xy -1.016000 0.355600) (xy -1.016000 1.041400) 15 | (xy 1.016000 1.041400) (xy 1.016000 0.355600) (xy 0.330200 0.355600) (xy 0.330200 -1.016000) (xy 1.701800 -1.016000) (xy 1.701800 -0.330200) (xy 2.362200 -0.330200) (xy 2.362200 -1.016000) 16 | (xy 1.701800 -1.016000) (xy 0.330200 -1.016000) (xy 0.330200 -1.676400) (xy -0.330200 -1.676400) (xy -0.330200 0.355600) (xy -1.016000 0.355600) (xy -3.733800 0.355600) (xy -3.733800 -1.016000) 17 | (xy -2.362200 -1.016000) (xy -2.362200 -0.330200) (xy -1.701800 -0.330200) (xy -1.701800 -1.016000) (xy -2.362200 -1.016000) (xy -3.733800 -1.016000) (xy -4.394200 -1.016000) (xy -4.394200 -1.676400) 18 | (xy -5.080000 -1.676400) (xy -5.080000 -4.394200) (xy -4.394200 -4.394200) (xy -4.394200 -3.708400) )(layer F.SilkS) (width 0.010000) 19 | ) 20 | ) 21 | -------------------------------------------------------------------------------- /SW/CGAVIDEO.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/SW/CGAVIDEO.COM -------------------------------------------------------------------------------- /SW/TDYKBD.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/SW/TDYKBD.COM -------------------------------------------------------------------------------- /SW/TDYVIDEO.COM: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/SW/TDYVIDEO.COM -------------------------------------------------------------------------------- /fab/isavideo_rev2.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/fab/isavideo_rev2.zip -------------------------------------------------------------------------------- /fp-info-cache: -------------------------------------------------------------------------------- 1 | 1620141462916 2 | Fiducials 3 | Fiducial_0.5mm_Dia_1mm_Outer 4 | 5 | 6 | 0 7 | 0 8 | 0 9 | Fiducials 10 | Fiducial_0.75mm_Dia_1.5mm_Outer 11 | 12 | 13 | 0 14 | 0 15 | 0 16 | Fiducials 17 | Fiducial_1mm_Dia_2.54mm_Outer_CopperBottom 18 | 19 | 20 | 0 21 | 0 22 | 0 23 | Fiducials 24 | Fiducial_1mm_Dia_2.54mm_Outer_CopperTop 25 | 26 | 27 | 0 28 | 0 29 | 0 30 | Fiducials 31 | Fiducial_1mm_Dia_2mm_Outer 32 | 33 | 34 | 0 35 | 0 36 | 0 37 | Fiducials 38 | Fiducial_classic_big_CopperBottom_Type1 39 | 40 | 41 | 0 42 | 0 43 | 0 44 | Fiducials 45 | Fiducial_classic_big_CopperBottom_Type2 46 | 47 | 48 | 0 49 | 0 50 | 0 51 | Fiducials 52 | Fiducial_classic_big_CopperTop_Type1 53 | 54 | 55 | 0 56 | 0 57 | 0 58 | Fiducials 59 | Fiducial_classic_big_CopperTop_Type2 60 | 61 | 62 | 0 63 | 0 64 | 0 65 | Fiducials 66 | Fiducial_classic_big_SilkscreenTop_Type1 67 | 68 | 69 | 0 70 | 0 71 | 0 72 | Fiducials 73 | Fiducial_classic_big_SilkscreenTop_Type2 74 | 75 | 76 | 0 77 | 0 78 | 0 79 | Fiducials 80 | Fiducial_classic_Small_CopperBottom_Type1 81 | 82 | 83 | 0 84 | 0 85 | 0 86 | Fiducials 87 | Fiducial_classic_Small_CopperBottom_Type2 88 | 89 | 90 | 0 91 | 0 92 | 0 93 | Fiducials 94 | Fiducial_classic_Small_CopperTop_Type1 95 | 96 | 97 | 0 98 | 0 99 | 0 100 | Fiducials 101 | Fiducial_classic_Small_CopperTop_Type2 102 | 103 | 104 | 0 105 | 0 106 | 0 107 | Fiducials 108 | Fiducial_classic_Small_SilkscreenTop_Type1 109 | 110 | 111 | 0 112 | 0 113 | 0 114 | Fiducials 115 | Fiducial_classic_Small_SilkscreenTop_Type2 116 | 117 | 118 | 0 119 | 0 120 | 0 121 | Fiducials 122 | Fiducial_Modern_CopperBottom 123 | 124 | 125 | 0 126 | 0 127 | 0 128 | Fiducials 129 | Fiducial_Modern_CopperTop 130 | 131 | 132 | 0 133 | 0 134 | 0 135 | Fiducials 136 | Fiducial_Modern_SilkscreenTop 137 | 138 | 139 | 0 140 | 0 141 | 0 142 | -------------------------------------------------------------------------------- /fp-lib-table: -------------------------------------------------------------------------------- 1 | (fp_lib_table 2 | (lib (name ISAVideo)(type KiCad)(uri ${KIPRJMOD}/ISAVideo.pretty)(options "")(descr "")) 3 | ) 4 | -------------------------------------------------------------------------------- /images/gremlin.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/images/gremlin.jpg -------------------------------------------------------------------------------- /isabracket.stl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/isabracket.stl -------------------------------------------------------------------------------- /isavideo.csv: -------------------------------------------------------------------------------- 1 | Item,Qty,Reference(s),Value,Mouser 2 | 1,23,"C1, C7, C8, C9, C10, C11, C13, C14, C15, C16, C17, C20, C21, C22, C23, C24, C25, C26, C27, C28, C29, C30, C31",1u,810-CGA3E1X7R1C105AC 3 | 2,8,"C2, C3, C4, C5, C6, C12, C18, C19",4.7u,187-CL10A475KP8NNNC 4 | 3,1,F1,1A,530-0ZCJ0050FF2G 5 | 4,1,J1,PROG, 6 | 5,1,J2,DE15,156-3315-E 7 | 6,1,J3,NTSC,161-0360-E 8 | 7,1,J4,DE9,152-3409 9 | 8,1,J6,RFMOD, 10 | 9,13,"R1, R2, R3, R4, R5, R8, R9, R14, R15, R20, R23, R24, R27",10K,603-RC0603FR-0710KL 11 | 10,5,"R6, R7, R10, R25, R26",10,603-RC0603FR-0710RL 12 | 11,1,R11,DNI,DNI 13 | 12,3,"R12, R21, R22",100,603-RC0603FR-07100RL 14 | 13,1,R13,1K,603-RC0603FR-071KL 15 | 14,5,"R16, R17, R18, R19, R31",75,603-RC0603FR-0775RL 16 | 15,3,"R28, R29, R30",237,603-RC0603FR-07237RL 17 | 16,6,"RN1, RN2, RN3, RN4, RN5, RN6",604,652-CAY16-6040F4LF 18 | 17,4,"RN7, RN8, RN9, RN10",300,652-CAY16-3000F4LF 19 | 18,1,SW1,SW_DIP_x04,706-76PSB04ST 20 | 19,1,U1,ICE40HX4K-TQ144,842-ICE40HX4K-TQ144 21 | 20,1,U2,SST26VF080A-104I/SN,579-26VF080A-104I/SN 22 | 21,3,"U3, U4, U5",74ALVC164245,771-74ALVC164245 23 | 22,1,U6,ADA4891-3,584-ADA4891-3ARZ 24 | 23,1,U7,IS61WV5128BLL-10KLI,870-61WV5128B10KLI 25 | 24,1,U8,AP2114HA-3.3,621-AP2114HA-3.3TRG1 26 | 25,1,U9,AP2114HA-1.2,621-AP2114HA-1.2TRG1 27 | 26,1,U10,APX803S00-29SA-7,621-APX803S00-29SA-7 28 | 27,1,U11,74HCT125,771-74HCT125PW-T 29 | 28,1,X1,10MHz,520-ECS-2333-100-BNT 30 | 29,1,X2,14.318MHz,815-ASE-14.318MLCT 31 | -------------------------------------------------------------------------------- /isavideo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/isavideo.pdf -------------------------------------------------------------------------------- /isavideo.pro: -------------------------------------------------------------------------------- 1 | update=1/15/2021 6:28:53 PM 2 | version=1 3 | last_client=kicad 4 | [general] 5 | version=1 6 | RootSch= 7 | BoardNm= 8 | [cvpcb] 9 | version=1 10 | NetIExt=net 11 | [eeschema] 12 | version=1 13 | LibDir= 14 | [eeschema/libraries] 15 | [pcbnew] 16 | version=1 17 | PageLayoutDescrFile= 18 | LastNetListRead=isavideo.net 19 | CopperLayerCount=2 20 | BoardThickness=1.6 21 | AllowMicroVias=0 22 | AllowBlindVias=0 23 | RequireCourtyardDefinitions=0 24 | ProhibitOverlappingCourtyards=1 25 | MinTrackWidth=0.1524 26 | MinViaDiameter=0.7111999999999999 27 | MinViaDrill=0.3048 28 | MinMicroViaDiameter=0.2 29 | MinMicroViaDrill=0.09999999999999999 30 | MinHoleToHole=0.25 31 | TrackWidth1=0.1524 32 | TrackWidth2=0.1524 33 | TrackWidth3=0.254 34 | TrackWidth4=0.3048 35 | TrackWidth5=0.762 36 | ViaDiameter1=0.7112 37 | ViaDrill1=0.3048 38 | dPairWidth1=0.2 39 | dPairGap1=0.25 40 | dPairViaGap1=0.25 41 | SilkLineWidth=0.12 42 | SilkTextSizeV=1 43 | SilkTextSizeH=1 44 | SilkTextSizeThickness=0.15 45 | SilkTextItalic=0 46 | SilkTextUpright=1 47 | CopperLineWidth=0.2 48 | CopperTextSizeV=1.5 49 | CopperTextSizeH=1.5 50 | CopperTextThickness=0.3 51 | CopperTextItalic=0 52 | CopperTextUpright=1 53 | EdgeCutLineWidth=0.05 54 | CourtyardLineWidth=0.05 55 | OthersLineWidth=0.15 56 | OthersTextSizeV=1 57 | OthersTextSizeH=1 58 | OthersTextSizeThickness=0.15 59 | OthersTextItalic=0 60 | OthersTextUpright=1 61 | SolderMaskClearance=0.0254 62 | SolderMaskMinWidth=0.25 63 | SolderPasteClearance=0 64 | SolderPasteRatio=-0 65 | -------------------------------------------------------------------------------- /verilog/Makefile: -------------------------------------------------------------------------------- 1 | # Graphics Gremlin 2 | # 3 | # Copyright (c) 2021 Eric Schlaepfer 4 | # This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | # International License. To view a copy of this license, visit 6 | # http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | # Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | # 9 | 10 | PROJ = isavideo 11 | IMAGES = mda70_top mda_top cga_top sound_top 12 | SOURCES = mda70_top.v mda_top.v mda.v UM6845R.v mda_vgaport.v mda_vram.v mda_attrib.v mda_sequencer.v mda_pixel.v cga_top.v cga.v cga_vgaport.v cga_sequencer.v cga_pixel.v cga_attrib.v cga_vram.v cga_composite.v cga_scandoubler.v sound_top.v sound.v saa1099.v ./jtopl/hdl/jtopl2.v ./jtopl/hdl/jtopl.v ./jtopl/hdl/jtopl_acc.v ./jtopl/hdl/jtopl_op.v ./jtopl/hdl/jtopl_eg.v ./jtopl/hdl/jtopl_pg.v ./jtopl/hdl/jtopl_lfo.v ./jtopl/hdl/jtopl_timers.v ./jtopl/hdl/jtopl_mmr.v ./jtopl/hdl/jtopl_reg.v ./jtopl/hdl/jtopl_div.v ./jtopl/hdl/jtopl_sh_rst.v ./jtopl/hdl/jtopl_pg_comb.v ./jtopl/hdl/jtopl_noise.v ./jtopl/hdl/jtopl_sh.v ./jtopl/hdl/jtopl_eg_comb.v ./jtopl/hdl/jtopl_eg_cnt.v ./jtopl/hdl/jtopl_exprom.v ./jtopl/hdl/jtopl_logsin.v ./jtopl/hdl/jtopl_single_acc.v ./jtopl/hdl/jtopl_eg_final.v ./jtopl/hdl/jtopl_eg_pure.v ./jtopl/hdl/jtopl_eg_step.v ./jtopl/hdl/jtopl_eg_ctrl.v ./jtopl/hdl/jtopl_pg_rhy.v ./jtopl/hdl/jtopl_pg_sum.v ./jtopl/hdl/jtopl_pg_inc.v ./jtopl/hdl/jtopl_pm.v ./jtopl/hdl/jtopl_reg_ch.v ./jtopl/hdl/jtopl_csr.v ./jtopl/hdl/jtopl_slot_cnt.v 13 | PIN_DEF = gremlin.pcf 14 | DEVICE = hx8k 15 | ODIR = build 16 | DEPS = $(addprefix $(ODIR)/,$(addsuffix .d,$(IMAGES))) 17 | 18 | # Want to build report and main bin file 19 | all: $(addprefix $(ODIR)/,$(addsuffix .rpt,$(IMAGES))) $(ODIR)/$(PROJ).binm 20 | 21 | # removed %.v 22 | $(ODIR)/%.json: $(SOURCES) 23 | yosys -p 'synth_ice40 -top $(basename $(notdir $@)) -json $@' $(SOURCES) -E $(basename $(notdir $@)).d 24 | # yosys -p 'synth_ice40 -top mda_top -json $@' $(SOURCES) -E $(DEPS) 25 | # @echo yosys -p 'synth_ice40 -top isavideo -json $@' $^ -E $(DEPS) 26 | echo $@ 27 | 28 | $(ODIR)/%.asc: $(ODIR)/%.json $(PIN_DEF) 29 | # add -q to quiet lots of messages 30 | nextpnr-ice40 -q --$(DEVICE) --pcf $(PIN_DEF) --json $< --asc $@ --package tq144:4k 31 | # @echo nextpnr $< $@ 32 | 33 | $(ODIR)/%.bin: $(ODIR)/%.asc 34 | icepack $< $@ 35 | # @echo icepack $< $@ 36 | 37 | # Combined multiboot image 38 | $(ODIR)/%.binm: $(addprefix $(ODIR)/,$(addsuffix .bin, $(IMAGES))) 39 | icemulti -c -o $@ $^ 40 | 41 | $(ODIR)/%.rpt: $(ODIR)/%.asc 42 | icetime -d $(DEVICE) -mtr $@ $< 43 | # @echo icetime -d $(DEVICE) -mtr $@ $< 44 | 45 | sim: $(ODIR)/$(PROJ)_t.vcd 46 | 47 | $(ODIR)/$(PROJ)_t.vcd: $(PROJ)_t.v $(SOURCES) is61c5128_t.v 48 | 49 | prog: $(ODIR)/$(PROJ).binm 50 | # iCEburn -e -v -w $< 51 | iceprog -p $< 52 | 53 | sudo-prog: $(ODIR)/$(PROJ).bin 54 | @echo 'Executing prog as root!!!' 55 | iCEburn -e -v -w $< 56 | 57 | clean: 58 | rm -f $(ODIR)/$(PROJ).blif $(ODIR)/$(PROJ).asc $(ODIR)/$(PROJ).bin $(ODIR)/$(PROJ).json $(ODIR)/$(PROJ).d $(ODIR)/*.bin $(ODIR)/*.binm $(ODIR)/*.rpt 59 | 60 | reset: 61 | iceprog -t 62 | 63 | %.vcd: 64 | iverilog $^ -o $(@:.vcd=.out) 65 | vvp $(@:.vcd=.out) 66 | 67 | # Don't delete individual images 68 | PRECIOUS: $(addsuffix .bin, $(addprefix $(ODIR)/,$(IMAGES))) 69 | 70 | .PHONY: all prog clean reset 71 | 72 | # Depsfile 73 | -include $(DEPS) 74 | -------------------------------------------------------------------------------- /verilog/README.md: -------------------------------------------------------------------------------- 1 | # The Graphics Gremlin - FPGA code 2 | 3 | (Click here for the [main README](https://github.com/schlae/graphics-gremlin/blob/main/README.md)) 4 | 5 | The FPGA code is divided into two major sets of files, those for CGA graphics and those for MDA/HGC graphics. At some point I'll tidy up and make a nice organized directory tree, but for now they're all in the same place. 6 | 7 | * mda\_top.v: The top level file instantiating the MDA/HGC graphics logic 8 | * mda70\_top.v: An alternative top level file for VGA compatible MDA/HGC graphics 9 | * mda.v: Implements MDA/HGC ISA interface, IO registers and instantiates the CRTC, SRAM interface, sequencer, and pixel engine 10 | * crtc6845.v: This is my mostly-accurate recreation of the old Motorola 6845 CRT controller chip. It generates all the sync timings as well as the character and row addresses. There are probably slight differences between it and the real thing. 11 | * mda\_sequencer.v: Controls timing across the entire card, deciding when to fetch SRAM data, look up character bits from the character ROM, and allow ISA bus access to the SRAM 12 | * mda\_vram.v: Implements the state machine to arbitrate ISA bus and pixel engine access to the video ram (external SRAM) 13 | * mda\_pixel.v: This is the pixel engine. It takes data coming from the SRAM, looks up the pixels in the character ROM, and shifts the data out one pixel at a time. 14 | * mda\_attrib.v: The attribute generator applies video attributes to the raw pixel data, including brightness, underline, inverse video, blinking. It also applies the blinking cursor. 15 | * mda\_vgaport.v: This module turns the digital MDA video signals into numbers to drive the resistor ladder DAC connected to the VGA port. If you (gasp) dislike amber monochrome monitors, then you can hack this code to make it green or white. 16 | 17 | CGA graphics logic is similar to MDA/HGC and shares the same crtc6845.v logic, but the cards are different enough that I couldn't share more. 18 | * cga\_top.v: Instantiates top level CGA logic. 19 | * cga.v: Implements the ISA bus interface, CGA control registers, wait state generator, and most of the other CGA modules 20 | * cga\_sequencer.v: Generates most of the timing signals used on the card, including memory fetches and pixel engine timing. 21 | * cga\_vram.v: Implements a very basic address MUX for the SRAM interface. This actually causes too much CGA snow, and should be improved using the HGC VRAM interface as a model. 22 | * cga\_pixel.v: The CGA pixel engine takes data from the SRAM, does a character lookup (text mode only), and shifts the data out 1 or 2 bits at a time, depending on the video mode. 23 | * cga\_attrib.v: The attribute generator applies video attributes to the raw pixels data, including color, brightness, and blinking. 24 | * cga\_composite.v: Contains the flip flops used to generate NTSC composite color as well as new sync pulses. The output is a 7-bit signal passed off to the green DAC channel for the RCA jack on the card. 25 | * cga\_scandoubler.v: A very basic scan doubler to convert 15.7KHz CGA video to 31.4KHz VGA video. To save memory, this is done using 4-bit digital RGBI signals. 26 | * cga\_vgaport.v: This module takes RGBI digital video from the scan doubler and turns it into numbers that drive the resistor ladder DAC connected to the VGA port. It produces CGA brown instead of dark yellow. 27 | 28 | Other miscellaneous files include: 29 | * cga.hex and mda.hex: character ROM 30 | * gremlin.pcf: The pin constraints file that determines what signals are tied to what pins on the FPGA 31 | * isavideo\_t.v: A sloppy test bench that I used to validate and troubleshoot the rest of the logic. 32 | * is61c5128\_t.v: A behavorial Verilog model of the SRAM chip. 33 | * is61\_tester.v: A test bench I used to verify the SRAM chip behavioral model. 34 | 35 | ## Building 36 | 37 | To build the project, you will need to install the tools from [Project IceStorm](http://www.clifford.at/icestorm/) (full instructions are available at that link). The Graphics Gremlin uses NextPNR, so make sure you install that. 38 | 39 | Alternatively, you can install the [OSS Cad Suite](https://github.com/YosysHQ/oss-cad-suite-build) which is prebuilt and runs on a variety of platforms. 40 | 41 | Once the tools are installed, just navigate to the Graphics Gremlin Verilog directory and run 42 | ``` 43 | mkdir build 44 | make 45 | ``` 46 | If you have the FTDI programming cable hooked up to the card, you can also type `make prog`. As a convenience, `make reset` will not program the FPGA but will toggle its reset line which is useful if you change the red switch bank and don't want to cycle power on the host PC. 47 | 48 | If the `make prog` command can't find the FTDI programming cable, make sure you have the udev rules set up. 49 | 50 | 51 | -------------------------------------------------------------------------------- /verilog/cga_attrib.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | `default_nettype none 10 | module cga_attrib( 11 | input clk, 12 | input[7:0] att_byte, 13 | input[4:0] row_addr, 14 | input[7:0] cga_color_reg, 15 | input grph_mode, 16 | input bw_mode, 17 | input mode_640, 18 | input tandy_16_mode, 19 | input display_enable, 20 | input blink_enabled, 21 | input blink, 22 | input cursor, 23 | input hsync, 24 | input vsync, 25 | input pix_in, 26 | input c0, 27 | input c1, 28 | input pix_640, 29 | input [3:0] pix_tandy, 30 | input [3:0] tandy_bordercol, 31 | input tandy_color_4, 32 | input tandy_color_16, 33 | output reg[3:0] pix_out, 34 | output wire overscan 35 | ); 36 | 37 | reg blinkdiv; 38 | reg[1:0] blink_old; 39 | wire att_blink; 40 | wire[3:0] att_fg; 41 | wire[3:0] att_bg; 42 | wire cursorblink; 43 | wire blink_area; 44 | wire alpha_dots; 45 | wire mux_a; 46 | wire mux_b; 47 | wire shutter; 48 | wire selblue; 49 | wire[3:0] rgbi; 50 | wire[3:0] active_area; 51 | 52 | // Extract attributes from the attribute byte 53 | assign att_fg = att_byte[3:0]; 54 | assign att_bg = blink_enabled ? {1'b0, att_byte[6:4]} : att_byte[7:4]; 55 | assign att_blink = att_byte[7]; 56 | 57 | // Character blink is half the rate of the cursor blink 58 | always @ (posedge clk) 59 | begin 60 | blink_old <= {blink_old[0], blink}; 61 | if (blink_old == 2'b01) begin 62 | blinkdiv <= ~blinkdiv; 63 | end 64 | end 65 | 66 | // Assemble all the signals to create the final video signal 67 | assign cursorblink = cursor & blink; 68 | assign blink_area = ~(blink_enabled & att_blink & ~cursor) | ~blinkdiv; 69 | assign alpha_dots = (pix_in & blink_area) | cursorblink; 70 | 71 | // Determine mux A and mux B inputs for selecting output colors. 72 | assign mux_a = ~display_enable | 73 | (grph_mode ? 74 | ((tandy_16_mode | tandy_color_16) ? 0 : (~(~mode_640 & (c0 | c1)))) : 75 | ~alpha_dots); 76 | assign mux_b = grph_mode | ~display_enable; 77 | 78 | // Shutter closes when video is blanked during sync 79 | assign shutter = (hsync | vsync) | ((mode_640 & ~tandy_color_4) ? ~(display_enable & pix_640) : 1'b0); 80 | 81 | // Blue palette selection bit 82 | assign selblue = bw_mode ? c0 : cga_color_reg[5]; 83 | 84 | assign active_area = tandy_color_4 ? {1'b0, c1, c0, 1'b0} : 85 | (tandy_16_mode | tandy_color_16) ? pix_tandy : {cga_color_reg[4], c1, c0, selblue}; 86 | 87 | assign overscan = (mux_b & mux_a); 88 | 89 | always @ (*) 90 | begin 91 | if (shutter) begin 92 | pix_out <= 4'b0; 93 | end else begin 94 | case ({mux_b, mux_a}) 95 | 2'b00: pix_out <= att_fg; // Text foreground 96 | 2'b01: pix_out <= att_bg; // Text background 97 | 2'b10: pix_out <= active_area; // Graphics 98 | 2'b11: pix_out <= (tandy_16_mode | tandy_color_16) ? tandy_bordercol : cga_color_reg[3:0]; // Overscan color 99 | endcase 100 | end 101 | end 102 | 103 | endmodule 104 | 105 | -------------------------------------------------------------------------------- /verilog/cga_composite.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | `default_nettype none 10 | module cga_composite( 11 | // Clock 12 | input clk, 13 | 14 | input lclk, 15 | input hclk, 16 | 17 | input[3:0] video, // IRGB video in 18 | input hsync, 19 | input vsync_l, 20 | input bw_mode, 21 | 22 | output hsync_out, 23 | output vsync_out, 24 | output [6:0] comp_video 25 | ); 26 | 27 | reg[3:0] vid_del; 28 | reg hsync_dly = 1'b0; 29 | reg vsync_dly_l = 1'b0; 30 | reg[3:0] hsync_counter = 4'd0; 31 | reg[3:0] vsync_counter = 4'd0; 32 | reg vsync_trig = 1'b0; 33 | 34 | reg[2:0] count_358 = 3'd0; 35 | wire clk_3m58; 36 | wire clk_14m3; 37 | reg clk_old = 1'b0; 38 | 39 | wire burst; 40 | wire csync; 41 | 42 | reg[6:0] grey_level; 43 | 44 | // Color shifter 45 | reg yellow_burst; 46 | reg red; 47 | reg magenta; 48 | wire blue; 49 | wire cyan; 50 | wire green; 51 | 52 | reg color_out; 53 | wire color_out2; 54 | 55 | reg hclk_old; 56 | 57 | always @ (posedge clk) 58 | begin 59 | hclk_old <= hclk; 60 | end 61 | 62 | // Resync the video to the falling edge of 14.318MHz 63 | always @ (posedge clk) 64 | begin 65 | if (clk_14m3 && !clk_old) begin 66 | vid_del <= video; 67 | end 68 | end 69 | 70 | // Delay the sync pulses 71 | always @ (posedge clk) 72 | begin 73 | if (hclk && !hclk_old) begin 74 | hsync_dly <= hsync; 75 | vsync_dly_l <= vsync_l; 76 | end 77 | end 78 | 79 | // hsync counter 80 | always @ (posedge clk) 81 | begin 82 | if (lclk) begin 83 | if (hsync_dly) begin 84 | if (hsync_counter == 4'd11) begin 85 | hsync_counter <= 4'd0; 86 | end else begin 87 | hsync_counter <= hsync_counter + 4'd1; 88 | if ((hsync_counter + 4'd1) == 4'd2) begin 89 | vsync_trig <= 1'b1; 90 | end 91 | end 92 | end else begin 93 | hsync_counter <= 4'd0; 94 | end 95 | end else begin 96 | vsync_trig <= 1'b0; 97 | end 98 | end 99 | 100 | assign hsync_out = (hsync_counter > 4'd1) && (hsync_counter < 4'd6); 101 | assign burst = bw_mode ? 1'b0 : (~vsync_dly_l & 102 | ((hsync_counter == 4'd7) || 103 | (hsync_counter == 4'd8))); 104 | 105 | // vsync counter 106 | always @ (posedge clk) 107 | begin 108 | if (vsync_trig) begin 109 | if (!vsync_dly_l) begin 110 | vsync_counter <= 4'd0; 111 | end else begin 112 | vsync_counter <= {vsync_counter[2:0], 1'b1}; 113 | end 114 | end 115 | end 116 | 117 | // Positive going vsync pulse 118 | assign vsync_out = vsync_counter[0] & ~vsync_counter[3]; 119 | 120 | assign csync = ~(vsync_out ^ hsync_out); 121 | 122 | // Generate 3.58MHz from the 28MHz clock coming in 123 | always @ (posedge clk) 124 | begin 125 | count_358 <= count_358 + 3'd1; 126 | clk_old <= clk_14m3; 127 | end 128 | assign clk_3m58 = count_358[2]; 129 | wire clk_7m; 130 | assign clk_7m = count_358[1]; 131 | assign clk_14m3 = count_358[0]; 132 | 133 | // Create color phase clocks 134 | always @ (posedge clk) 135 | begin 136 | // Check for 14.318MHz rising edge 137 | if (!clk_14m3 && clk_old) begin 138 | yellow_burst <= clk_3m58; 139 | red <= yellow_burst; 140 | end 141 | // Check for 14.318MHz falling edge 142 | if (clk_14m3 && !clk_old) begin 143 | magenta <= red; 144 | end 145 | end 146 | assign blue = ~yellow_burst; 147 | assign cyan = ~red; 148 | assign green = ~magenta; 149 | 150 | // Color mux 151 | always @ (*) 152 | begin 153 | // R, G, B 154 | case ({vid_del[2] ^ burst, vid_del[1] ^ burst, vid_del[0]}) 155 | 3'd0: color_out <= 1'b0; 156 | 3'd1: color_out <= blue; 157 | 3'd2: color_out <= green; 158 | 3'd3: color_out <= cyan; 159 | 3'd4: color_out <= red; 160 | 3'd5: color_out <= magenta; 161 | 3'd6: color_out <= yellow_burst; 162 | 3'd7: color_out <= 1'b1; 163 | endcase 164 | end 165 | 166 | // Black and white mode? Color is disabled. 167 | assign color_out2 = bw_mode ? 168 | (vid_del[2:0] != 0) : 169 | (color_out); 170 | 171 | always @ (*) 172 | begin 173 | case (vid_del[2:0]) 174 | 3'd0: grey_level <= 7'd29; 175 | 3'd1: grey_level <= 7'd36; 176 | 3'd2: grey_level <= 7'd49; 177 | 3'd3: grey_level <= 7'd56; 178 | 3'd4: grey_level <= 7'd39; 179 | 3'd5: grey_level <= 7'd46; 180 | 3'd6: grey_level <= 7'd60; 181 | 3'd7: grey_level <= 7'd68; 182 | endcase 183 | end 184 | 185 | assign comp_video = ~csync ? 0 : (grey_level + (vid_del[3] ? 7'd31 : 7'd0) + 186 | (color_out2 ? 7'd28 : 7'd0)); 187 | 188 | endmodule 189 | -------------------------------------------------------------------------------- /verilog/cga_scandoubler.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | `default_nettype none 10 | module cga_scandoubler( 11 | input clk, 12 | input line_reset, 13 | input[3:0] video, 14 | output reg dbl_hsync, 15 | output[3:0] dbl_video 16 | ); 17 | 18 | reg sclk = 1'b0; 19 | reg[9:0] hcount_slow; 20 | reg[9:0] hcount_fast; 21 | reg line_reset_old = 1'b0; 22 | 23 | wire[9:0] addr_a; 24 | wire[9:0] addr_b; 25 | 26 | reg[3:0] data_a; 27 | reg[3:0] data_b; 28 | 29 | reg[3:0] scan_ram_a [1023:0]; 30 | reg[3:0] scan_ram_b [1023:0]; 31 | 32 | reg select = 1'b0; 33 | 34 | // VGA 640x480@60Hz has pix clk of 25.175MHz. Ours is 28.6364MHz, 35 | // so it is not quite an exact match. 896 clocks per line gives us 36 | // an horizontal rate of 31.96KHz which is close to 31.78KHz (spec). 37 | 38 | // Vertical lines are doubled, so 262 * 2 = 524 which matches exactly. 39 | 40 | always @ (posedge clk) 41 | begin 42 | line_reset_old <= line_reset; 43 | end 44 | 45 | // Double scanned horizontal counter 46 | always @ (posedge clk) 47 | begin 48 | if (line_reset & ~line_reset_old) begin 49 | hcount_fast <= 11'd0; 50 | end else begin 51 | if (hcount_fast == 10'd911) begin 52 | hcount_fast <= 10'd0; 53 | end else begin 54 | hcount_fast <= hcount_fast + 11'd1; 55 | end 56 | 57 | // Fixed doubled hsync 58 | if (hcount_fast == 10'd720) begin 59 | dbl_hsync <= 1; 60 | end 61 | if (hcount_fast == (10'd720 + 10'd160)) begin 62 | dbl_hsync <= 0; 63 | end 64 | end 65 | end 66 | 67 | // Standard scan horizontal counter 68 | always @ (posedge clk) 69 | begin 70 | sclk <= ~sclk; 71 | if (line_reset & ~line_reset_old) begin 72 | hcount_slow <= 10'd0; 73 | end else if (sclk) begin 74 | hcount_slow <= hcount_slow + 10'd1; 75 | end 76 | end 77 | 78 | // Select latch lets us swap between line store RAMs A and B 79 | always @ (posedge clk) 80 | begin 81 | if (line_reset & ~line_reset_old) begin 82 | select = ~select; 83 | end 84 | end 85 | 86 | assign addr_a = select ? hcount_slow : hcount_fast; 87 | assign addr_b = select ? hcount_fast : hcount_slow; 88 | 89 | // RAM A 90 | always @ (posedge clk) 91 | begin 92 | if (select) begin 93 | scan_ram_a[(addr_a)] <= video; 94 | end 95 | data_a <= scan_ram_a[addr_a]; 96 | end 97 | 98 | // RAM B 99 | always @ (posedge clk) 100 | begin 101 | if (!select) begin 102 | scan_ram_b[(addr_b)] <= video; 103 | end 104 | data_b <= scan_ram_b[addr_b]; 105 | end 106 | 107 | assign dbl_video = select ? data_b : data_a; 108 | 109 | endmodule 110 | -------------------------------------------------------------------------------- /verilog/cga_sequencer.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | `default_nettype none 10 | module cga_sequencer( 11 | input clk, 12 | output[4:0] clk_seq, 13 | output vram_read, 14 | output vram_read_a0, 15 | output vram_read_char, 16 | output vram_read_att, 17 | input hres_mode, 18 | output crtc_clk, 19 | output charrom_read, 20 | output disp_pipeline, 21 | output isa_op_enable, 22 | output hclk, 23 | output lclk, 24 | input tandy_16_gfx, 25 | input tandy_color_16 26 | ); 27 | 28 | wire crtc_clk_int; 29 | reg[4:0] clkdiv = 5'b0; 30 | 31 | // Sequencer: times internal operations 32 | always @ (posedge clk) 33 | begin 34 | if (clkdiv == 5'd31) begin 35 | clkdiv <= 5'd0; 36 | end else begin 37 | clkdiv <= clkdiv + 1; 38 | end 39 | end 40 | 41 | // For 80 column text, we do everything twice for a complete clkdiv cycle. 42 | // For 40 column text, we do everything once for a complete clkdiv cycle. 43 | assign lclk = (clkdiv == 5'd0); 44 | assign hclk = (clkdiv == 5'd0) || (clkdiv == 5'd16); 45 | 46 | assign crtc_clk_int = (clkdiv == 5'd0) || (hres_mode ? (clkdiv == 5'd16) : 0); 47 | 48 | // Control signals based on the sequencer state 49 | assign vram_read = (clkdiv == 5'd1) || (clkdiv == 5'd2) || (clkdiv == 5'd3) || 50 | (clkdiv == 5'd17) || (clkdiv == 5'd18) || (clkdiv == 5'd19); 51 | assign vram_read_a0 = (clkdiv == 5'd2) || (clkdiv == 5'd18); 52 | assign vram_read_char = (clkdiv == 5'd2) || (hres_mode ? (clkdiv == 5'd18) : 0); 53 | assign vram_read_att = (clkdiv == 5'd3) || (hres_mode ? (clkdiv == 5'd19) : 0); 54 | assign charrom_read = (clkdiv == 5'd3) || (hres_mode ? (clkdiv == 5'd19) : 0);// 3 and 19? 55 | assign disp_pipeline = (clkdiv == (tandy_color_16 ? 5'd9 : tandy_16_gfx ? 5'd7 : 5'd4)) || (hres_mode ? (clkdiv == (tandy_16_gfx ? 5'd23 : 5'd20)) : 0); 56 | 57 | assign crtc_clk = crtc_clk_int; 58 | assign clk_seq = clkdiv; 59 | // Leave a gap of at least 2 cycles between the end of ISA operation and 60 | // vram_read. This is because an ISA operation takes 3 cycles. 61 | assign isa_op_enable = ((clkdiv > 5'd4) && (clkdiv < 5'd15)) || 62 | ((clkdiv > 5'd20) && (clkdiv < 5'd31)); 63 | 64 | endmodule 65 | 66 | -------------------------------------------------------------------------------- /verilog/cga_top.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | `default_nettype none 10 | module cga_top( 11 | // Clocks 12 | input clk_10m, 13 | input clk_14m318, 14 | input clk_bus, 15 | 16 | // Bus reset 17 | input busreset, 18 | 19 | // ISA bus 20 | input[19:0] bus_a, 21 | input bus_ior_l, 22 | input bus_iow_l, 23 | input bus_memr_l, 24 | input bus_memw_l, 25 | inout[7:0] bus_d, 26 | output bus_dir, 27 | output bus_rdy, 28 | output bus_0ws_l, 29 | input bus_aen, 30 | input bus_ale, 31 | 32 | // RAM 33 | output ram_we_l, 34 | output[18:0] ram_a, 35 | inout[7:0] ram_d, 36 | 37 | // Video outputs 38 | output hsync, 39 | output vsync, 40 | output vid_en_l, 41 | output d_r, 42 | output d_g, 43 | output d_b, 44 | output d_r2, 45 | output d_g2, 46 | output d_b2, 47 | output vga_hsync, 48 | output vga_vsync, 49 | output[5:0] red, 50 | output[6:0] green, 51 | output[5:0] blue, 52 | 53 | // Config switches 54 | input switch2, 55 | input switch3 56 | ); 57 | 58 | // Sets up the card to generate a video signal 59 | // that will work with a standard VGA monitor 60 | // connected to the VGA port. 61 | parameter MDA_70HZ = 0; 62 | 63 | wire clk_main; 64 | wire pll_lock; 65 | 66 | wire[7:0] bus_out; 67 | 68 | wire[3:0] video; 69 | // wire[3:0] vga_video; 70 | 71 | wire composite_on; 72 | wire thin_font; 73 | 74 | wire[5:0] vga_red; 75 | wire[6:0] vga_green; 76 | wire[5:0] vga_blue; 77 | wire[6:0] comp_video; 78 | 79 | // Unused pins on video connector 80 | assign bus_0ws_l = 1'b1; 81 | assign vid_en_l = 1'b0; 82 | 83 | assign d_r = video[2]; 84 | assign d_g = video[1]; 85 | assign d_b = video[0]; 86 | assign d_r2 = 1'b0; 87 | assign d_g2 = video[3]; 88 | assign d_b2 = 1'b0; 89 | 90 | // Composite mode switch 91 | assign composite_on = switch3; 92 | 93 | // Thin font switch 94 | assign thin_font = switch2; 95 | 96 | // Set up bus direction 97 | assign bus_d = (bus_dir) ? bus_out : 8'hzz; 98 | 99 | // CGA mode 100 | // Take our incoming 14.318MHz clock and generate the pixel clock 101 | // 28.636MHz: 0, 63, 5 102 | // Could also use an SB_PLL40_2_PAD to generate an additional 103 | // 14.318MHz clock without having to use a separate divider. 104 | wire int_clk; 105 | `ifdef SYNTHESIS 106 | SB_PLL40_PAD #( 107 | .FEEDBACK_PATH("SIMPLE"), 108 | .DIVR(0), 109 | .DIVF(63), 110 | .DIVQ(5), 111 | .FILTER_RANGE(1) 112 | ) cga_pll ( 113 | .LOCK(pll_lock), 114 | .RESETB(1'b1), 115 | .BYPASS(1'b0), 116 | .PACKAGEPIN(clk_14m318), 117 | .PLLOUTGLOBAL(clk_main) 118 | ); 119 | `else 120 | assign clk_main = clk_14m318; 121 | `endif 122 | 123 | // CGA digital to analog converter 124 | cga_vgaport vga ( 125 | .clk(clk_main), 126 | .video(video), 127 | .red(vga_red), 128 | .green(vga_green), 129 | .blue(vga_blue) 130 | ); 131 | 132 | // Analog output mux: Either RGB or composite 133 | assign red = composite_on ? 6'd0 : vga_red; 134 | assign green = composite_on ? comp_video : vga_green; 135 | assign blue = composite_on ? 6'd0 : vga_blue; 136 | 137 | assign vga_vsync = vsync; 138 | assign vga_hsync = hsync; 139 | 140 | cga cga1 ( 141 | .clk(clk_main), 142 | .bus_a(bus_a), 143 | .bus_ior_l(bus_ior_l), 144 | .bus_iow_l(bus_iow_l), 145 | .bus_memr_l(bus_memr_l), 146 | .bus_memw_l(bus_memw_l), 147 | .bus_d(bus_d), 148 | .bus_out(bus_out), 149 | .bus_dir(bus_dir), 150 | .bus_aen(bus_aen), 151 | .bus_rdy(bus_rdy), 152 | .ram_we_l(ram_we_l), 153 | .ram_a(ram_a), 154 | .ram_d(ram_d), 155 | .hsync(hsync), 156 | // .dbl_hsync(vga_hsync), 157 | .vsync(vsync), 158 | .video(video), 159 | // .dbl_video(vga_video), 160 | .comp_video(comp_video), 161 | .thin_font(thin_font) 162 | ); 163 | `ifdef SYNTHESIS 164 | defparam cga1.BLINK_MAX = 24'd4772727; 165 | `else 166 | defparam cga1.BLINK_MAX = 24'd10; 167 | `endif 168 | 169 | endmodule 170 | -------------------------------------------------------------------------------- /verilog/cga_vgaport.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | module cga_vgaport( 10 | input clk, 11 | 12 | input[3:0] video, 13 | 14 | // Analog outputs 15 | output[5:0] red, 16 | output[6:0] green, 17 | output[5:0] blue 18 | ); 19 | 20 | reg[17:0] c; 21 | 22 | assign blue = c[5:0]; 23 | assign green = {c[11:6], 1'b1}; // FIXME: 1? 24 | assign red = c[17:12]; 25 | 26 | always @(posedge clk) 27 | begin 28 | case(video) 29 | 4'h0: c <= 18'b000000_000000_000000; 30 | 4'h1: c <= 18'b000000_000000_101010; 31 | 4'h2: c <= 18'b000000_101010_000000; 32 | 4'h3: c <= 18'b000000_101010_101010; 33 | 4'h4: c <= 18'b101010_000000_000000; 34 | 4'h5: c <= 18'b101010_000000_101010; 35 | 4'h6: c <= 18'b101010_010101_000000; // Brown! 36 | 4'h7: c <= 18'b101010_101010_101010; 37 | 4'h8: c <= 18'b010101_010101_010101; 38 | 4'h9: c <= 18'b010101_010101_111111; 39 | 4'hA: c <= 18'b010101_111111_010101; 40 | 4'hB: c <= 18'b010101_111111_111111; 41 | 4'hC: c <= 18'b111111_010101_010101; 42 | 4'hD: c <= 18'b111111_010101_111111; 43 | 4'hE: c <= 18'b111111_111111_010101; 44 | 4'hF: c <= 18'b111111_111111_111111; 45 | default: ; 46 | endcase 47 | end 48 | endmodule 49 | -------------------------------------------------------------------------------- /verilog/cga_vram.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | module cga_vram( 10 | // Clock 11 | input clk, 12 | 13 | // Lines from other logic 14 | // Port 0 is read/write 15 | input[18:0] isa_addr, 16 | input[7:0] isa_din, 17 | output[7:0] isa_dout, 18 | input isa_read, 19 | input isa_write, 20 | input isa_op_enable, 21 | 22 | // Port 1 is read only 23 | input[18:0] pixel_addr, 24 | output reg[7:0] pixel_data, 25 | input pixel_read, 26 | 27 | // Lines to RAM pins 28 | output reg[18:0] ram_a, 29 | inout[7:0] ram_d, 30 | output ram_ce_l, 31 | output ram_oe_l, 32 | output ram_we_l 33 | ); 34 | 35 | parameter MDA_70HZ = 0; 36 | 37 | reg[19:0] op_addr = 20'd0; 38 | reg[7:0] ram_write_data = 8'd0; 39 | reg isa_write_old = 1'b0; 40 | reg[2:0] write_del = 0; 41 | 42 | assign ram_ce_l = 0; 43 | assign ram_oe_l = 0; 44 | 45 | assign ram_we_l = ~(write_del == 3'd4); 46 | assign isa_dout = ram_d; 47 | 48 | // Gated by clock so that we give the SRAM chip 49 | // some time to tristate its data output after 50 | // we begin the write operation. (tHZWE) 51 | assign ram_d = (~ram_we_l & ~clk) ? ram_write_data : 8'hZZ; 52 | 53 | // RAM address pin mux 54 | always @ (*) 55 | begin 56 | if (isa_read) begin 57 | ram_a <= isa_addr; 58 | end else if ((write_del == 3'd3) || (write_del == 3'd4)) begin 59 | ram_a <= op_addr; 60 | end else begin 61 | ram_a <= pixel_addr; 62 | end 63 | end 64 | 65 | // For edge detection of ISA writes 66 | always @ (posedge clk) 67 | begin 68 | isa_write_old <= isa_write; 69 | end 70 | 71 | // Address is latched on initial edge of write 72 | always @ (posedge clk) 73 | begin 74 | if (isa_write && !isa_write_old) begin 75 | op_addr <= isa_addr; 76 | end 77 | end 78 | 79 | // Wait a few cycles before latching data from ISA 80 | // bus, since the data isn't valid right away. 81 | always @ (posedge clk) 82 | begin 83 | if (isa_write && !isa_write_old) begin 84 | write_del <= 3'd1; 85 | end else if (write_del != 3'd0) begin 86 | if (write_del == 3'd7) begin 87 | write_del <= 3'd0; 88 | end else begin 89 | write_del <= write_del + 1; 90 | end 91 | end 92 | end 93 | 94 | always @ (posedge clk) 95 | begin 96 | if (write_del == 3'd2) begin 97 | ram_write_data <= isa_din; 98 | end 99 | end 100 | 101 | // Pixel data output mux 102 | always @ (posedge clk) 103 | begin 104 | if (isa_read || (write_del == 3'd3) || (write_del == 3'd4)) begin 105 | // The cause of CGA snow! 106 | pixel_data <= 8'hff; 107 | end else begin 108 | pixel_data <= ram_d; 109 | end 110 | end 111 | 112 | endmodule 113 | -------------------------------------------------------------------------------- /verilog/gremlin.pcf: -------------------------------------------------------------------------------- 1 | ### Graphics Gremlin 2 | 3 | ### Copyright (c) 2021 Eric Schlaepfer 4 | ### This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | ### International License. To view a copy of this license, visit 6 | ### http://creativecommons.org/license/by-sa/4.0/ or send a letter to Creative 7 | ### Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | 9 | ### Clocks 10 | set_io clk_14m318 129 11 | set_io clk_10m 49 12 | set_io clk_bus 128 13 | 14 | ### Bus reset 15 | set_io busreset 52 16 | 17 | ### ISA bus 18 | set_io bus_a[0] 1 19 | set_io bus_a[1] 2 20 | set_io bus_a[2] 3 21 | set_io bus_a[3] 4 22 | set_io bus_a[4] 7 23 | set_io bus_a[5] 8 24 | set_io bus_a[6] 9 25 | set_io bus_a[7] 10 26 | set_io bus_a[8] 11 27 | set_io bus_a[9] 12 28 | set_io bus_a[10] 15 29 | set_io bus_a[11] 16 30 | set_io bus_a[12] 17 31 | set_io bus_a[13] 18 32 | set_io bus_a[14] 19 33 | set_io bus_a[15] 20 34 | set_io bus_a[16] 21 35 | set_io bus_a[17] 22 36 | set_io bus_a[18] 23 37 | set_io bus_a[19] 24 38 | set_io bus_ior_l 25 39 | set_io bus_iow_l 26 40 | set_io bus_memr_l 28 41 | set_io bus_memw_l 29 42 | set_io bus_d[0] 31 43 | set_io bus_d[1] 32 44 | set_io bus_d[2] 33 45 | set_io bus_d[3] 34 46 | set_io bus_d[4] 37 47 | set_io bus_d[5] 38 48 | set_io bus_d[6] 39 49 | set_io bus_d[7] 41 50 | set_io bus_dir 42 51 | set_io bus_rdy 43 52 | set_io bus_0ws_l 44 53 | set_io bus_aen 45 54 | set_io bus_ale 47 55 | 56 | ### RAM 57 | set_io ram_we_l 130 58 | set_io ram_a[0] 105 59 | set_io ram_a[1] 106 60 | set_io ram_a[2] 110 61 | set_io ram_a[3] 113 62 | set_io ram_a[4] 115 63 | set_io ram_a[5] 135 64 | set_io ram_a[6] 137 65 | set_io ram_a[7] 139 66 | set_io ram_a[8] 142 67 | set_io ram_a[9] 144 68 | set_io ram_a[10] 143 69 | set_io ram_a[11] 141 70 | set_io ram_a[12] 138 71 | set_io ram_a[13] 136 72 | set_io ram_a[14] 134 73 | set_io ram_a[15] 116 74 | set_io ram_a[16] 114 75 | set_io ram_a[17] 112 76 | set_io ram_a[18] 107 77 | set_io ram_d[0] 117 78 | set_io ram_d[1] 119 79 | set_io ram_d[2] 121 80 | set_io ram_d[3] 124 81 | set_io ram_d[4] 125 82 | set_io ram_d[5] 122 83 | set_io ram_d[6] 120 84 | set_io ram_d[7] 118 85 | 86 | ### Video outputs 87 | set_io hsync 60 88 | set_io vsync 55 89 | set_io d_r 61 90 | set_io d_g 56 91 | set_io d_b 48 92 | set_io d_r2 73 93 | set_io d_g2 74 94 | set_io d_b2 62 95 | set_io vid_en_l 75 96 | set_io vga_hsync 102 97 | set_io vga_vsync 104 98 | set_io red[0] 93 99 | set_io red[1] 94 100 | set_io red[2] 95 101 | set_io red[3] 96 102 | set_io red[4] 97 103 | set_io red[5] 98 104 | set_io green[0] 83 105 | set_io green[1] 84 106 | set_io green[2] 85 107 | set_io green[3] 87 108 | set_io green[4] 88 109 | set_io green[5] 90 110 | set_io green[6] 91 111 | set_io blue[0] 76 112 | set_io blue[1] 78 113 | set_io blue[2] 79 114 | set_io blue[3] 80 115 | set_io blue[4] 81 116 | set_io blue[5] 82 117 | 118 | # Config switch inputs 119 | set_io switch2 101 120 | set_io switch3 99 121 | -------------------------------------------------------------------------------- /verilog/is61_tester.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | `timescale 1ns / 1ps 10 | module is61_tester; 11 | 12 | reg[18:0] address; 13 | wire[7:0] data; 14 | reg ce_l; 15 | reg oe_l; 16 | reg we_l; 17 | 18 | reg[7:0] data_out; 19 | reg data_dir; 20 | 21 | assign data = data_dir ? data_out : 8'hzz; 22 | 23 | is61c5128 dut( 24 | .address(address), 25 | .data(data), 26 | .ce_l(ce_l), 27 | .oe_l(oe_l), 28 | .we_l(we_l) 29 | ); 30 | 31 | initial begin 32 | $dumpfile("is61_tester.vcd"); 33 | $dumpvars(0,is61_tester); 34 | ce_l = 1; 35 | oe_l = 1; 36 | we_l = 1; 37 | address = 19'h00000; 38 | data_out = 8'h00; 39 | data_dir = 0; 40 | 41 | #500 42 | data_dir = 1; 43 | data_out = 8'hAA; 44 | ce_l = 0; 45 | oe_l = 0; 46 | we_l = 0; 47 | #10 48 | we_l = 1; 49 | data_dir = 0; 50 | #10 51 | address = 19'h1; 52 | data_dir = 1; 53 | data_out = 8'h55; 54 | we_l = 0; 55 | #10 56 | we_l = 1; 57 | data_dir = 0; 58 | #10 59 | address = 19'h0; 60 | 61 | 62 | #100 $finish; 63 | end 64 | endmodule 65 | -------------------------------------------------------------------------------- /verilog/is61c5128_t.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | 10 | // behavioral model of IS61C5128AL SRAM 11 | module is61c5128( 12 | input[18:0] address, 13 | inout[7:0] data, 14 | input ce_l, 15 | input oe_l, 16 | input we_l 17 | ); 18 | 19 | wire array_out; 20 | wire[7:0] data_out; 21 | wire[7:0] data_in_delay; 22 | wire[7:0] debug_data0; 23 | wire data_dir; 24 | 25 | wire ce_delay; 26 | wire oe_delay; 27 | wire we_delay; 28 | wire[18:0] addr_delay; 29 | integer i; 30 | // Truncated data array for simulation speed 31 | reg [7:0] data_array[0:1024]; 32 | 33 | initial begin 34 | for (i = 0; i < 1024; i++) begin 35 | data_array[i] = i & 8'hFF; 36 | end 37 | end 38 | 39 | assign debug_data0 = data_array[10'h00]; 40 | 41 | assign #10 addr_delay = address; 42 | assign #2 ce_delay = ~ce_l; // 2ns tLZCS 43 | assign oe_delay = ~oe_l; // 0ns min tLZOE 44 | assign #3 we_delay = ~we_l; // 3ns tLZWE 45 | assign #1 data_in_delay = data; // This makes the 0ns hold time work 46 | 47 | // Tristate buffer 48 | assign data_dir = ce_delay & oe_delay & ~we_delay; 49 | assign data = data_dir ? data_out : 8'hzz; 50 | 51 | assign data_out = data_array[addr_delay[10:0]]; 52 | 53 | always @ (posedge we_l) begin 54 | data_array[addr_delay[10:0]] <= data_in_delay; 55 | end 56 | 57 | endmodule 58 | 59 | -------------------------------------------------------------------------------- /verilog/isavideo.binm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/verilog/isavideo.binm -------------------------------------------------------------------------------- /verilog/isavideo_t.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | `timescale 1ns / 1ps 10 | 11 | // Test bench for ISA Video 12 | 13 | module isavideo_t; 14 | reg clk; 15 | wire hsync; 16 | wire vsync; 17 | wire video; 18 | 19 | reg[19:0] bus_a; 20 | wire[7:0] bus_d; 21 | reg[7:0] bus_d_out; 22 | reg bus_d_write = 0; 23 | wire bus_rdy; 24 | 25 | assign bus_d = (bus_d_write) ? bus_d_out : 8'hZZ; 26 | 27 | reg bus_ior_l = 1; 28 | reg bus_iow_l = 1; 29 | reg bus_memr_l = 1; 30 | reg bus_memw_l = 1; 31 | reg bus_aen = 1; 32 | 33 | wire ram_we_l; 34 | wire[18:0] ram_a; 35 | wire[7:0] ram_d; 36 | // Use isavideo here for HGC, cga_top for CGA. 37 | cga_top dut ( 38 | // .clk_10m(clk), // for HGC 39 | .clk_14m318(clk), // for CGA 40 | 41 | .bus_a(bus_a), 42 | .bus_ior_l(bus_ior_l), 43 | .bus_iow_l(bus_iow_l), 44 | .bus_memr_l(bus_memr_l), 45 | .bus_memw_l(bus_memw_l), 46 | .bus_aen(bus_aen), 47 | .bus_d(bus_d), 48 | .bus_rdy(bus_rdy), 49 | 50 | .ram_we_l(ram_we_l), 51 | .ram_d(ram_d), 52 | .ram_a(ram_a), 53 | 54 | .hsync(hsync), 55 | .vsync(vsync), 56 | .d_b2(video), 57 | .switch3(1'b0), 58 | .switch2(1'b0) 59 | ); 60 | 61 | is61c5128 vram( 62 | .address(ram_a), 63 | .data(ram_d), 64 | .ce_l(0), 65 | .oe_l(0), 66 | .we_l(ram_we_l) 67 | ); 68 | 69 | // 15=33.3MHz 70 | // 8=62.5MHz 71 | // 17=29.4MHz 72 | always #17 clk = ~clk; 73 | 74 | task isa_op; 75 | input state; 76 | input read; 77 | input io; 78 | begin 79 | if (read) begin 80 | if (io) begin 81 | bus_ior_l = state; 82 | end else begin 83 | bus_memr_l = state; 84 | end 85 | end else begin 86 | if (io) begin 87 | bus_iow_l = state; 88 | end else begin 89 | bus_memw_l = state; 90 | end 91 | end 92 | end 93 | endtask 94 | 95 | task isa_cycle; 96 | input[19:0] addr; 97 | input[7:0] data; 98 | input read; 99 | input io; 100 | begin 101 | bus_a = addr; 102 | bus_d_write = !read; 103 | bus_d_out = data; 104 | #176 105 | isa_op(0, read, io); 106 | #420 107 | wait(bus_rdy); 108 | isa_op(1, read, io); 109 | #236 110 | bus_d_write = 0; 111 | end 112 | endtask 113 | 114 | task crtc_write; 115 | input[7:0] addr; 116 | input[7:0] data; 117 | begin 118 | isa_cycle(20'h3D4, addr, 0, 1); 119 | isa_cycle(20'h3D5, data, 0, 1); 120 | end 121 | endtask 122 | 123 | integer i; 124 | 125 | initial begin 126 | clk = 0; 127 | $dumpfile("isavideo_t.vcd"); 128 | $dumpvars(0,isavideo_t); 129 | 130 | bus_aen = 0; 131 | 132 | // Set up graphics mode for this test. 133 | isa_cycle(20'h3D8, 8'b0000_1011, 0, 1); // 0000_1010 134 | isa_cycle(20'h3D9, 8'b0000_0000, 0, 1); 135 | crtc_write(8'd0, 8'd56); 136 | crtc_write(8'd1, 8'd40); 137 | crtc_write(8'd2, 8'd45); 138 | crtc_write(8'd4, 8'd127); 139 | crtc_write(8'd6, 8'd100); 140 | crtc_write(8'd7, 8'd112); 141 | crtc_write(8'd9, 8'd1); 142 | 143 | 144 | 145 | 146 | bus_a = 20'hB8055; 147 | bus_d_out = 8'hAA; 148 | bus_d_write = 1; 149 | #430 150 | #120 bus_memw_l = 0; 151 | #200 bus_memw_l = 1; 152 | #10 bus_d_write = 0; 153 | #100 bus_memr_l = 0; 154 | #200 bus_memr_l = 1; 155 | 156 | for (i = 0; i < 20; i++) begin 157 | #12 158 | #400 159 | bus_a = 20'hB8000 | i; 160 | bus_d_out = 8'h11; //8'hA0 + i; 161 | bus_memw_l = 0; 162 | bus_d_write = 1; 163 | #600 164 | wait(bus_rdy); 165 | bus_memw_l = 1; // was 200 166 | #50 bus_d_write = 0; 167 | end 168 | #400 169 | for (i = 0; i < 20; i++) begin 170 | #12 171 | #400 172 | bus_a = 20'hB8000 | i; 173 | bus_memr_l = 0; 174 | bus_d_write = 0; 175 | #600 176 | wait(bus_rdy); 177 | bus_memr_l = 1; 178 | end 179 | #400 180 | for (i = 0; i < 20; i+=2) begin 181 | bus_a = 20'hB8000 | i; 182 | bus_d_write = 0; 183 | #176 184 | bus_memr_l = 0; 185 | #420 186 | wait(bus_rdy); 187 | bus_memr_l = 1; 188 | #236 189 | bus_a = 20'hB8000 | (i + 1); 190 | #174 191 | bus_memr_l = 0; 192 | #420 193 | wait(bus_rdy); 194 | bus_memr_l = 1; 195 | #886 196 | bus_a = 20'hB8000 | i; 197 | bus_d_out = 8'h00 + (2<<(i&7)); 198 | bus_d_write = 1; 199 | #164 200 | bus_memw_l = 0; 201 | #420 202 | wait(bus_rdy); 203 | bus_memw_l = 1; 204 | #224 205 | bus_a = 20'hB8000 | (i + 1); 206 | bus_d_out = 8'h00 + (2<<((i + 1)&7)); 207 | #196 208 | bus_memw_l = 0; 209 | #420 210 | wait(bus_rdy); 211 | bus_memw_l = 1; 212 | #1494 213 | bus_d_write = 0; 214 | end 215 | 216 | // Try to write to CRTC 217 | bus_a = 20'h3D4; 218 | bus_aen = 0; 219 | bus_iow_l = 0; 220 | bus_d_write = 1; 221 | bus_d_out = 8'd1; 222 | #600 bus_iow_l = 1; 223 | bus_aen = 1; 224 | #400 225 | bus_a = 20'h3D5; 226 | bus_aen = 0; 227 | bus_iow_l = 0; 228 | bus_d_write = 1; 229 | bus_d_out = 8'd5; 230 | #600 bus_iow_l = 1; 231 | bus_aen = 1; 232 | bus_d_write = 0; 233 | #400 234 | bus_aen = 0; 235 | bus_ior_l = 0; 236 | bus_d_write = 0; 237 | #600 bus_ior_l = 1; 238 | bus_aen = 0; 239 | #350000 $finish; 240 | #10000 $finish; 241 | end 242 | endmodule 243 | 244 | -------------------------------------------------------------------------------- /verilog/jtopl/doc/Makefile: -------------------------------------------------------------------------------- 1 | all: lfo_count opll_patches 2 | 3 | lfo_count: lfo_count.cc opll.c 4 | 5 | opll_patches: opll_patches.c opll.c -------------------------------------------------------------------------------- /verilog/jtopl/doc/Y8950 app notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/verilog/jtopl/doc/Y8950 app notes.pdf -------------------------------------------------------------------------------- /verilog/jtopl/doc/Y8950 datasheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/verilog/jtopl/doc/Y8950 datasheet.pdf -------------------------------------------------------------------------------- /verilog/jtopl/doc/YM2413.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/verilog/jtopl/doc/YM2413.pdf -------------------------------------------------------------------------------- /verilog/jtopl/doc/YM3812 datasheet.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/verilog/jtopl/doc/YM3812 datasheet.pdf -------------------------------------------------------------------------------- /verilog/jtopl/doc/Yamaha YM3812 Application Manual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/verilog/jtopl/doc/Yamaha YM3812 Application Manual.pdf -------------------------------------------------------------------------------- /verilog/jtopl/doc/lfo_count.cc: -------------------------------------------------------------------------------- 1 | #include "opll.h" 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | int main() { 8 | opll_t fm; 9 | OPLL_Reset(&fm, opll_type_ym2413); 10 | int last=0; 11 | for( int k=0; k<1'000'000; k++ ) { 12 | int32_t buffer[2]; 13 | if( last != fm.lfo_am_out ) { 14 | cout << setw(10) << k << " " << setw(4) << fm.lfo_am_counter 15 | << " " << (int)fm.lfo_am_car << " DIR=" << (int)fm.lfo_am_dir 16 | << " " << (int)fm.lfo_am_out << '\n'; 17 | last = fm.lfo_am_out; 18 | } 19 | OPLL_Clock( &fm, buffer); 20 | } 21 | } 22 | 23 | -------------------------------------------------------------------------------- /verilog/jtopl/doc/notes.ods: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/verilog/jtopl/doc/notes.ods -------------------------------------------------------------------------------- /verilog/jtopl/doc/opl3.h: -------------------------------------------------------------------------------- 1 | /* Nuked OPL3 2 | * Copyright (C) 2013-2020 Nuke.YKT 3 | * 4 | * This file is part of Nuked OPL3. 5 | * 6 | * Nuked OPL3 is free software: you can redistribute it and/or modify 7 | * it under the terms of the GNU Lesser General Public License as 8 | * published by the Free Software Foundation, either version 2.1 9 | * of the License, or (at your option) any later version. 10 | * 11 | * Nuked OPL3 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 Lesser General Public License for more details. 15 | * 16 | * You should have received a copy of the GNU Lesser General Public License 17 | * along with Nuked OPL3. If not, see . 18 | 19 | * Nuked OPL3 emulator. 20 | * Thanks: 21 | * MAME Development Team(Jarek Burczynski, Tatsuyuki Satoh): 22 | * Feedback and Rhythm part calculation information. 23 | * forums.submarine.org.uk(carbon14, opl3): 24 | * Tremolo and phase generator calculation information. 25 | * OPLx decapsulated(Matthew Gambrell, Olli Niemitalo): 26 | * OPL2 ROMs. 27 | * siliconpr0n.org(John McMaster, digshadow): 28 | * YMF262 and VRC VII decaps and die shots. 29 | * 30 | * version: 1.8 31 | */ 32 | 33 | #ifndef OPL_OPL3_H 34 | #define OPL_OPL3_H 35 | 36 | #include 37 | 38 | #define OPL_WRITEBUF_SIZE 1024 39 | #define OPL_WRITEBUF_DELAY 2 40 | 41 | typedef uintptr_t Bitu; 42 | typedef intptr_t Bits; 43 | typedef uint64_t Bit64u; 44 | typedef int64_t Bit64s; 45 | typedef uint32_t Bit32u; 46 | typedef int32_t Bit32s; 47 | typedef uint16_t Bit16u; 48 | typedef int16_t Bit16s; 49 | typedef uint8_t Bit8u; 50 | typedef int8_t Bit8s; 51 | 52 | typedef struct _opl3_slot opl3_slot; 53 | typedef struct _opl3_channel opl3_channel; 54 | typedef struct _opl3_chip opl3_chip; 55 | 56 | struct _opl3_slot { 57 | opl3_channel *channel; 58 | opl3_chip *chip; 59 | Bit16s out; 60 | Bit16s fbmod; 61 | Bit16s *mod; 62 | Bit16s prout; 63 | Bit16s eg_rout; 64 | Bit16s eg_out; 65 | Bit8u eg_inc; 66 | Bit8u eg_gen; 67 | Bit8u eg_rate; 68 | Bit8u eg_ksl; 69 | Bit8u *trem; 70 | Bit8u reg_vib; 71 | Bit8u reg_type; 72 | Bit8u reg_ksr; 73 | Bit8u reg_mult; 74 | Bit8u reg_ksl; 75 | Bit8u reg_tl; 76 | Bit8u reg_ar; 77 | Bit8u reg_dr; 78 | Bit8u reg_sl; 79 | Bit8u reg_rr; 80 | Bit8u reg_wf; 81 | Bit8u key; 82 | Bit32u pg_reset; 83 | Bit32u pg_phase; 84 | Bit16u pg_phase_out; 85 | Bit8u slot_num; 86 | }; 87 | 88 | struct _opl3_channel { 89 | opl3_slot *slots[2]; 90 | opl3_channel *pair; 91 | opl3_chip *chip; 92 | Bit16s *out[4]; 93 | Bit8u chtype; 94 | Bit16u f_num; 95 | Bit8u block; 96 | Bit8u fb; 97 | Bit8u con; 98 | Bit8u alg; 99 | Bit8u ksv; 100 | Bit16u cha, chb; 101 | Bit8u ch_num; 102 | }; 103 | 104 | typedef struct _opl3_writebuf { 105 | Bit64u time; 106 | Bit16u reg; 107 | Bit8u data; 108 | } opl3_writebuf; 109 | 110 | struct _opl3_chip { 111 | opl3_channel channel[18]; 112 | opl3_slot slot[36]; 113 | Bit16u timer; 114 | Bit64u eg_timer; 115 | Bit8u eg_timerrem; 116 | Bit8u eg_state; 117 | Bit8u eg_add; 118 | Bit8u newm; 119 | Bit8u nts; 120 | Bit8u rhy; 121 | Bit8u vibpos; 122 | Bit8u vibshift; 123 | Bit8u tremolo; 124 | Bit8u tremolopos; 125 | Bit8u tremoloshift; 126 | Bit32u noise; 127 | Bit16s zeromod; 128 | Bit32s mixbuff[2]; 129 | Bit8u rm_hh_bit2; 130 | Bit8u rm_hh_bit3; 131 | Bit8u rm_hh_bit7; 132 | Bit8u rm_hh_bit8; 133 | Bit8u rm_tc_bit3; 134 | Bit8u rm_tc_bit5; 135 | //OPL3L 136 | Bit32s rateratio; 137 | Bit32s samplecnt; 138 | Bit16s oldsamples[2]; 139 | Bit16s samples[2]; 140 | 141 | Bit64u writebuf_samplecnt; 142 | Bit32u writebuf_cur; 143 | Bit32u writebuf_last; 144 | Bit64u writebuf_lasttime; 145 | opl3_writebuf writebuf[OPL_WRITEBUF_SIZE]; 146 | }; 147 | 148 | void OPL3_Generate(opl3_chip *chip, Bit16s *buf); 149 | void OPL3_GenerateResampled(opl3_chip *chip, Bit16s *buf); 150 | void OPL3_Reset(opl3_chip *chip, Bit32u samplerate); 151 | void OPL3_WriteReg(opl3_chip *chip, Bit16u reg, Bit8u v); 152 | void OPL3_WriteRegBuffered(opl3_chip *chip, Bit16u reg, Bit8u v); 153 | void OPL3_GenerateStream(opl3_chip *chip, Bit16s *sndptr, Bit32u numsamples); 154 | #endif 155 | -------------------------------------------------------------------------------- /verilog/jtopl/doc/opll.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Nuke.YKT 3 | * 4 | * This program is free software; you can redistribute it and/or 5 | * modify it under the terms of the GNU General Public License 6 | * as published by the Free Software Foundation; either version 2 7 | * of the License, or (at your option) any later version. 8 | * 9 | * This program is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * 15 | * Yamaha YM2413 emulator 16 | * Thanks: 17 | * siliconpr0n.org(digshadow, John McMaster): 18 | * VRC VII decap and die shot. 19 | * 20 | * version: 1.0.1 21 | */ 22 | 23 | #ifndef OPLL_H 24 | #define OPLL_H 25 | 26 | #include 27 | 28 | enum { 29 | opll_type_ym2413 = 0x00, /* Yamaha YM2413 */ 30 | opll_type_ds1001, /* Konami VRC VII */ 31 | opll_type_ym2413b, /* Yamaha YM2413B */ 32 | opll_type_ymf281, /* Yamaha YMF281 */ 33 | opll_type_ymf281b, /* Yamaha YMF281B */ 34 | opll_type_ym2420, /* Yamaha YM2420 */ 35 | opll_type_ym2423, /* Yamaha YM2423 */ 36 | }; 37 | 38 | enum { 39 | opll_patch_1 = 0x00, 40 | opll_patch_2, 41 | opll_patch_3, 42 | opll_patch_4, 43 | opll_patch_5, 44 | opll_patch_6, 45 | opll_patch_7, 46 | opll_patch_8, 47 | opll_patch_9, 48 | opll_patch_10, 49 | opll_patch_11, 50 | opll_patch_12, 51 | opll_patch_13, 52 | opll_patch_14, 53 | opll_patch_15, 54 | opll_patch_drum_0, 55 | opll_patch_drum_1, 56 | opll_patch_drum_2, 57 | opll_patch_drum_3, 58 | opll_patch_drum_4, 59 | opll_patch_drum_5, 60 | opll_patch_max 61 | }; 62 | 63 | typedef struct { 64 | uint8_t tl; 65 | uint8_t dc; 66 | uint8_t dm; 67 | uint8_t fb; 68 | uint8_t am[2]; 69 | uint8_t vib[2]; 70 | uint8_t et[2]; 71 | uint8_t ksr[2]; 72 | uint8_t multi[2]; 73 | uint8_t ksl[2]; 74 | uint8_t ar[2]; 75 | uint8_t dr[2]; 76 | uint8_t sl[2]; 77 | uint8_t rr[2]; 78 | } opll_patch_t; 79 | 80 | typedef struct { 81 | uint32_t chip_type; 82 | uint32_t cycles; 83 | uint32_t slot; 84 | const opll_patch_t *patchrom; 85 | /* IO */ 86 | uint8_t write_data; 87 | uint8_t write_a; 88 | uint8_t write_d; 89 | uint8_t write_a_en; 90 | uint8_t write_d_en; 91 | uint8_t write_fm_address; 92 | uint8_t write_fm_data; 93 | uint8_t write_mode_address; 94 | uint8_t address; 95 | uint8_t data; 96 | /* Envelope generator */ 97 | uint8_t eg_counter_state; 98 | uint8_t eg_counter_state_prev; 99 | uint32_t eg_timer; 100 | uint8_t eg_timer_low_lock; 101 | uint8_t eg_timer_carry; 102 | uint8_t eg_timer_shift; 103 | uint8_t eg_timer_shift_lock; 104 | uint8_t eg_timer_shift_stop; 105 | uint8_t eg_state[18]; 106 | uint8_t eg_level[18]; 107 | uint8_t eg_kon; 108 | uint32_t eg_dokon; 109 | uint8_t eg_off; 110 | uint8_t eg_rate; 111 | uint8_t eg_maxrate; 112 | uint8_t eg_zerorate; 113 | uint8_t eg_inc_lo; 114 | uint8_t eg_inc_hi; 115 | uint8_t eg_rate_hi; 116 | uint16_t eg_sl; 117 | uint16_t eg_ksltl; 118 | uint8_t eg_out; 119 | uint8_t eg_silent; 120 | /* Phase generator */ 121 | uint16_t pg_fnum; 122 | uint8_t pg_block; 123 | uint16_t pg_out; 124 | uint32_t pg_inc; 125 | uint32_t pg_phase[18]; 126 | uint32_t pg_phase_next; 127 | /* Operator */ 128 | int16_t op_fb1[9]; 129 | int16_t op_fb2[9]; 130 | int16_t op_fbsum; 131 | int16_t op_mod; 132 | uint8_t op_neg; 133 | uint16_t op_logsin; 134 | uint16_t op_exp_m; 135 | uint16_t op_exp_s; 136 | /* Channel */ 137 | int16_t ch_out; 138 | int16_t ch_out_hh; 139 | int16_t ch_out_tm; 140 | int16_t ch_out_bd; 141 | int16_t ch_out_sd; 142 | int16_t ch_out_tc; 143 | /* LFO */ 144 | uint16_t lfo_counter; 145 | uint8_t lfo_vib_counter; 146 | uint16_t lfo_am_counter; 147 | uint8_t lfo_am_step; 148 | uint8_t lfo_am_dir; 149 | uint8_t lfo_am_car; 150 | uint8_t lfo_am_out; 151 | /* Register set */ 152 | uint16_t fnum[9]; 153 | uint8_t block[9]; 154 | uint8_t kon[9]; 155 | uint8_t son[9]; 156 | uint8_t vol[9]; 157 | uint8_t inst[9]; 158 | uint8_t rhythm; 159 | uint8_t testmode; 160 | opll_patch_t patch; 161 | uint8_t c_instr; 162 | uint8_t c_op; 163 | uint8_t c_tl; 164 | uint8_t c_dc; 165 | uint8_t c_dm; 166 | uint8_t c_fb; 167 | uint8_t c_am; 168 | uint8_t c_vib; 169 | uint8_t c_et; 170 | uint8_t c_ksr; 171 | uint8_t c_ksr_freq; 172 | uint8_t c_ksl_freq; 173 | uint8_t c_ksl_block; 174 | uint8_t c_multi; 175 | uint8_t c_ksl; 176 | uint8_t c_adrr[3]; 177 | uint8_t c_sl; 178 | uint16_t c_fnum; 179 | uint16_t c_block; 180 | /* Rhythm mode */ 181 | int8_t rm_enable; 182 | uint32_t rm_noise; 183 | uint32_t rm_select; 184 | uint8_t rm_hh_bit2; 185 | uint8_t rm_hh_bit3; 186 | uint8_t rm_hh_bit7; 187 | uint8_t rm_hh_bit8; 188 | uint8_t rm_tc_bit3; 189 | uint8_t rm_tc_bit5; 190 | 191 | int16_t output_m; 192 | int16_t output_r; 193 | 194 | } opll_t; 195 | 196 | void OPLL_Reset(opll_t *chip, uint32_t chip_type); 197 | void OPLL_Clock(opll_t *chip, int32_t *buffer); 198 | void OPLL_Write(opll_t *chip, uint32_t port, uint8_t data); 199 | #endif 200 | -------------------------------------------------------------------------------- /verilog/jtopl/doc/opll_patches.c: -------------------------------------------------------------------------------- 1 | #include "opll.h" 2 | #include 3 | 4 | opll_patch_t patch_ym2413[opll_patch_max] = { 5 | { 0x1e, 0x01, 0x00, 0x07,{ 0x00, 0x00 },{ 0x01, 0x01 },{ 0x01, 0x01 },{ 0x01, 0x00 },{ 0x01, 0x01 },{ 0x00, 0x00 },{ 0x0d, 0x07 },{ 0x00, 0x08 },{ 0x00, 0x01 },{ 0x00, 0x07 } }, 6 | { 0x1a, 0x00, 0x01, 0x05,{ 0x00, 0x00 },{ 0x00, 0x01 },{ 0x00, 0x00 },{ 0x01, 0x00 },{ 0x03, 0x01 },{ 0x00, 0x00 },{ 0x0d, 0x0f },{ 0x08, 0x07 },{ 0x02, 0x01 },{ 0x03, 0x03 } }, 7 | { 0x19, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x01, 0x00 },{ 0x03, 0x01 },{ 0x02, 0x00 },{ 0x0f, 0x0c },{ 0x02, 0x04 },{ 0x01, 0x02 },{ 0x01, 0x03 } }, 8 | { 0x0e, 0x00, 0x00, 0x07,{ 0x00, 0x00 },{ 0x00, 0x01 },{ 0x01, 0x01 },{ 0x01, 0x00 },{ 0x01, 0x01 },{ 0x00, 0x00 },{ 0x0a, 0x06 },{ 0x08, 0x04 },{ 0x07, 0x02 },{ 0x00, 0x07 } }, 9 | { 0x1e, 0x00, 0x00, 0x06,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x01, 0x01 },{ 0x01, 0x00 },{ 0x02, 0x01 },{ 0x00, 0x00 },{ 0x0e, 0x07 },{ 0x00, 0x06 },{ 0x00, 0x02 },{ 0x00, 0x08 } }, 10 | { 0x16, 0x00, 0x00, 0x05,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x01, 0x01 },{ 0x01, 0x00 },{ 0x01, 0x02 },{ 0x00, 0x00 },{ 0x0e, 0x07 },{ 0x00, 0x01 },{ 0x00, 0x01 },{ 0x00, 0x08 } }, 11 | { 0x1d, 0x00, 0x00, 0x07,{ 0x00, 0x00 },{ 0x00, 0x01 },{ 0x01, 0x01 },{ 0x00, 0x00 },{ 0x01, 0x01 },{ 0x00, 0x00 },{ 0x08, 0x08 },{ 0x02, 0x01 },{ 0x01, 0x00 },{ 0x00, 0x07 } }, 12 | { 0x2d, 0x01, 0x00, 0x04,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x01, 0x01 },{ 0x00, 0x00 },{ 0x03, 0x01 },{ 0x00, 0x00 },{ 0x0a, 0x07 },{ 0x02, 0x02 },{ 0x00, 0x00 },{ 0x00, 0x07 } }, 13 | { 0x1b, 0x00, 0x00, 0x06,{ 0x00, 0x00 },{ 0x01, 0x01 },{ 0x01, 0x01 },{ 0x00, 0x00 },{ 0x01, 0x01 },{ 0x00, 0x00 },{ 0x06, 0x06 },{ 0x04, 0x05 },{ 0x01, 0x01 },{ 0x00, 0x07 } }, 14 | { 0x0b, 0x01, 0x01, 0x00,{ 0x00, 0x00 },{ 0x01, 0x01 },{ 0x00, 0x01 },{ 0x00, 0x00 },{ 0x01, 0x01 },{ 0x00, 0x00 },{ 0x08, 0x0f },{ 0x05, 0x07 },{ 0x07, 0x00 },{ 0x01, 0x07 } }, 15 | { 0x03, 0x01, 0x00, 0x01,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x01, 0x00 },{ 0x03, 0x01 },{ 0x02, 0x00 },{ 0x0f, 0x0e },{ 0x0a, 0x04 },{ 0x01, 0x00 },{ 0x00, 0x04 } }, 16 | { 0x24, 0x00, 0x00, 0x07,{ 0x00, 0x01 },{ 0x00, 0x01 },{ 0x00, 0x00 },{ 0x01, 0x00 },{ 0x07, 0x01 },{ 0x00, 0x00 },{ 0x0f, 0x0f },{ 0x08, 0x08 },{ 0x02, 0x01 },{ 0x02, 0x02 } }, 17 | { 0x0c, 0x00, 0x00, 0x05,{ 0x00, 0x00 },{ 0x01, 0x01 },{ 0x01, 0x00 },{ 0x00, 0x01 },{ 0x01, 0x00 },{ 0x00, 0x00 },{ 0x0c, 0x0f },{ 0x02, 0x05 },{ 0x02, 0x04 },{ 0x00, 0x02 } }, 18 | { 0x15, 0x00, 0x00, 0x03,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x01, 0x01 },{ 0x01, 0x00 },{ 0x0c, 0x09 },{ 0x09, 0x05 },{ 0x00, 0x00 },{ 0x03, 0x02 } }, 19 | { 0x09, 0x00, 0x00, 0x03,{ 0x00, 0x00 },{ 0x01, 0x01 },{ 0x01, 0x00 },{ 0x00, 0x00 },{ 0x01, 0x01 },{ 0x02, 0x00 },{ 0x0f, 0x0e },{ 0x01, 0x04 },{ 0x04, 0x01 },{ 0x00, 0x03 } }, 20 | 21 | { 0x18, 0x00, 0x01, 0x07,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x01, 0x00 },{ 0x00, 0x00 },{ 0x0d, 0x00 },{ 0x0f, 0x00 },{ 0x06, 0x00 },{ 0x0a, 0x00 } }, 22 | { 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x01, 0x00 },{ 0x00, 0x00 },{ 0x0c, 0x00 },{ 0x08, 0x00 },{ 0x0a, 0x00 },{ 0x07, 0x00 } }, 23 | { 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x05, 0x00 },{ 0x00, 0x00 },{ 0x0f, 0x00 },{ 0x08, 0x00 },{ 0x05, 0x00 },{ 0x09, 0x00 } }, 24 | { 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x01 },{ 0x00, 0x00 },{ 0x00, 0x0f },{ 0x00, 0x08 },{ 0x00, 0x06 },{ 0x00, 0x0d } }, 25 | { 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x01 },{ 0x00, 0x00 },{ 0x00, 0x0d },{ 0x00, 0x08 },{ 0x00, 0x04 },{ 0x00, 0x08 } }, 26 | { 0x00, 0x00, 0x00, 0x00,{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x00 },{ 0x00, 0x01 },{ 0x00, 0x00 },{ 0x00, 0x0a },{ 0x00, 0x0a },{ 0x00, 0x05 },{ 0x00, 0x05 } } 27 | }; 28 | 29 | void make_bin(char *data) { 30 | for( int k=0; kam[0]<<7) 34 | | (p->vib[0]<<6) 35 | | (p->et[0]<<5) 36 | | (p->ksr[0]<<4) 37 | | (p->multi[0]); 38 | d[1]=(p->am[1]<<7) 39 | | (p->vib[1]<<6) 40 | | (p->et[1]<<5) 41 | | (p->ksr[1]<<4) 42 | | (p->multi[1]); 43 | d[2]=(p->ksl[0]<<6) | (p->tl); 44 | d[3]=(p->ksl[1]<<6) | (p->dc<<4) 45 | | (p->dm<<3) | (p->fb); 46 | d[4]=(p->ar[0]<<4) | (p->dr[0]); 47 | d[5]=(p->ar[1]<<4) | (p->dr[1]); 48 | d[6]=(p->sl[0]<<4) | (p->rr[0]); 49 | d[7]=(p->sl[1]<<4) | (p->rr[1]); 50 | for( int j=0; j<8; j++ ) { 51 | *data++ = d[j]; 52 | } 53 | } 54 | } 55 | 56 | int main() { 57 | char data[8*21]; 58 | make_bin(data); 59 | for( int j=0;j<21;j++ ) { 60 | printf(" patch[%02d]=64'h",j+1); 61 | char *p = data+8*(j+1)-1; 62 | for( int k=7; k>=0; k-- ) { 63 | printf("%02X",(unsigned)(*p--)&0xff); 64 | } 65 | printf(";\n"); 66 | } 67 | return 0; 68 | } 69 | 70 | -------------------------------------------------------------------------------- /verilog/jtopl/doc/ym2413 app notes.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/verilog/jtopl/doc/ym2413 app notes.pdf -------------------------------------------------------------------------------- /verilog/jtopl/hdl/common.yaml: -------------------------------------------------------------------------------- 1 | here: 2 | - jtopl_acc.v 3 | - jtopl_csr.v 4 | - jtopl_div.v 5 | - jtopl_lfo.v 6 | - jtopl_pm.v 7 | - jtopl_eg_cnt.v 8 | - jtopl_eg_comb.v 9 | - jtopl_eg_ctrl.v 10 | - jtopl_eg_final.v 11 | - jtopl_eg_pure.v 12 | - jtopl_eg_step.v 13 | - jtopl_eg.v 14 | - jtopl_exprom.v 15 | - jtopl_logsin.v 16 | - jtopl_op.v 17 | - jtopl_pg_comb.v 18 | - jtopl_pg_inc.v 19 | - jtopl_pg_sum.v 20 | - jtopl_pg_rhy.v 21 | - jtopl_pg.v 22 | - jtopl_reg_ch.v 23 | - jtopl_sh_rst.v 24 | - jtopl_sh.v 25 | - jtopl_slot_cnt.v 26 | - jtopl_single_acc.v 27 | - jtopl_timers.v 28 | - jtopl_noise.v 29 | -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jt2413.yaml: -------------------------------------------------------------------------------- 1 | here: 2 | - common.yaml 3 | - jt2413.v 4 | - jtopll_mmr.v 5 | - jtopll_reg.v 6 | -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jt26.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_acc.v] 2 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_csr.v] 3 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_div.v] 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_lfo.v] 5 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_pm.v] 6 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg_cnt.v] 7 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg_comb.v] 8 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg_ctrl.v] 9 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg_final.v] 10 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg_pure.v] 11 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg_step.v] 12 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_eg.v] 13 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_exprom.v] 14 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_logsin.v] 15 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_mmr.v] 16 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_op.v] 17 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_pg_comb.v] 18 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_pg_inc.v] 19 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_pg_sum.v] 20 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_pg_rhy.v] 21 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_pg.v] 22 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_reg.v] 23 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_sh_rst.v] 24 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_sh.v] 25 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_single_acc.v] 26 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_timers.v] 27 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_noise.v] 28 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_slot_cnt.v] 29 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl_reg_ch.v] 30 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl.v] 31 | -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jt26.yaml: -------------------------------------------------------------------------------- 1 | here: 2 | - common.yaml 3 | - jtopl_mmr.v 4 | - jtopl_reg.v 5 | - jtopl.v 6 | -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/spark2k06/graphics-gremlin/8453503e26fb3384a3a737d101b5e054cf8a72e5/verilog/jtopl/hdl/jtopl.yaml -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl2.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) jtopl2.v ] 2 | set_global_assignment -name QIP_FILE [file join $::quartus(qip_path) jt26.qip ] -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl2.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 10-10-2021 19 | 20 | */ 21 | 22 | module jtopl2( 23 | input rst, // rst should be at least 6 clk&cen cycles long 24 | input clk, // CPU clock 25 | input cen, // optional clock enable, it not needed leave as 1'b1 26 | input [ 7:0] din, 27 | input addr, 28 | input cs_n, 29 | input wr_n, 30 | output [ 7:0] dout, 31 | output irq_n, 32 | // combined output 33 | output signed [15:0] snd, 34 | output sample 35 | ); 36 | 37 | `define JTOPL2 38 | jtopl #(.OPL_TYPE(2)) u_base( 39 | .rst ( rst ), 40 | .clk ( clk ), 41 | .cen ( cen ), 42 | .din ( din ), 43 | .addr ( addr ), 44 | .cs_n ( cs_n ), 45 | .wr_n ( wr_n ), 46 | .dout ( dout ), 47 | .irq_n ( irq_n ), 48 | .snd ( snd ), 49 | .sample ( sample ) 50 | ); 51 | 52 | endmodule -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl2.yaml: -------------------------------------------------------------------------------- 1 | here: 2 | - jtopl2.v 3 | - jt26.yaml -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_acc.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | 4 | JTOPL program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | JTOPL program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with JTOPL. If not, see . 16 | 17 | Author: Jose Tejada Gomez. Twitter: @topapate 18 | Version: 1.0 19 | Date: 20-6-2020 20 | 21 | */ 22 | 23 | module jtopl_acc( 24 | input rst, 25 | input clk, 26 | input cenop, 27 | input signed [12:0] op_result, 28 | input zero, 29 | input op, // 0 for modulator operators 30 | input con, // 0 for modulated connection 31 | output signed [15:0] snd 32 | ); 33 | 34 | wire sum_en; 35 | 36 | assign sum_en = op | con; 37 | 38 | // Continuous output 39 | jtopl_single_acc u_acc( 40 | .clk ( clk ), 41 | .cenop ( cenop ), 42 | .op_result ( op_result ), 43 | .sum_en ( sum_en ), 44 | .zero ( zero ), 45 | .snd ( snd ) 46 | ); 47 | 48 | endmodule 49 | -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_csr.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | 4 | JTOPL program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | JTOPL program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with JTOPL. If not, see . 16 | 17 | Author: Jose Tejada Gomez. Twitter: @topapate 18 | Version: 1.0 19 | Date: 17-6-2020 20 | 21 | */ 22 | 23 | module jtopl_csr #( 24 | parameter LEN=18, W=34 25 | ) ( // Circular Shift Register + input mux 26 | input rst, 27 | input clk, 28 | input cen, 29 | input [ 7:0] din, 30 | output [W-1:0] shift_out, 31 | 32 | input up_mult, 33 | input up_ksl_tl, 34 | input up_ar_dr, 35 | input up_sl_rr, 36 | input up_wav, 37 | input update_op_I, 38 | input update_op_II, 39 | input update_op_IV 40 | ); 41 | 42 | 43 | wire [W-1:0] regop_in; 44 | 45 | jtopl_sh_rst #(.width(W),.stages(LEN)) u_regch( 46 | .clk ( clk ), 47 | .cen ( cen ), 48 | .rst ( rst ), 49 | .din ( regop_in ), 50 | .drop ( shift_out ) 51 | ); 52 | 53 | wire up_mult_I = up_mult & update_op_I; 54 | wire up_mult_II = up_mult & update_op_II; 55 | wire up_mult_IV = up_mult & update_op_IV; 56 | wire up_ksl_tl_IV = up_ksl_tl & update_op_IV; 57 | wire up_ar_dr_op = up_ar_dr & update_op_I; 58 | wire up_sl_rr_op = up_sl_rr & update_op_I; 59 | wire up_wav_I = up_wav & update_op_I; 60 | 61 | assign regop_in[31:0] = { // 4 bytes: 62 | up_mult_IV ? din[7] : shift_out[31], // AM enable 63 | up_mult_I ? din[6:5] : shift_out[30:29], // Vib enable, EG type, KSR 64 | up_mult_II ? din[4:0] : shift_out[28:24], // KSR + Mult 65 | 66 | up_ksl_tl_IV? din : shift_out[23:16], // KSL + TL 67 | 68 | up_ar_dr_op ? din : shift_out[15: 8], 69 | 70 | up_sl_rr_op ? din : shift_out[ 7: 0] 71 | }; 72 | 73 | `ifdef JTOPL2 74 | assign regop_in[33:32] = up_wav_I ? din[1:0] : shift_out[33:32]; 75 | `endif 76 | 77 | endmodule // jtopl_reg -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_div.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 10-6-2020 19 | 20 | */ 21 | 22 | module jtopl_div( 23 | input rst, 24 | input clk, 25 | input cen, 26 | output reg cenop // clock enable at operator rate 27 | ); 28 | 29 | parameter OPL_TYPE=1; 30 | 31 | localparam W = 2; // OPL_TYPE==2 ? 1 : 2; 32 | 33 | reg [W-1:0] cnt; 34 | 35 | `ifdef SIMULATION 36 | initial cnt={W{1'b0}}; 37 | `endif 38 | 39 | always @(posedge clk) if(cen) begin 40 | cnt <= cnt+1'd1; 41 | end 42 | 43 | always @(posedge clk) begin 44 | cenop <= cen && (&cnt); 45 | end 46 | 47 | endmodule 48 | -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_eg_cnt.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 17-6-2020 19 | 20 | */ 21 | 22 | module jtopl_eg_cnt( 23 | input rst, 24 | input clk, 25 | input cen, 26 | input zero, 27 | output reg [14:0] eg_cnt 28 | ); 29 | 30 | always @(posedge clk, posedge rst) begin : envelope_counter 31 | if( rst ) begin 32 | eg_cnt <=15'd0; 33 | end 34 | else begin 35 | if( zero && cen ) begin 36 | // envelope counter increases at each zero input 37 | // This is different from OPN/M where it increased 38 | // once every three zero inputs 39 | eg_cnt <= eg_cnt + 1'b1; 40 | end 41 | end 42 | end 43 | 44 | endmodule -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_eg_comb.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 17-6-2020 19 | 20 | */ 21 | 22 | module jtopl_eg_comb( 23 | input keyon_now, 24 | input keyoff_now, 25 | input [ 2:0] state_in, 26 | input [ 9:0] eg_in, 27 | // envelope configuration 28 | input en_sus, // enable sustain 29 | input [ 3:0] arate, // attack rate 30 | input [ 3:0] drate, // decay rate 31 | input [ 3:0] rrate, 32 | input [ 3:0] sl, // sustain level 33 | 34 | output [ 4:0] base_rate, 35 | output [ 2:0] state_next, 36 | output pg_rst, 37 | /////////////////////////////////// 38 | // II 39 | input step_attack, 40 | input [ 4:0] step_rate_in, 41 | input [ 3:0] keycode, 42 | input [14:0] eg_cnt, 43 | input cnt_in, 44 | input ksr, 45 | output cnt_lsb, 46 | output step, 47 | output [ 5:0] step_rate_out, 48 | output sum_up_out, 49 | /////////////////////////////////// 50 | // III 51 | input pure_attack, 52 | input pure_step, 53 | input [ 5:1] pure_rate, 54 | input [ 9:0] pure_eg_in, 55 | output [ 9:0] pure_eg_out, 56 | input sum_up_in, 57 | /////////////////////////////////// 58 | // IV 59 | input [ 3:0] lfo_mod, 60 | input [ 3:0] fnum, 61 | input [ 2:0] block, 62 | input amsen, 63 | input ams, 64 | input [ 5:0] tl, 65 | input [ 1:0] ksl, 66 | input [ 3:0] final_keycode, 67 | input [ 9:0] final_eg_in, 68 | output [ 9:0] final_eg_out 69 | ); 70 | 71 | // I 72 | jtopl_eg_ctrl u_ctrl( 73 | .keyon_now ( keyon_now ), 74 | .keyoff_now ( keyoff_now ), 75 | .state_in ( state_in ), 76 | .eg ( eg_in ), 77 | // envelope configuration 78 | .en_sus ( en_sus ), 79 | .arate ( arate ), // attack rate 80 | .drate ( drate ), // decay rate 81 | .rrate ( rrate ), 82 | .sl ( sl ), // sustain level 83 | 84 | .base_rate ( base_rate ), 85 | .state_next ( state_next ), 86 | .pg_rst ( pg_rst ) 87 | ); 88 | 89 | // II 90 | 91 | jtopl_eg_step u_step( 92 | .attack ( step_attack ), 93 | .base_rate ( step_rate_in ), 94 | .keycode ( keycode ), 95 | .eg_cnt ( eg_cnt ), 96 | .cnt_in ( cnt_in ), 97 | .ksr ( ksr ), 98 | .cnt_lsb ( cnt_lsb ), 99 | .step ( step ), 100 | .rate ( step_rate_out ), 101 | .sum_up ( sum_up_out ) 102 | ); 103 | 104 | // III 105 | 106 | wire [9:0] egin, egout; 107 | jtopl_eg_pure u_pure( 108 | .attack ( pure_attack ), 109 | .step ( pure_step ), 110 | .rate ( pure_rate ), 111 | .eg_in ( pure_eg_in ), 112 | .eg_pure( pure_eg_out ), 113 | .sum_up ( sum_up_in ) 114 | ); 115 | 116 | // IV 117 | 118 | jtopl_eg_final u_final( 119 | .fnum ( fnum ), 120 | .block ( block ), 121 | .lfo_mod ( lfo_mod ), 122 | .amsen ( amsen ), 123 | .ams ( ams ), 124 | .tl ( tl ), 125 | .ksl ( ksl ), 126 | .eg_pure_in ( final_eg_in ), 127 | .eg_limited ( final_eg_out ) 128 | ); 129 | 130 | endmodule // jtopl_eg_comb -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_eg_ctrl.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 17-6-2020 19 | 20 | */ 21 | 22 | module jtopl_eg_ctrl( 23 | input keyon_now, 24 | input keyoff_now, 25 | input [2:0] state_in, 26 | input [9:0] eg, 27 | // envelope configuration 28 | input en_sus, // enable sustain 29 | input [3:0] arate, // attack rate 30 | input [3:0] drate, // decay rate 31 | input [3:0] rrate, 32 | input [3:0] sl, // sustain level 33 | 34 | output reg [4:0] base_rate, 35 | output reg [2:0] state_next, 36 | output reg pg_rst 37 | ); 38 | 39 | localparam ATTACK = 3'b001, 40 | DECAY = 3'b010, 41 | HOLD = 3'b100, 42 | RELEASE= 3'b000; // default state is release 43 | 44 | // wire is_decaying = state_in[1] | state_in[2]; 45 | 46 | wire [4:0] sustain = { &sl, sl}; //93dB if sl==4'hF 47 | 48 | always @(*) begin 49 | pg_rst = keyon_now; 50 | end 51 | 52 | always @(*) 53 | casez ( { keyoff_now, keyon_now, state_in} ) 54 | 5'b01_???: begin // key on 55 | base_rate = {arate,1'b0}; 56 | state_next = ATTACK; 57 | end 58 | {2'b00, ATTACK}: 59 | if( eg==10'd0 ) begin 60 | base_rate = {drate,1'b0}; 61 | state_next = DECAY; 62 | end 63 | else begin 64 | base_rate = {arate,1'b0}; 65 | state_next = ATTACK; 66 | end 67 | {2'b00, DECAY}: begin 68 | if( eg[9:5] >= sustain ) begin 69 | base_rate = en_sus ? 5'd0 : {rrate,1'b0}; 70 | state_next = en_sus ? HOLD : RELEASE; 71 | end else begin 72 | base_rate = {drate,1'b0}; 73 | state_next = DECAY; 74 | end 75 | end 76 | {2'b00, HOLD}: begin 77 | base_rate = 5'd0; 78 | state_next = HOLD; 79 | end 80 | default: begin // RELEASE, note that keyoff_now==1 will enter this state too 81 | base_rate = {rrate,1'b1}; 82 | state_next = RELEASE; // release 83 | end 84 | endcase 85 | 86 | 87 | endmodule // jtopl_eg_ctrl -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_eg_final.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 17-6-2020 19 | 20 | */ 21 | 22 | module jtopl_eg_final( 23 | input [3:0] lfo_mod, 24 | input [3:0] fnum, 25 | input [2:0] block, 26 | input amsen, 27 | input ams, 28 | input [5:0] tl, 29 | input [1:0] ksl, // level damped by pitch 30 | input [9:0] eg_pure_in, 31 | output reg [9:0] eg_limited 32 | ); 33 | 34 | reg [ 5:0] am_final; 35 | reg [11:0] sum_eg_tl; 36 | reg [11:0] sum_eg_tl_am; 37 | reg [ 8:0] ksl_dB; 38 | reg [ 6:0] ksl_lut[0:15]; 39 | reg [ 7:0] ksl_base; 40 | 41 | always @(*) begin 42 | ksl_base = {1'b0, ksl_lut[fnum]}- { 1'b0, 4'd8-{1'b0,block}, 3'b0 }; 43 | if( ksl_base[7] || ksl==2'b0 ) begin 44 | ksl_dB = 9'd0; 45 | end else begin 46 | ksl_dB = {ksl_base[6:0],2'b0} >> ~ksl; 47 | end 48 | end 49 | 50 | always @(*) begin 51 | am_final = amsen ? ( ams ? {lfo_mod, 2'b0} : {2'b0, lfo_mod} ) : 6'd0; 52 | sum_eg_tl = { 2'b0, tl, 3'd0 } + 53 | { 1'b0, ksl_dB, 1'd0 } + 54 | { 1'b0, eg_pure_in}; // leading zeros needed to compute correctly 55 | sum_eg_tl_am = sum_eg_tl + { 5'd0, am_final }; 56 | end 57 | 58 | always @(*) begin 59 | eg_limited = sum_eg_tl_am[11:10]==2'd0 ? sum_eg_tl_am[9:0] : 10'h3ff; 60 | end 61 | 62 | initial begin 63 | ksl_lut[ 0] = 7'd00; ksl_lut[ 1] = 7'd32; ksl_lut[ 2] = 7'd40; ksl_lut[ 3] = 7'd45; 64 | ksl_lut[ 4] = 7'd48; ksl_lut[ 5] = 7'd51; ksl_lut[ 6] = 7'd53; ksl_lut[ 7] = 7'd55; 65 | ksl_lut[ 8] = 7'd56; ksl_lut[ 9] = 7'd58; ksl_lut[10] = 7'd59; ksl_lut[11] = 7'd60; 66 | ksl_lut[12] = 7'd61; ksl_lut[13] = 7'd62; ksl_lut[14] = 7'd63; ksl_lut[15] = 7'd64; 67 | end 68 | 69 | endmodule -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_eg_pure.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 17-6-2020 19 | 20 | */ 21 | 22 | module jtopl_eg_pure( 23 | input attack, 24 | input step, 25 | input [ 5:1] rate, 26 | input [ 9:0] eg_in, 27 | input sum_up, 28 | output reg [9:0] eg_pure 29 | ); 30 | 31 | reg [ 3:0] dr_sum; 32 | reg [ 9:0] dr_adj; 33 | reg [10:0] dr_result; 34 | 35 | always @(*) begin : dr_calculation 36 | case( rate[5:2] ) 37 | 4'b1100: dr_sum = 4'h2; // 12 38 | 4'b1101: dr_sum = 4'h4; // 13 39 | 4'b1110: dr_sum = 4'h8; // 14 40 | 4'b1111: dr_sum = 4'hf;// 15 41 | default: dr_sum = { 2'b0, step, 1'b0 }; 42 | endcase 43 | // Decay rate attenuation is multiplied by 4 for SSG operation 44 | dr_adj = {6'd0, dr_sum}; 45 | dr_result = dr_adj + eg_in; 46 | end 47 | 48 | reg [ 7:0] ar_sum0; 49 | reg [ 8:0] ar_sum1; 50 | reg [10:0] ar_result; 51 | reg [ 9:0] ar_sum; 52 | 53 | always @(*) begin : ar_calculation 54 | casez( rate[5:2] ) 55 | default: ar_sum0 = {2'd0, eg_in[9:4]}; 56 | 4'b1011, 4'b1100: ar_sum0 = {1'd0, eg_in[9:3]}; // 'hb 57 | // 4'b1101: ar_sum0 = {1'd0, eg_in[9:3]}; // 'hd 58 | // 4'b111?: ar_sum0 = eg_in[9:2]; // 'he/f 59 | 4'b1101, 4'b111?: ar_sum0 = eg_in[9:2]; // 'he/f 60 | endcase 61 | ar_sum1 = ar_sum0+9'd1; 62 | if( rate[5:2] == 4'he ) 63 | ar_sum = { ar_sum1, 1'b0 }; 64 | else if( rate[5:2] > 4'hb ) 65 | ar_sum = step ? { ar_sum1, 1'b0 } : { 1'b0, ar_sum1 }; // adds ar_sum1*3/2 max 66 | // else if( rate[5:2] == 4'hb ) 67 | // ar_sum = step ? { ar_sum1, 1'b0 } : 10'd0; // adds ar_sum1 max 68 | else 69 | ar_sum = step ? { 1'b0, ar_sum1 } : 10'd0; // adds ar_sum1/2 max 70 | ar_result = eg_in-ar_sum; 71 | end 72 | 73 | /////////////////////////////////////////////////////////// 74 | // rate not used below this point 75 | reg [9:0] eg_pre_fastar; // pre fast attack rate 76 | always @(*) begin 77 | if(sum_up) begin 78 | if( attack ) 79 | eg_pre_fastar = ar_result[10] ? 10'd0: ar_result[9:0]; 80 | else 81 | eg_pre_fastar = dr_result[10] ? 10'h3FF : dr_result[9:0]; 82 | end 83 | else eg_pre_fastar = eg_in; 84 | eg_pure = (attack&rate[5:1]==5'h1F) ? 10'd0 : eg_pre_fastar; 85 | end 86 | 87 | endmodule -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_eg_step.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 17-6-2020 19 | 20 | */ 21 | 22 | module jtopl_eg_step( 23 | input attack, 24 | input [ 4:0] base_rate, 25 | input [ 3:0] keycode, 26 | input [14:0] eg_cnt, 27 | input cnt_in, 28 | input ksr, 29 | output cnt_lsb, 30 | output reg step, 31 | output reg [ 5:0] rate, 32 | output reg sum_up 33 | ); 34 | 35 | reg [6:0] pre_rate; 36 | 37 | always @(*) begin : pre_rate_calc 38 | if( base_rate == 5'd0 ) 39 | pre_rate = 7'd0; 40 | else 41 | pre_rate = { 1'b0, base_rate, 1'b0 } + // base_rate LSB is always zero except for RR 42 | ({ 3'b0, keycode } >> (ksr ? 1 : 3)); 43 | end 44 | 45 | always @(*) 46 | rate = pre_rate>=7'b1111_00 ? 6'b1111_11 : pre_rate[5:0]; 47 | 48 | reg [2:0] cnt; 49 | 50 | reg [4:0] mux_sel; 51 | always @(*) begin 52 | mux_sel = attack ? (rate[5:2]+4'd1): {1'b0,rate[5:2]}; 53 | end 54 | 55 | always @(*) 56 | case( mux_sel ) 57 | 5'h0: cnt = eg_cnt[13:11]; 58 | 5'h1: cnt = eg_cnt[12:10]; 59 | 5'h2: cnt = eg_cnt[11: 9]; 60 | 5'h3: cnt = eg_cnt[10: 8]; 61 | 5'h4: cnt = eg_cnt[ 9: 7]; 62 | 5'h5: cnt = eg_cnt[ 8: 6]; 63 | 5'h6: cnt = eg_cnt[ 7: 5]; 64 | 5'h7: cnt = eg_cnt[ 6: 4]; 65 | 5'h8: cnt = eg_cnt[ 5: 3]; 66 | 5'h9: cnt = eg_cnt[ 4: 2]; 67 | 5'ha: cnt = eg_cnt[ 3: 1]; 68 | default: cnt = eg_cnt[ 2: 0]; 69 | endcase 70 | 71 | //////////////////////////////// 72 | reg [7:0] step_idx; 73 | 74 | always @(*) begin : rate_step 75 | if( rate[5:4]==2'b11 ) begin // 0 means 1x, 1 means 2x 76 | if( rate[5:2]==4'hf && attack) 77 | step_idx = 8'b11111111; // Maximum attack speed, rates 60&61 78 | else 79 | case( rate[1:0] ) 80 | 2'd0: step_idx = 8'b00000000; 81 | 2'd1: step_idx = 8'b10001000; // 2 82 | 2'd2: step_idx = 8'b10101010; // 4 83 | 2'd3: step_idx = 8'b11101110; // 6 84 | endcase 85 | end 86 | else begin 87 | if( rate[5:2]==4'd0 && !attack) 88 | step_idx = 8'b11111110; // limit slowest decay rate 89 | else 90 | case( rate[1:0] ) 91 | 2'd0: step_idx = 8'b10101010; // 4 92 | 2'd1: step_idx = 8'b11101010; // 5 93 | 2'd2: step_idx = 8'b11101110; // 6 94 | 2'd3: step_idx = 8'b11111110; // 7 95 | endcase 96 | end 97 | // a rate of zero keeps the level still 98 | step = rate[5:1]==5'd0 ? 1'b0 : step_idx[ cnt ]; 99 | end 100 | 101 | assign cnt_lsb = cnt[0]; 102 | always @(*) begin 103 | sum_up = cnt[0] != cnt_in; 104 | end 105 | 106 | endmodule // eg_step -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_lfo.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 21-6-2020 19 | */ 20 | 21 | // Follows OPLL Reverse Engineering from Nuked 22 | // https://github.com/nukeykt/Nuked-OPLL 23 | 24 | // The AM logic renders a triangular waveform. The logic for it is rather 25 | // obscure, but apparently that's how the original was done 26 | 27 | module jtopl_lfo( 28 | input rst, 29 | input clk, 30 | input cenop, 31 | input [17:0] slot, 32 | output [ 2:0] vib_cnt, 33 | output reg [ 3:0] trem 34 | ); 35 | 36 | parameter [6:0] LIM=7'd60; 37 | 38 | reg [12:0] cnt; 39 | reg am_inc, am_incen, am_dir, am_step; 40 | reg [ 1:0] am_bit; 41 | reg am_carry; 42 | reg [ 8:0] am_cnt; 43 | 44 | wire [12:0] next = cnt+1'b1; 45 | 46 | assign vib_cnt = cnt[12:10]; 47 | 48 | always @(*) begin 49 | am_inc = (slot[0] | am_dir ) & am_step & am_incen; 50 | am_bit = {1'b0, am_cnt[0]} + {1'b0, am_inc} + {1'b0, am_carry & am_incen}; 51 | end 52 | 53 | always @(posedge clk) begin 54 | if( rst ) begin 55 | cnt <= 13'd0; 56 | am_incen <= 1; 57 | am_dir <= 0; 58 | am_carry <= 0; 59 | am_cnt <= 9'd0; 60 | am_step <= 0; 61 | end else if( cenop ) begin 62 | if( slot[17] ) begin 63 | cnt <= next; 64 | am_step <= &next[5:0]; 65 | am_incen <= 1; 66 | end 67 | else if(slot[8]) am_incen <= 0; 68 | am_cnt <= { am_bit[0], am_cnt[8:1] }; 69 | am_carry <= am_bit[1]; 70 | if( slot[0] ) begin 71 | if( am_dir && am_cnt[6:0]==7'd0 ) am_dir <= 0; 72 | else 73 | if( !am_dir && ( (am_cnt[6:0]&7'h69) == 7'h69) ) am_dir <= 1; 74 | end 75 | // output 76 | if( slot[0] ) trem <= am_cnt[6:3]; 77 | end 78 | end 79 | 80 | endmodule 81 | -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_noise.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 24-6-2020 19 | 20 | */ 21 | 22 | // Following research by Andete in 23 | // https://github.com/andete/ym2413 24 | // This has been research for the YM2413 (OPLL) 25 | // I assume other OPL chips use the same one 26 | 27 | module jtopl_noise( 28 | input rst, // rst should be at least 6 clk&cen cycles long 29 | input clk, // CPU clock 30 | input cen, // optional clock enable, it not needed leave as 1'b1 31 | output noise 32 | ); 33 | 34 | reg [22:0] poly; 35 | reg nbit; 36 | 37 | assign noise = poly[22] ^ poly[9] ^ poly[8] ^ poly[0]; 38 | 39 | always @(posedge clk, posedge rst) begin 40 | if( rst ) 41 | poly <= 1; 42 | else if(cen) begin 43 | poly <= poly==0 ? 23'd1 : { poly[21:0], noise }; 44 | end 45 | end 46 | 47 | endmodule -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_pg.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 13-6-2020 19 | 20 | */ 21 | 22 | module jtopl_pg( 23 | input rst, 24 | input clk, 25 | input cenop, 26 | input [17:0] slot, 27 | input rhy_en, 28 | // Channel frequency 29 | input [ 9:0] fnum_I, 30 | input [ 2:0] block_I, 31 | // Operator multiplying 32 | input [ 3:0] mul_II, 33 | // phase modulation from LFO (vibrato at 6.4Hz) 34 | input [ 2:0] vib_cnt, 35 | input vib_dep, 36 | input viben_I, 37 | // phase operation 38 | input pg_rst_II, 39 | 40 | output reg [ 3:0] keycode_II, 41 | output [ 9:0] phase_IV 42 | ); 43 | 44 | parameter CH=9; 45 | 46 | wire [ 3:0] keycode_I; 47 | wire [16:0] phinc_I; 48 | reg [16:0] phinc_II; 49 | wire [18:0] phase_drop, phase_in; 50 | wire [ 9:0] phase_II; 51 | wire noise; 52 | reg [ 9:0] hh, tc; 53 | reg rm_xor; 54 | wire hh_en, sd_en, tc_en; 55 | 56 | always @(posedge clk) if(cenop) begin 57 | keycode_II <= keycode_I; 58 | phinc_II <= phinc_I; 59 | end 60 | 61 | // Rhythm phase 62 | always @(posedge clk, posedge rst) begin 63 | if( rst ) begin 64 | hh <= 10'd0; 65 | tc <= 10'd0; 66 | end else begin 67 | if( slot[13] ) hh <= phase_drop[18:9]; 68 | if( slot[17] ) tc <= phase_drop[18:9]; 69 | rm_xor <= (hh[2]^hh[7]) | (hh[3]^tc[5]) | (tc[3]^tc[5]); 70 | end 71 | end 72 | 73 | assign hh_en = rhy_en & slot[14]; // 13+1 74 | assign sd_en = rhy_en & slot[17]; // 16+1 75 | assign tc_en = rhy_en & slot[ 0]; // (17+1)%18 76 | 77 | jtopl_noise u_noise( 78 | .clk ( clk ), 79 | .cen ( cenop ), 80 | .rst ( rst ), 81 | .noise ( noise ) 82 | ); 83 | 84 | jtopl_pg_comb u_comb( 85 | .block ( block_I ), 86 | .fnum ( fnum_I ), 87 | // Phase Modulation 88 | .vib_cnt ( vib_cnt ), 89 | .vib_dep ( vib_dep ), 90 | .viben ( viben_I ), 91 | 92 | .keycode ( keycode_I ), 93 | // Phase increment 94 | .phinc_out ( phinc_I ), 95 | // Phase add 96 | .mul ( mul_II ), 97 | .phase_in ( phase_drop ), 98 | .pg_rst ( pg_rst_II ), 99 | .phinc_in ( phinc_II ), 100 | // Rhythm 101 | .hh_en ( hh_en ), 102 | .sd_en ( sd_en ), 103 | .tc_en ( tc_en ), 104 | .rm_xor ( rm_xor ), 105 | .noise ( noise ), 106 | .hh ( hh ), 107 | 108 | .phase_out ( phase_in ), 109 | .phase_op ( phase_II ) 110 | ); 111 | 112 | jtopl_sh_rst #( .width(19), .stages(2*CH) ) u_phsh( 113 | .clk ( clk ), 114 | .cen ( cenop ), 115 | .rst ( rst ), 116 | .din ( phase_in ), 117 | .drop ( phase_drop) 118 | ); 119 | 120 | jtopl_sh_rst #( .width(10), .stages(2) ) u_pad( 121 | .clk ( clk ), 122 | .cen ( cenop ), 123 | .rst ( rst ), 124 | .din ( phase_II ), 125 | .drop ( phase_IV ) 126 | ); 127 | 128 | endmodule 129 | 130 | -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_pg_comb.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 13-6-2020 19 | 20 | */ 21 | 22 | module jtopl_pg_comb ( 23 | input [ 2:0] block, 24 | input [ 9:0] fnum, 25 | // Phase Modulation 26 | input [ 2:0] vib_cnt, 27 | input vib_dep, 28 | input viben, 29 | 30 | output [ 3:0] keycode, 31 | // Phase increment 32 | output [16:0] phinc_out, 33 | // Phase add 34 | input [ 3:0] mul, 35 | input [18:0] phase_in, 36 | input pg_rst, 37 | // input signed [7:0] pm_in, 38 | input [16:0] phinc_in, 39 | // Rhythm 40 | input noise, 41 | input [ 9:0] hh, 42 | input hh_en, 43 | input tc_en, 44 | input sd_en, 45 | input rm_xor, 46 | 47 | output [18:0] phase_out, 48 | output [ 9:0] phase_op 49 | ); 50 | 51 | wire signed [3:0] pm_offset; 52 | wire [9:0] phase_pre; 53 | 54 | assign keycode = { block, fnum[9] }; 55 | 56 | /* pm and pg_inc operate in parallel */ 57 | jtopl_pm u_pm( 58 | .vib_cnt ( vib_cnt ), 59 | .fnum ( fnum ), 60 | .vib_dep ( vib_dep ), 61 | .viben ( viben ), 62 | .pm_offset ( pm_offset ) 63 | ); 64 | 65 | jtopl_pg_inc u_inc( 66 | .block ( block ), 67 | .fnum ( fnum ), 68 | .pm_offset ( pm_offset ), 69 | .phinc_pure ( phinc_out ) 70 | ); 71 | 72 | // pg_sum uses the output from the previous blocks 73 | 74 | jtopl_pg_sum u_sum( 75 | .mul ( mul ), 76 | .phase_in ( phase_in ), 77 | .pg_rst ( pg_rst ), 78 | .phinc_pure ( phinc_in ), 79 | .phase_out ( phase_out ), 80 | .phase_op ( phase_pre ) 81 | ); 82 | 83 | jtopl_pg_rhy u_rhy( 84 | .phase_pre ( phase_pre ), 85 | // Rhythm 86 | .noise ( noise ), 87 | .hh ( hh ), 88 | .hh_en ( hh_en ), 89 | .tc_en ( tc_en ), 90 | .sd_en ( sd_en ), 91 | .rm_xor ( rm_xor ), 92 | .phase_op ( phase_op ) 93 | ); 94 | 95 | endmodule // jtopl_pg_comb -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_pg_inc.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 13-6-2020 19 | 20 | */ 21 | 22 | module jtopl_pg_inc ( 23 | input [ 2:0] block, 24 | input [ 9:0] fnum, 25 | input signed [ 3:0] pm_offset, 26 | output reg [16:0] phinc_pure 27 | ); 28 | 29 | reg [16:0] freq; 30 | 31 | always @(*) begin 32 | freq = { 7'd0, fnum } + { {13{pm_offset[3]}}, pm_offset }; 33 | // Add PM here 34 | freq = freq << block; 35 | phinc_pure = freq >> 1; 36 | end 37 | 38 | endmodule // jtopl_pg_inc -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_pg_rhy.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 25-6-2020 19 | 20 | */ 21 | 22 | module jtopl_pg_rhy ( 23 | input [ 9:0] phase_pre, 24 | // Rhythm 25 | input noise, 26 | input [ 9:0] hh, 27 | input hh_en, 28 | input tc_en, 29 | input sd_en, 30 | input rm_xor, 31 | output reg [ 9:0] phase_op 32 | ); 33 | 34 | always @(*) begin 35 | if( hh_en ) begin 36 | phase_op = {rm_xor, 9'd0 }; 37 | if( rm_xor ^ noise ) 38 | phase_op = phase_op | 10'hd0; 39 | else 40 | phase_op = phase_op | 10'h34; 41 | end else if( sd_en ) begin 42 | phase_op = { hh[8], hh[8]^noise, 8'd0 }; 43 | end else if( tc_en ) begin 44 | phase_op = { rm_xor, 9'h80 }; 45 | end else 46 | phase_op = phase_pre; 47 | end 48 | 49 | endmodule // jtopl_pg_sum -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_pg_sum.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 13-6-2020 19 | 20 | */ 21 | 22 | // Original hardware uses an adder to do the multiplication 23 | // but I think it will take less resources of the FPGA to 24 | // use a real multiplier instead 25 | 26 | module jtopl_pg_sum ( 27 | input [ 3:0] mul, 28 | input [18:0] phase_in, 29 | input pg_rst, 30 | input [16:0] phinc_pure, 31 | 32 | output reg [18:0] phase_out, 33 | output reg [ 9:0] phase_op 34 | ); 35 | 36 | reg [21:0] phinc_mul; 37 | reg [ 4:0] factor[0:15]; 38 | 39 | always @(*) begin 40 | phinc_mul = { 5'b0, phinc_pure} * factor[mul]; 41 | phase_out = pg_rst ? 'd0 : (phase_in + phinc_mul[19:1]); 42 | phase_op = phase_out[18:9]; 43 | end 44 | 45 | initial begin 46 | factor[ 0] = 5'd01; factor[ 1] = 5'd02; factor[ 2] = 5'd04; factor[ 3] = 5'd06; 47 | factor[ 4] = 5'd08; factor[ 5] = 5'd10; factor[ 6] = 5'd12; factor[ 7] = 5'd14; 48 | factor[ 8] = 5'd16; factor[ 9] = 5'd18; factor[10] = 5'd20; factor[11] = 5'd20; 49 | factor[12] = 5'd24; factor[13] = 5'd24; factor[14] = 5'd30; factor[15] = 5'd30; 50 | end 51 | 52 | endmodule // jtopl_pg_sum -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_pm.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 21-6-2020 19 | */ 20 | 21 | // Based on Nuked's work on OPLL and OPL3 22 | 23 | module jtopl_pm ( 24 | input [ 2:0] vib_cnt, 25 | input [ 9:0] fnum, 26 | input vib_dep, 27 | input viben, 28 | output reg [ 3:0] pm_offset 29 | ); 30 | 31 | reg [2:0] range; 32 | 33 | always @(*) begin 34 | if( vib_cnt[1:0]==2'b00 ) 35 | range = 3'd0; 36 | else begin 37 | range = fnum[9:7]>>vib_cnt[0]; 38 | if(!vib_dep) range = range>>1; 39 | end 40 | if( vib_cnt[2] ) 41 | pm_offset = ~{1'b0, range } + 4'd1; 42 | else 43 | pm_offset = {1'b0, range }; 44 | if(!viben) pm_offset = 4'd0; 45 | end 46 | 47 | endmodule 48 | -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_reg_ch.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL 2 | 3 | JTOPL program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 28-5-2022 19 | 20 | */ 21 | 22 | module jtopl_reg_ch#( parameter 23 | CHCSRW = 10 24 | ) ( 25 | input rst, 26 | input clk, 27 | input cen, 28 | input zero, 29 | input rhy_en, 30 | input [4:0] rhy_kon, 31 | input [17:0] slot, 32 | 33 | input [1:0] group, 34 | input [CHCSRW-1:0] chcfg_inmux, 35 | 36 | output reg [CHCSRW-1:0] chcfg, 37 | output reg rhy_oen, // high for rhythm operators if rhy_en is set 38 | output rhyon_csr 39 | ); 40 | 41 | // Rhythm key-on CSR 42 | localparam BD=4, SD=3, TOM=2, TC=1, HH=0; 43 | 44 | reg [CHCSRW-1:0] chcfg0_in, chcfg1_in, chcfg2_in; 45 | wire [CHCSRW-1:0] chcfg0_out, chcfg1_out, chcfg2_out; 46 | 47 | reg [5:0] rhy_csr; 48 | 49 | assign rhyon_csr = rhy_csr[5]; 50 | 51 | always @(*) begin 52 | case( group ) 53 | default: chcfg = chcfg0_out; 54 | 2'd1: chcfg = chcfg1_out; 55 | 2'd2: chcfg = chcfg2_out; 56 | endcase 57 | chcfg0_in = group==2'b00 ? chcfg_inmux : chcfg0_out; 58 | chcfg1_in = group==2'b01 ? chcfg_inmux : chcfg1_out; 59 | chcfg2_in = group==2'b10 ? chcfg_inmux : chcfg2_out; 60 | end 61 | 62 | `ifdef SIMULATION 63 | reg [CHCSRW-1:0] chsnap0, chsnap1,chsnap2; 64 | 65 | always @(posedge clk) if(zero) begin 66 | chsnap0 <= chcfg0_out; 67 | chsnap1 <= chcfg1_out; 68 | chsnap2 <= chcfg2_out; 69 | end 70 | `endif 71 | 72 | always @(posedge clk, posedge rst) begin 73 | if( rst ) begin 74 | rhy_csr <= 6'd0; 75 | rhy_oen <= 0; 76 | end else if(cen) begin 77 | if(slot[11]) rhy_oen <= rhy_en; 78 | if(slot[17]) begin 79 | rhy_csr <= { rhy_kon[BD], rhy_kon[HH], rhy_kon[TOM], 80 | rhy_kon[BD], rhy_kon[SD], rhy_kon[TC] }; 81 | rhy_oen <= 0; 82 | end else 83 | rhy_csr <= { rhy_csr[4:0], rhy_csr[5] }; 84 | end 85 | end 86 | 87 | jtopl_sh_rst #(.width(CHCSRW),.stages(3)) u_group0( 88 | .clk ( clk ), 89 | .cen ( cen ), 90 | .rst ( rst ), 91 | .din ( chcfg0_in ), 92 | .drop ( chcfg0_out ) 93 | ); 94 | 95 | jtopl_sh_rst #(.width(CHCSRW),.stages(3)) u_group1( 96 | .clk ( clk ), 97 | .cen ( cen ), 98 | .rst ( rst ), 99 | .din ( chcfg1_in ), 100 | .drop ( chcfg1_out ) 101 | ); 102 | 103 | jtopl_sh_rst #(.width(CHCSRW),.stages(3)) u_group2( 104 | .clk ( clk ), 105 | .cen ( cen ), 106 | .rst ( rst ), 107 | .din ( chcfg2_in ), 108 | .drop ( chcfg2_out ) 109 | ); 110 | 111 | endmodule -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_sh.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 19-6-2020 19 | */ 20 | 21 | // stages must be greater than 2 22 | module jtopl_sh #(parameter width=5, stages=24 ) 23 | ( 24 | input clk, 25 | input cen, 26 | input [width-1:0] din, 27 | output [width-1:0] drop 28 | ); 29 | 30 | reg [stages-1:0] bits[width-1:0]; 31 | 32 | genvar i; 33 | generate 34 | for (i=0; i < width; i=i+1) begin: bit_shifter 35 | always @(posedge clk) if(cen) begin 36 | bits[i] <= {bits[i][stages-2:0], din[i]}; 37 | end 38 | assign drop[i] = bits[i][stages-1]; 39 | end 40 | endgenerate 41 | 42 | endmodule 43 | -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_sh_rst.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 13-6-2020 19 | */ 20 | 21 | // stages must be greater than 2 22 | module jtopl_sh_rst #(parameter width=5, stages=18, rstval=1'b0 ) 23 | ( 24 | input rst, 25 | input clk, 26 | input cen, 27 | input [width-1:0] din, 28 | output [width-1:0] drop 29 | ); 30 | 31 | reg [stages-1:0] bits[width-1:0]; 32 | 33 | genvar i; 34 | integer k; 35 | generate 36 | initial 37 | for (k=0; k < width; k=k+1) begin 38 | bits[k] = { stages{rstval}}; 39 | end 40 | endgenerate 41 | 42 | generate 43 | for (i=0; i < width; i=i+1) begin: bit_shifter 44 | always @(posedge clk, posedge rst) 45 | if( rst ) begin 46 | bits[i] <= {stages{rstval}}; 47 | end else if(cen) begin 48 | bits[i] <= {bits[i][stages-2:0], din[i]}; 49 | end 50 | assign drop[i] = bits[i][stages-1]; 51 | end 52 | endgenerate 53 | 54 | endmodule 55 | -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_single_acc.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | 4 | JTOPL program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | 9 | JTOPL program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with JTOPL. If not, see . 16 | 17 | Author: Jose Tejada Gomez. Twitter: @topapate 18 | Version: 1.0 19 | Date: 20-6-2020 20 | 21 | */ 22 | 23 | // Accumulates an arbitrary number of inputs with saturation 24 | // restart the sum when input "zero" is high 25 | 26 | module jtopl_single_acc #(parameter 27 | INW=13, // input data width 28 | OUTW=16 // output data width 29 | )( 30 | input clk, 31 | input cenop, 32 | input [INW-1:0] op_result, 33 | input sum_en, 34 | input zero, 35 | output reg [OUTW-1:0] snd 36 | ); 37 | 38 | // for full resolution use INW=14, OUTW=16 39 | // for cut down resolution use INW=9, OUTW=12 40 | // OUTW-INW should be > 0 41 | 42 | reg signed [OUTW-1:0] next, acc, current; 43 | reg overflow; 44 | 45 | wire [OUTW-1:0] plus_inf = { 1'b0, {(OUTW-1){1'b1}} }; // maximum positive value 46 | wire [OUTW-1:0] minus_inf = { 1'b1, {(OUTW-1){1'b0}} }; // minimum negative value 47 | 48 | always @(*) begin 49 | current = sum_en ? { {(OUTW-INW){op_result[INW-1]}}, op_result } : {OUTW{1'b0}}; 50 | next = zero ? current : current + acc; 51 | overflow = !zero && 52 | (current[OUTW-1] == acc[OUTW-1]) && 53 | (acc[OUTW-1]!=next[OUTW-1]); 54 | end 55 | 56 | always @(posedge clk) if( cenop ) begin 57 | acc <= overflow ? (acc[OUTW-1] ? minus_inf : plus_inf) : next; 58 | if(zero) snd <= acc; 59 | end 60 | 61 | endmodule -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_slot_cnt.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL 2 | 3 | JTOPL program is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 13-6-2020 19 | 20 | */ 21 | 22 | module jtopl_slot_cnt( 23 | input rst, 24 | input clk, 25 | input cen, 26 | 27 | // Pipeline order 28 | output zero, 29 | output reg [ 1:0] group, 30 | output reg op, // 0 for modulator operators 31 | output reg [ 2:0] subslot, 32 | output reg [17:0] slot // hot one encoding of active slot 33 | ); 34 | 35 | // Each group contains three channels 36 | // and each subslot contains six operators 37 | wire [2:0] next_sub = subslot==3'd5 ? 3'd0 : (subslot+3'd1); 38 | wire [1:0] next_group = subslot==3'd5 ? (group==2'b10 ? 2'b00 : group+2'b1) : group; 39 | 40 | `ifdef SIMULATION 41 | // These signals need to operate during rst 42 | // initial state is not relevant (or critical) in real life 43 | // but we need a clear value during simulation 44 | initial begin 45 | group = 2'd0; 46 | subslot = 3'd0; 47 | slot = 18'd1; 48 | end 49 | `endif 50 | 51 | assign zero = slot[0]; 52 | 53 | always @(posedge clk) begin : up_counter 54 | if( cen ) begin 55 | { group, subslot } <= { next_group, next_sub }; 56 | if( { next_group, next_sub }==5'd0 ) begin 57 | slot <= 18'd1; 58 | end else begin 59 | slot <= { slot[16:0], 1'b0 }; 60 | end 61 | op <= next_sub >= 3'd3; 62 | end 63 | end 64 | 65 | endmodule -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopl_timers.v: -------------------------------------------------------------------------------- 1 | /* This file is part of JTOPL. 2 | 3 | JTOPL is free software: you can redistribute it and/or modify 4 | it under the terms of the GNU General Public License as published by 5 | the Free Software Foundation, either version 3 of the License, or 6 | (at your option) any later version. 7 | 8 | JTOPL is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | 13 | You should have received a copy of the GNU General Public License 14 | along with JTOPL. If not, see . 15 | 16 | Author: Jose Tejada Gomez. Twitter: @topapate 17 | Version: 1.0 18 | Date: 10-6-2020 19 | 20 | */ 21 | 22 | module jtopl_timers( 23 | input clk, 24 | input rst, 25 | input cenop, 26 | input zero, 27 | input [7:0] value_A, 28 | input [7:0] value_B, 29 | input load_A, 30 | input load_B, 31 | input clr_flag_A, 32 | input clr_flag_B, 33 | output flag_A, 34 | output flag_B, 35 | input flagen_A, 36 | input flagen_B, 37 | output overflow_A, 38 | output irq_n 39 | ); 40 | 41 | wire pre_A, pre_B; 42 | 43 | assign flag_A = pre_A & flagen_A; 44 | assign flag_B = pre_B & flagen_B; 45 | 46 | assign irq_n = ~( flag_A | flag_B ); 47 | 48 | // 1 count per 288 master clock ticks 49 | jtopl_timer #(.MW(2)) timer_A ( 50 | .clk ( clk ), 51 | .rst ( rst ), 52 | .cenop ( cenop ), 53 | .zero ( zero ), 54 | .start_value( value_A ), 55 | .load ( load_A ), 56 | .clr_flag ( clr_flag_A), 57 | .flag ( pre_A ), 58 | .overflow ( overflow_A) 59 | ); 60 | 61 | // 1 count per 288*4 master clock ticks 62 | jtopl_timer #(.MW(4)) timer_B( 63 | .clk ( clk ), 64 | .rst ( rst ), 65 | .cenop ( cenop ), 66 | .zero ( zero ), 67 | .start_value( value_B ), 68 | .load ( load_B ), 69 | .clr_flag ( clr_flag_B), 70 | .flag ( pre_B ), 71 | .overflow ( ) 72 | ); 73 | 74 | endmodule 75 | 76 | module jtopl_timer #(parameter MW=2) ( 77 | input clk, 78 | input rst, 79 | input cenop, 80 | input zero, 81 | input [7:0] start_value, 82 | input load, 83 | input clr_flag, 84 | output reg flag, 85 | output reg overflow 86 | ); 87 | 88 | reg [7:0] cnt, next, init; 89 | reg [MW-1:0] free_cnt, free_next; 90 | reg load_l, free_ov; 91 | 92 | always@(posedge clk) 93 | if( clr_flag || rst) 94 | flag <= 1'b0; 95 | else if(cenop && zero && load && overflow) flag<=1'b1; 96 | 97 | always @(*) begin 98 | {free_ov, free_next} = { 1'b0, free_cnt} + 1'b1; 99 | /* verilator lint_off WIDTH */ 100 | {overflow, next } = {1'b0, cnt}+free_ov; 101 | /* verilator lint_on WIDTH */ 102 | init = start_value; 103 | end 104 | 105 | always @(posedge clk) begin 106 | load_l <= load; 107 | if( (!load_l && load) || rst) begin 108 | cnt <= start_value; 109 | end else if( cenop && zero && load ) begin 110 | cnt <= overflow ? init : next; 111 | end 112 | end 113 | 114 | // Free running counter, resetting 115 | // the value of this part with the load 116 | // event can slow down music, vg Bad Dudes 117 | always @(posedge clk) begin 118 | if( rst ) begin 119 | free_cnt <= 0; 120 | end else if( cenop && zero ) begin 121 | free_cnt <= free_next; 122 | end 123 | end 124 | 125 | endmodule 126 | -------------------------------------------------------------------------------- /verilog/jtopl/hdl/jtopll.yaml: -------------------------------------------------------------------------------- 1 | here: 2 | - jtopll.v 3 | - jtopl.yaml -------------------------------------------------------------------------------- /verilog/jtopl/ver/jtopl_eg/sweep.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This file runs a simulation on the purely combinational logic of the envelope generator. 4 | The simulation is controlled via text files 5 | 6 | The text file is a sequence of write commands that will configure the inputs to the logic 7 | then a wait command will kick the simulation for a given number of clocks 8 | 9 | The LFO is always running. The simulations show that SSG is well implemented and that 10 | the circuit behaves within bounds for extreme cases 11 | 12 | The core logic of the ASDR envelope is simulated on separate test bench eg2. 13 | 14 | Arguments: 15 | -w write VCD (always enabled, uncomment to evaluate this argument) 16 | -o path-to-test-file 17 | 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include "Vsweep.h" 25 | #include "verilated_vcd_c.h" 26 | 27 | using namespace std; 28 | 29 | 30 | vluint64_t main_time = 0; // Current simulation time 31 | const vluint64_t HALFPERIOD=133; // 3.57MHz (133ns * 2) 32 | Vsweep top; 33 | VerilatedVcdC* vcd; 34 | bool keep = true; 35 | 36 | void clock(int n) { 37 | while( n-->0 ) { 38 | top.eval(); 39 | if(keep) vcd->dump(main_time); 40 | 41 | main_time += HALFPERIOD; 42 | top.clk=1; 43 | top.eval(); 44 | if(keep) vcd->dump(main_time); 45 | 46 | main_time += HALFPERIOD; 47 | top.clk=0; 48 | } 49 | } 50 | 51 | double sc_time_stamp () { // Called by $time in Verilog 52 | return main_time; 53 | } 54 | 55 | void reset() { 56 | top.rst = 1; 57 | top.keyon_I = 0; 58 | clock(18*2); 59 | top.rst = 0; 60 | } 61 | 62 | void attack_sweep() { 63 | // YM2413 64 | // float atime[] = { 0.1, 1738,863,432,216,108,54,27,13.52,6.76,3.38,1.69,0.84,0.5,0.28,0.1 }; 65 | // YM3812 66 | float atime[] = { 0.1, 2826, 1413, 706, 353, 176, 88, 44, 22, 11, 5.52, 2.76, 1.40, 0.7, 0.38,0.1 }; 67 | 68 | top.ksr_II=1; 69 | for( top.arate_I=3; top.arate_I<15; top.arate_I++ ) 70 | for( top.block_I=0; top.block_I<4; top.block_I++ ) 71 | { 72 | reset(); 73 | top.keyon_I = 1; 74 | vluint64_t t0=main_time; 75 | int limit=1'000'000; 76 | if( top.arate_I!=0) { 77 | while( (int)top.eg_V!=0 && --limit ) { 78 | clock( 10 ); 79 | } 80 | } 81 | if( limit==0 ) { 82 | cout << "ARATE " << hex << (int)top.arate_I << dec << " timeout " << "(" << (int) top.eg_V << ")\n"; 83 | if( top.arate_I>5 ) break; // do not continue 84 | } 85 | if( (int)top.eg_V==0 ) { 86 | float delta=(float)main_time-t0; 87 | delta /= 1e6; 88 | float err = (delta-atime[top.arate_I])/atime[top.arate_I]*100.0; 89 | printf("ARATE %X (block %d) %6.2f ms (%4.1f %%)\n", 90 | top.arate_I, top.block_I, delta, err ); 91 | } 92 | } 93 | } 94 | 95 | void decay_sweep() { 96 | // YM3812 97 | float atime[] = { 0.1, 39280,19640,9820,4910,2455,1227,613.7,306.8,153.44,76.72,38.36,19.20,9.60,4.80,2.40 }; 98 | 99 | top.arate_I=15; 100 | top.sl_I=15; 101 | for( top.drate_I= keep ? 5 : 1; top.drate_I<16; top.drate_I++ ) { 102 | reset(); 103 | top.keyon_I = 1; 104 | clock( 100 ); 105 | vluint64_t t0=main_time; 106 | int limit=1'000'000; 107 | if( top.drate_I!=0) { 108 | while( (int)top.eg_V<0x3e0 && --limit ) { 109 | clock( 10 ); 110 | } 111 | } 112 | if( limit==0 ) { 113 | cout << "DRATE " << hex << (int)top.drate_I << dec << " timeout " << "(" << (int) top.eg_V << ")\n"; 114 | if( top.drate_I>5 ) break; // do not continue 115 | } 116 | if( (int)top.eg_V>=0x3e0 ) { 117 | float delta=(float)main_time-t0; 118 | delta /= 1e6; 119 | float err = (delta-atime[top.drate_I])/atime[top.drate_I]*100.0; 120 | printf("DRATE %X (block %d) %6.2f ms (%4.1f %%)\n", 121 | top.drate_I, top.block_I, delta, err ); 122 | } else { 123 | printf("End not reached\n"); 124 | } 125 | } 126 | } 127 | 128 | int main(int argc, char *argv[]) { 129 | int err_code=0; 130 | vcd = new VerilatedVcdC; 131 | bool trace=true; 132 | 133 | if( trace ) { 134 | Verilated::traceEverOn(true); 135 | top.trace(vcd,99); 136 | vcd->open("test.vcd"); 137 | } 138 | 139 | //attack_sweep(); 140 | decay_sweep(); 141 | 142 | if(trace) vcd->close(); 143 | // VerilatedCov::write("logs/coverage.dat"); 144 | delete vcd; 145 | return err_code; 146 | } 147 | 148 | 149 | void remove_blanks( char*& str ) { 150 | while( *str!=0 && (*str==' ' || *str=='\t') ) str++; 151 | } -------------------------------------------------------------------------------- /verilog/jtopl/ver/jtopl_eg/sweep.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if ! verilator -f sweep.f sweep.cpp --cc --exe --trace --timescale 1ns/1ns > s; then 4 | cat s; rm s 5 | exit $? 6 | fi 7 | 8 | if ! make -j -C obj_dir -f Vsweep.mk Vsweep > s; then 9 | cat s; rm s 10 | exit $? 11 | fi 12 | 13 | if ! obj_dir/Vsweep $*; then 14 | exit $? 15 | fi 16 | # verilator_coverage logs/coverage.dat --annotate coverage 17 | -------------------------------------------------------------------------------- /verilog/jtopl/ver/jtopl_eg/sweep.v: -------------------------------------------------------------------------------- 1 | module test( 2 | input rst, 3 | input clk, 4 | input eg_stop, 5 | // envelope configuration 6 | input en_sus_I, // enable sustain 7 | input [3:0] arate_I, // attack rate 8 | input [3:0] drate_I, // decay rate 9 | input [3:0] rrate_I, // release rate 10 | input [3:0] sl_I, // sustain level 11 | input ksr_II, // key scale 12 | // envelope operation 13 | input keyon_I, 14 | // envelope number 15 | input [9:0] fnum_I, 16 | input [2:0] block_I, 17 | input [3:0] lfo_mod, 18 | input amsen_IV, 19 | input ams_IV, 20 | input [5:0] tl_IV, 21 | input [1:0] ksl_IV, 22 | 23 | output reg [9:0] eg_V, 24 | output reg pg_rst_II 25 | ); 26 | 27 | wire cenop, zero, op; 28 | wire kon = keyon_I;// & zero; 29 | wire [17:0] slot; 30 | wire [ 3:0] keycode_II = { block_I, fnum_I[9] }; 31 | 32 | reg cen=0; 33 | 34 | always @(posedge clk) cen <= ~cen; 35 | 36 | jtopl_div u_div( 37 | .rst ( rst ), 38 | .clk ( clk ), 39 | .cen ( cen ), 40 | .cenop ( cenop ) // clock enable at operator rate 41 | ); 42 | 43 | jtopl_slot_cnt u_slot_cnt( 44 | .rst ( rst ), 45 | .clk ( clk ), 46 | .cen ( cenop ), 47 | 48 | // Pipeline order 49 | .zero ( zero ), 50 | .group ( ), 51 | .op ( op ), // 0 for modulator operators 52 | .subslot( ), 53 | .slot ( slot ) // hot one encoding of active slot 54 | ); 55 | 56 | jtopl_eg uut( 57 | .rst ( rst ), 58 | .clk ( clk ), 59 | // .cen ( cen ),Mas 60 | .cenop ( cenop ), 61 | .zero ( zero ), 62 | .eg_stop ( eg_stop ), 63 | // envelope configuration 64 | .en_sus_I ( en_sus_I ), // enable sustain 65 | .keycode_II ( keycode_II ), 66 | .arate_I ( arate_I ), // attack rate 67 | .drate_I ( drate_I ), // decay rate 68 | .rrate_I ( rrate_I ), // release rate 69 | .sl_I ( sl_I ), // sustain level 70 | .ksr_II ( ksr_II ), // key scale 71 | // envelope operation 72 | .keyon_I ( kon ), 73 | // envelope number 74 | .fnum_I ( fnum_I ), 75 | .block_I ( block_I ), 76 | .lfo_mod ( lfo_mod ), 77 | .amsen_IV ( amsen_IV ), 78 | .ams_IV ( ams_IV ), 79 | .tl_IV ( tl_IV ), 80 | .ksl_IV ( ksl_IV ), 81 | 82 | .eg_V ( eg_V ), 83 | .pg_rst_II ( pg_rst_II ) 84 | ); 85 | 86 | endmodule -------------------------------------------------------------------------------- /verilog/jtopl/ver/jtopl_eg_comb_tb/README: -------------------------------------------------------------------------------- 1 | This file runs a simulation on the purely combinational logic of the envelope generator. 2 | The simulation is controlled via text files 3 | 4 | The text file is a sequence of write commands that will configure the inputs to the logic 5 | then a wait command will kick the simulation for a given number of clocks. Test files 6 | are stored in the tests folder. 7 | 8 | The LFO is always running. The simulations show that SSG is well implemented and that 9 | the circuit behaves within bounds for extreme cases 10 | 11 | The core logic of the ASDR envelope is simulated on separate test bench eg2. 12 | 13 | Arguments: 14 | -w write VCD (always enabled, uncomment to evaluate this argument) 15 | -f path-to-test-file -------------------------------------------------------------------------------- /verilog/jtopl/ver/jtopl_eg_comb_tb/sim.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if ! verilator -f gather.f test.cpp --cc --exe --trace > s; then 4 | cat s; rm s 5 | exit $? 6 | fi 7 | 8 | if ! make -j -C obj_dir -f Vtest.mk Vtest > s; then 9 | cat s; rm s 10 | exit $? 11 | fi 12 | 13 | if ! obj_dir/Vtest $*; then 14 | exit $? 15 | fi 16 | # verilator_coverage logs/coverage.dat --annotate coverage 17 | -------------------------------------------------------------------------------- /verilog/jtopl/ver/jtopl_eg_comb_tb/test.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | This file runs a simulation on the purely combinational logic of the envelope generator. 4 | The simulation is controlled via text files 5 | 6 | The text file is a sequence of write commands that will configure the inputs to the logic 7 | then a wait command will kick the simulation for a given number of clocks 8 | 9 | The LFO is always running. The simulations show that SSG is well implemented and that 10 | the circuit behaves within bounds for extreme cases 11 | 12 | The core logic of the ASDR envelope is simulated on separate test bench eg2. 13 | 14 | Arguments: 15 | -w write VCD (always enabled, uncomment to evaluate this argument) 16 | -o path-to-test-file 17 | 18 | */ 19 | 20 | #include 21 | #include 22 | #include 23 | #include "Vtest.h" 24 | #include "verilated_vcd_c.h" 25 | 26 | using namespace std; 27 | 28 | class Stim { 29 | ifstream file; 30 | int wait_count, line_cnt; 31 | void read_line(); 32 | public: 33 | // inputs 34 | int keyon_now, keyoff_now, state_in, eg_in, arate, drate, rate2, rrate, sl, 35 | keycode, eg_cnt, cnt_in, ksr, en_sus, sum_up_in, 36 | lfo_mod, amsen, ams, tl; 37 | // outputs 38 | int state_next, pg_rst, cnt_lsb, pure_eg_out, eg_out, sum_up_out; 39 | void reset(); 40 | void apply(Vtest* dut); 41 | void get(Vtest* dut); 42 | void next(Vtest* dut); 43 | void open(const char *filename); 44 | bool done() { return file.eof() && wait_count==0; } 45 | Stim() { reset(); } 46 | }; 47 | 48 | vluint64_t main_time = 0; // Current simulation time 49 | 50 | double sc_time_stamp () { // Called by $time in Verilog 51 | return main_time; 52 | } 53 | 54 | int main(int argc, char *argv[]) { 55 | 56 | Vtest* top = new Vtest; 57 | Stim stim; 58 | int err_code=0; 59 | VerilatedVcdC* vcd = new VerilatedVcdC; 60 | bool trace=true; 61 | 62 | for(int k=1; ktrace(vcd,99); 73 | vcd->open("test.vcd"); 74 | } 75 | 76 | // time 0 state: 77 | stim.apply(top); top->eval(); 78 | if(trace) vcd->dump(main_time); 79 | 80 | try{ 81 | do { 82 | stim.next(top); 83 | if(trace) vcd->dump(main_time); 84 | } while( !stim.done() ); 85 | } catch( int ) {} 86 | quit: 87 | if(trace) vcd->close(); 88 | // VerilatedCov::write("logs/coverage.dat"); 89 | delete vcd; 90 | delete top; 91 | return err_code; 92 | } 93 | 94 | 95 | void Stim::reset() { 96 | keyon_now=0, keyoff_now=0, state_in=0, eg_in=0x3ff, arate=0, drate=0, 97 | rrate=0, sl=0, en_sus=0, 98 | keycode=0, eg_cnt=0, cnt_in=0, ksr=0, 99 | lfo_mod=0, amsen=0, ams=0, tl=0; 100 | sum_up_in = 0; 101 | wait_count=0; 102 | } 103 | 104 | void Stim::apply(Vtest* dut) { 105 | dut->keyon_now = keyon_now; 106 | dut->keyoff_now = keyoff_now; 107 | dut->state_in = state_in; 108 | dut->sum_up_in = sum_up_in; 109 | dut->eg_in = eg_in; 110 | dut->arate = arate; 111 | dut->drate = drate; 112 | dut->rrate = rrate; 113 | dut->sl = sl; 114 | dut->en_sus = en_sus; 115 | 116 | dut->keycode = keycode; 117 | dut->eg_cnt = eg_cnt; 118 | dut->cnt_in = cnt_in; 119 | dut->ksr = ksr; 120 | 121 | dut->lfo_mod = lfo_mod; 122 | dut->amsen = amsen; 123 | dut->ams = ams; 124 | dut->tl = tl; 125 | } 126 | 127 | void Stim::get(Vtest* dut) { 128 | state_next = dut->state_next; 129 | pg_rst = dut->pg_rst; 130 | cnt_lsb = dut->cnt_lsb; 131 | pure_eg_out = dut->pure_eg_out; 132 | eg_out = dut->eg_out; 133 | sum_up_out = dut->sum_up_out; 134 | } 135 | 136 | void Stim::next(Vtest* dut) { 137 | read_line(); 138 | apply(dut); 139 | dut->eval(); 140 | main_time+=20000; // zero period=20us = 4*18*1/3.6MHz 141 | get(dut); 142 | state_in = state_next; 143 | eg_in = pure_eg_out; 144 | cnt_in = cnt_lsb; 145 | sum_up_in = sum_up_out; 146 | eg_cnt++; 147 | lfo_mod++; 148 | if( wait_count>0 ) wait_count--; 149 | } 150 | 151 | void Stim::open(const char *filename ) { 152 | line_cnt = 0; 153 | file.open(filename); 154 | } 155 | 156 | void remove_blanks( char*& str ) { 157 | while( *str!=0 && (*str==' ' || *str=='\t') ) str++; 158 | } 159 | 160 | void Stim::read_line() { 161 | while( !file.eof() && file.good() && wait_count==0) { 162 | char line[256]=""; 163 | char *noblanks; 164 | do{ 165 | file.getline(line,128); 166 | line_cnt++; 167 | //cout << line_cnt << '\n'; 168 | noblanks = line; 169 | remove_blanks(noblanks); 170 | } while( (noblanks[0]=='#' || strlen(line)==0) && !file.eof() ); 171 | char cmd[256]; 172 | int value; 173 | if( sscanf( noblanks, "%[a-z_12] = %x", cmd, &value ) != 2 ) { 174 | if( strcmp(cmd,"reset")==0 ) { reset(); continue; } 175 | cout << "ERROR: Incomplete line " << line_cnt << "\n\t" << noblanks << '\n'; 176 | throw 1; 177 | } 178 | while( true ) { 179 | if( strcmp(cmd,"keyon")==0 ) { keyon_now = value; break; } 180 | if( strcmp(cmd,"keyoff")==0 ) { keyoff_now = value; break; } 181 | if( strcmp(cmd,"state")==0 ) { state_in = value; break; } 182 | if( strcmp(cmd,"eg")==0 ) { eg_in = value; break; } 183 | if( strcmp(cmd,"arate")==0 ) { arate = value; break; } 184 | if( strcmp(cmd,"drate")==0 ) { drate = value; break; } 185 | if( strcmp(cmd,"rrate")==0 ) { rrate = value; break; } 186 | if( strcmp(cmd,"sl")==0 ) { sl = value; break; } 187 | if( strcmp(cmd,"keycode")==0) { keycode = value; break; } 188 | if( strcmp(cmd,"eg_cnt")==0 ) { eg_cnt = value; break; } 189 | if( strcmp(cmd,"cnt_in")==0 ) { cnt_in = value; break; } 190 | if( strcmp(cmd,"ksr")==0 ) { ksr = value; break; } 191 | if( strcmp(cmd,"lfo_mod")==0) { lfo_mod = value; break; } 192 | if( strcmp(cmd,"amsen")==0 ) { amsen = value; break; } 193 | if( strcmp(cmd,"ams")==0 ) { ams = value; break; } 194 | if( strcmp(cmd,"tl")==0 ) { tl = value; break; } 195 | if( strcmp(cmd,"wait")==0 ) { wait_count = value; break; } 196 | cout << "ERROR: Unknown command '" << cmd << "'\n"; 197 | throw 2; 198 | } 199 | } 200 | } -------------------------------------------------------------------------------- /verilog/jtopl/ver/jtopl_eg_comb_tb/test.v: -------------------------------------------------------------------------------- 1 | module test( 2 | input keyon_now, 3 | input keyoff_now, 4 | input [ 2:0] state_in, 5 | input [ 9:0] eg_in, 6 | // envelope configuration 7 | input en_sus, // enable sustain 8 | input [ 3:0] arate, // attack rate 9 | input [ 3:0] drate, // decay rate 10 | input [ 3:0] rrate, 11 | input [ 3:0] sl, // sustain level 12 | 13 | output reg [ 2:0] state_next, 14 | output reg pg_rst, 15 | /////////////////////////////////// 16 | // II 17 | input [ 3:0] keycode, 18 | input [14:0] eg_cnt, 19 | input cnt_in, 20 | input ksr, 21 | output cnt_lsb, 22 | output sum_up_out, 23 | /////////////////////////////////// 24 | // III 25 | input sum_up_in, 26 | output reg [ 9:0] pure_eg_out, 27 | /////////////////////////////////// 28 | // IV 29 | input [ 3:0] lfo_mod, 30 | input [ 3:0] fnum, 31 | input [ 2:0] block, 32 | input amsen, 33 | input ams, 34 | input [ 5:0] tl, 35 | input [ 1:0] ksl, 36 | input [ 3:0] final_keycode, 37 | output reg [ 9:0] eg_out 38 | ); 39 | 40 | wire [4:0] base_rate; 41 | wire attack = state_next[0]; 42 | wire step; 43 | wire [5:0] step_rate_out; 44 | 45 | jtopl_eg_comb uut( 46 | .keyon_now ( keyon_now ), 47 | .keyoff_now ( keyoff_now ), 48 | .state_in ( state_in ), 49 | .eg_in ( eg_in ), 50 | // envelope configuration 51 | .en_sus ( en_sus ), 52 | .arate ( arate ), // attack rate 53 | .drate ( drate ), // decay rate 54 | .rrate ( rrate ), 55 | .sl ( sl ), // sustain level 56 | 57 | .base_rate ( base_rate ), 58 | .state_next ( state_next ), 59 | .pg_rst ( pg_rst ), 60 | 61 | // Frequency settings 62 | .fnum ( fnum ), 63 | .block ( block ), 64 | .ksl ( ksl ), 65 | .ksr ( ksr ), 66 | .final_keycode ( final_keycode ), 67 | 68 | /////////////////////////////////// 69 | // II 70 | .step_attack ( attack ), 71 | .step_rate_in ( base_rate ), 72 | .keycode ( keycode ), 73 | .eg_cnt ( eg_cnt ), 74 | .cnt_in ( cnt_in ), 75 | .cnt_lsb ( cnt_lsb ), 76 | .step ( step ), 77 | .step_rate_out ( step_rate_out ), 78 | .sum_up_out ( sum_up_out ), 79 | /////////////////////////////////// 80 | // III 81 | .pure_attack ( attack ), 82 | .pure_step ( step ) , 83 | .pure_rate (step_rate_out[5:1]), 84 | .pure_eg_in ( eg_in ), 85 | .pure_eg_out ( pure_eg_out ), 86 | .sum_up_in ( sum_up_in ), 87 | /////////////////////////////////// 88 | // IV 89 | .lfo_mod ( lfo_mod ), 90 | .amsen ( amsen ), 91 | .ams ( ams ), 92 | .tl ( tl ), 93 | .final_eg_in ( pure_eg_out ), 94 | .final_eg_out ( eg_out ) 95 | ); 96 | 97 | endmodule // test -------------------------------------------------------------------------------- /verilog/jtopl/ver/jtopl_eg_comb_tb/tests/attack.tst: -------------------------------------------------------------------------------- 1 | reset 2 | arate=A 3 | drate=7 4 | rrate=A 5 | sl=6 6 | keycode=0 7 | ksr=1 8 | 9 | keyon=1 10 | wait=1 11 | keyon=0 12 | 13 | wait=2000 14 | 15 | keyoff=1 16 | wait=1 17 | keyoff=0 18 | 19 | wait=2000 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/VGMParser.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __VGMPARSER 2 | #define __VGMPARSER 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | // Do not output to cout because it will interfere with 9 | // signal dumping! 10 | 11 | class RipParser { 12 | public: 13 | enum chip_type { ym2203=1, ym2612=2, ym2610=3, ym2151=4, ym3526=5, ym2413=6, ym3812=7, unknown=0 }; 14 | protected: 15 | int clk_period; // synthesizer clock period 16 | chip_type chip_cfg; 17 | public: 18 | char cmd, val, addr; 19 | uint64_t wait; 20 | virtual void open(const char *filename, int limit=0 )=0; 21 | virtual int parse()=0; 22 | virtual uint64_t length()=0; 23 | virtual ~RipParser() {}; 24 | RipParser(int c) { clk_period = c; } 25 | enum { cmd_error=-2, cmd_finish=-1, cmd_write=0, cmd_wait=1, cmd_psg=2, cmd_nop=3 }; 26 | chip_type chip() { return chip_cfg; } 27 | virtual int period(); 28 | }; 29 | 30 | RipParser* ParserFactory( const char *filename, int clk_period ); 31 | 32 | class VGMParser : public RipParser { 33 | std::ifstream file; 34 | std::ofstream ftrans; // translation to JTT format 35 | float cur_time; // used by ftrans 36 | int totalwait, pending_wait, stream_id; 37 | bool done, stream_notmplemented_info; 38 | void adjust_wait() { 39 | double w=wait; 40 | w /= 44100.0; 41 | w *= 1e9; 42 | wait = (uint64_t)w; 43 | } 44 | void translate_cmd(); 45 | void translate_wait(); 46 | char *stream_data; 47 | uint32_t data_offset, ym_freq; 48 | 49 | // int max_PSG_warning; 50 | public: 51 | void open(const char *filename, int limit=0 ); 52 | int parse(); 53 | uint64_t length(); 54 | int period(); 55 | VGMParser(int c) : RipParser(c) { 56 | stream_data=NULL; stream_id=0; 57 | } 58 | ~VGMParser(); 59 | }; 60 | 61 | class Gym : public RipParser { 62 | std::ifstream file; 63 | int max_PSG_warning; 64 | int count, count_limit; 65 | void adjust_wait() { wait*=100000; wait/=441; } 66 | public: 67 | void open(const char *filename, int limit=0); 68 | int parse(); 69 | uint64_t length() { return 0; /* unknown */ } 70 | Gym(int c) : RipParser(c) {} 71 | }; 72 | 73 | class JTTParser : public RipParser { 74 | std::ifstream file; 75 | int line_cnt; 76 | bool done; 77 | int default_ch; 78 | // int max_PSG_warning; 79 | void remove_blanks( char*& str ); 80 | void parse_chdata(char *txt_arg, int cmd_base); 81 | void parse_opdata(char *txt_arg, int cmd_base); 82 | 83 | std::map op_commands; 84 | std::map ch_commands; 85 | std::map global_commands; 86 | public: 87 | JTTParser(int c); 88 | ~JTTParser(); 89 | void open(const char *filename, int limit=0); 90 | int parse(); 91 | uint64_t length() { return 0; } 92 | int period(); 93 | }; 94 | 95 | #endif -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/WaveWritter.cpp: -------------------------------------------------------------------------------- 1 | #include "WaveWritter.hpp" 2 | #include 3 | #include 4 | 5 | using namespace std; 6 | 7 | void WaveWritter::write( int16_t* lr ) { 8 | fsnd.write( (char*)lr, sizeof(int16_t)*2 ); 9 | if( dump_hex ) { 10 | fhex << hex << lr[0] << '\n'; 11 | fhex << hex << lr[1] << '\n'; 12 | } 13 | } 14 | 15 | void WaveWritter::Constructor( const char *filename, int sample_rate, bool hex ) { 16 | name = filename; 17 | fsnd.open(filename, ios_base::binary); 18 | dump_hex = hex; 19 | if( dump_hex ) { 20 | char *hexname; 21 | hexname = new char[strlen(filename)+1]; 22 | strcpy(hexname,filename); 23 | strcpy( hexname+strlen(filename)-4, ".hex" ); 24 | cerr << "Hex file " << hexname << '\n'; 25 | fhex.open(hexname); 26 | delete[] hexname; 27 | } 28 | // write header 29 | char zero=0; 30 | for( int k=0; k<45; k++ ) fsnd.write( &zero, 1 ); 31 | fsnd.seekp(0); 32 | fsnd.write( "RIFF", 4 ); 33 | fsnd.seekp(8); 34 | fsnd.write( "WAVEfmt ", 8 ); 35 | int32_t number32 = 16; 36 | fsnd.write( (char*)&number32, 4 ); 37 | int16_t number16 = 1; 38 | fsnd.write( (char*) &number16, 2); 39 | number16=2; 40 | fsnd.write( (char*) &number16, 2); 41 | number32 = sample_rate; 42 | fsnd.write( (char*)&number32, 4 ); 43 | number32 = sample_rate*2*2; 44 | fsnd.write( (char*)&number32, 4 ); 45 | number16=2*2; // Block align 46 | fsnd.write( (char*) &number16, 2); 47 | number16=16; 48 | fsnd.write( (char*) &number16, 2); 49 | fsnd.write( "data", 4 ); 50 | fsnd.seekp(44); 51 | } 52 | 53 | WaveWritter::~WaveWritter() { 54 | int32_t number32; 55 | streampos file_length = fsnd.tellp(); 56 | number32 = (int32_t)file_length-8; 57 | fsnd.seekp(4); 58 | fsnd.write( (char*)&number32, 4); 59 | fsnd.seekp(40); 60 | number32 = (int32_t)file_length-44; 61 | fsnd.write( (char*)&number32, 4); 62 | } 63 | -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/WaveWritter.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __WAVEWRITTER_H 2 | #define __WAVEWRITTER_H 3 | 4 | #include 5 | #include 6 | 7 | class WaveWritter { 8 | std::ofstream fsnd, fhex; 9 | std::string name; 10 | bool dump_hex; 11 | void Constructor(const char *filename, int sample_rate, bool hex ); 12 | public: 13 | WaveWritter(const char *filename, int sample_rate, bool hex ) { 14 | Constructor( filename, sample_rate, hex ); 15 | } 16 | WaveWritter(const std::string &filename, int sample_rate, bool hex ) { 17 | Constructor( filename.c_str(), sample_rate, hex ); 18 | } 19 | void write( int16_t *lr ); 20 | ~WaveWritter(); 21 | }; 22 | 23 | #endif -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/feature.hpp: -------------------------------------------------------------------------------- 1 | #ifndef __FEATUREUSE_H 2 | #define __FEATUREUSE_H 3 | 4 | #include 5 | #include 6 | 7 | class FeatureUse { 8 | bool used; 9 | char _name[11]; 10 | char _regmask, _enable_mask, _regbase; 11 | bool (*check_use)(char); 12 | public: 13 | FeatureUse( const char *name, char regmask, char regbase, char enable_mask, 14 | bool (*check)(char) ); 15 | bool is_used() const { return used; } 16 | const char *name() const { return _name; } 17 | void check( char cmd, char val ); 18 | }; 19 | 20 | FeatureUse::FeatureUse( const char *name, char regmask, char regbase, 21 | char enable_mask, bool (*check)(char) ) { 22 | strncpy( _name, name, 10 ); 23 | _name[10] = 0; 24 | _regmask = regmask; 25 | _regbase = regbase; 26 | _enable_mask = enable_mask; 27 | used=false; 28 | check_use = check; 29 | } 30 | 31 | void FeatureUse::check( char cmd, char val ) { 32 | cmd &= _regmask; 33 | if( cmd == _regbase ) { 34 | val &= _enable_mask; 35 | used=(*check_use)(val); 36 | } 37 | // std::cout << std::hex << ((int)cmd&0xff) << " vs " << ((int)_regbase&0xff) << '\n'; 38 | } 39 | 40 | #endif -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/mmr.lut: -------------------------------------------------------------------------------- 1 | 00 Or0 mod 2 | 01 Or0 car 3 | 02 Or1 mod 4 | 03 Or1 car 5 | 04 Or2 mod 6 | 05 Or2 car 7 | 06 Or3 mod 8 | 07 Or3 car 9 | 0E Rythm 10 | 0F Test 11 | 10 FLSB-0 12 | 11 FLSB-1 13 | 12 FLSB-2 14 | 13 FLSB-3 15 | 14 FLSB-4 16 | 15 FLSB-5 17 | 16 FLSB-6 18 | 17 FLSB-7 19 | 18 FLSB-8 20 | 20 KON-0 21 | 21 KON-1 22 | 22 KON-2 23 | 23 KON-3 24 | 24 KON-4 25 | 25 KON-5 26 | 26 KON-6 27 | 27 KON-7 28 | 28 KON-8 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/sim.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TOP=jtopl 4 | DUMPSIGNALS= 5 | EXTRA= 6 | GYM_FILE= 7 | GYM_ARG= 8 | FAST=-DFASTDIV 9 | VERI_EXTRA="-DSIMULATION" 10 | WAV_FILE= 11 | GATHER=gather.f 12 | SKIPMAKE=FALSE 13 | MACROS= 14 | 15 | # Locate jtfiles.go 16 | if which jtfiles > /dev/null; then 17 | JTFILES=jtfiles 18 | elif [ -e $JTFRAME/bin/jtfiles.go ]; then 19 | JTFILES="go run $JTFRAME/bin/jtfiles.go" 20 | else 21 | cat < "$UNZIP_GYM" 137 | else 138 | UNZIP_GYM=$GYM_FILE 139 | fi 140 | 141 | date 142 | 143 | # Link files located in ../../cc 144 | # Maybe I could just reference to files there, but it is not 145 | # so obvious how to do it with Verilator Makefile so I just 146 | # add them here 147 | if [ ! -e WaveWritter.cpp ]; then 148 | ln -s ../../cc/WaveWritter.cpp 149 | fi 150 | 151 | if [ ! -e WaveWritter.hpp ]; then 152 | ln -s ../../cc/WaveWritter.hpp 153 | fi 154 | 155 | if [ $SKIPMAKE = FALSE ]; then 156 | if ! verilator --cc -f $GATHER --top-module $TOP --prefix Vjtopl \ 157 | -I../../hdl --trace -DTEST_SUPPORT $MACROS -DSIMULATION \ 158 | $VERI_EXTRA $FAST --exe test.cpp VGMParser.cpp WaveWritter.cpp; then 159 | exit $? 160 | fi 161 | 162 | if ! make -j -C obj_dir -f Vjtopl.mk Vjtopl; then 163 | exit $? 164 | fi 165 | echo Simulation start... 166 | echo obj_dir/Vjtopl $DUMPSIGNALS $EXTRA $GYM_ARG "$UNZIP_GYM" -o "$WAV_FILE" 167 | fi 168 | 169 | if [[ $DUMPSIGNALS == "-trace" ]]; then 170 | if which vcd2fst; then 171 | # Verilator VCD output goes through standard output 172 | echo VCD to FST conversion running in parallel 173 | # filter out lines starting with INFO: because these come from $display commands in verilog and are 174 | # routed to standard output but are not part of the VCD file 175 | obj_dir/Vjtopl $DUMPSIGNALS $EXTRA $GYM_ARG "$UNZIP_GYM" -o "$WAV_FILE" | grep -v "^INFO: " | vcd2fst -v - -f test.fst 176 | else 177 | if which simvisdbutil; then 178 | obj_dir/Vjtopl $DUMPSIGNALS $EXTRA $GYM_ARG "$UNZIP_GYM" -o "$WAV_FILE" | grep -v "^INFO: " > test.vcd 179 | echo VCD to SST2 conversion 180 | simvisdbutil test.vcd -output test -overwrite -shm && rm test.vcd 181 | else 182 | obj_dir/Vjtopl $DUMPSIGNALS $EXTRA $GYM_ARG "$UNZIP_GYM" -o "$WAV_FILE" > test.vcd 183 | fi 184 | fi 185 | else 186 | obj_dir/Vjtopl $DUMPSIGNALS $EXTRA $GYM_ARG "$UNZIP_GYM" -o "$WAV_FILE" 187 | fi 188 | -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/am.jtt: -------------------------------------------------------------------------------- 1 | #No modulation 2 | $C0,1 3 | 4 | #Only operator 1 of channel 0 used (slot 3) 5 | #AM enabled 6 | $23,81 7 | # KSL=3 8 | $43,C0 9 | $63,F0 10 | $83,F0 11 | 12 | $A0,20 13 | $B0,20 14 | wait 200 15 | 16 | # 1dB default 17 | $B0,2A 18 | wait 4000 19 | 20 | # 4.8dB Max 21 | $BD,80 22 | wait 4000 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/fb.jtt: -------------------------------------------------------------------------------- 1 | #Attack rate 2 | $60,F0 3 | $63,00 4 | # Decay rate 5 | $80,F0 6 | 7 | # TL 8 | $40,18 9 | 10 | #FB 11 | $C0,1 12 | # Issue a key-on 13 | $A0,F0 14 | $B0,2F 15 | 16 | #Change FB to different values 17 | wait 500 18 | $C0,3 19 | wait 500 20 | $C0,3 21 | wait 500 22 | $C0,5 23 | wait 500 24 | $C0,7 25 | wait 500 26 | $C0,9 27 | wait 500 28 | $C0,B 29 | wait 500 30 | $C0,D 31 | wait 500 32 | $C0,F 33 | wait 500 34 | -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/fnum.jtt: -------------------------------------------------------------------------------- 1 | $b0,00 2 | $a0,0 3 | $b1,04 4 | $a1,1 5 | $b2,08 6 | $a2,2 7 | $b3,0c 8 | $a3,3 9 | $b4,10 10 | $a4,4 11 | $b5,14 12 | $a5,5 13 | $b6,18 14 | $a6,6 15 | $b7,1c 16 | $a7,7 17 | $b8,20 18 | $a8,8 19 | wait 40 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/keycode.jtt: -------------------------------------------------------------------------------- 1 | #No modulation 2 | $C0,1 3 | 4 | #Only operator 1 of channel 0 used (slot 3) 5 | $23,1 6 | # KSL=3 7 | $43,C0 8 | $63,F0 9 | $83,F0 10 | 11 | #Sweep 12 | # block 0 13 | $A0,6B 14 | $B0,21 15 | wait 250 16 | $A0,81 17 | $B0,21 18 | wait 250 19 | $A0,98 20 | $B0,21 21 | wait 250 22 | $A0,B0 23 | $B0,21 24 | wait 250 25 | $A0,CA 26 | $B0,21 27 | wait 250 28 | $A0,E5 29 | $B0,21 30 | wait 250 31 | $A0,2 32 | $B0,22 33 | wait 250 34 | $A0,20 35 | $B0,22 36 | wait 250 37 | $A0,41 38 | $B0,22 39 | wait 250 40 | $A0,63 41 | $B0,22 42 | wait 250 43 | $A0,87 44 | $B0,22 45 | wait 250 46 | # block 1 47 | $A0,6B 48 | $B0,25 49 | wait 250 50 | $A0,81 51 | $B0,25 52 | wait 250 53 | $A0,98 54 | $B0,25 55 | wait 250 56 | $A0,B0 57 | $B0,25 58 | wait 250 59 | $A0,CA 60 | $B0,25 61 | wait 250 62 | $A0,E5 63 | $B0,25 64 | wait 250 65 | $A0,2 66 | $B0,26 67 | wait 250 68 | $A0,20 69 | $B0,26 70 | wait 250 71 | $A0,41 72 | $B0,26 73 | wait 250 74 | $A0,63 75 | $B0,26 76 | wait 250 77 | $A0,87 78 | $B0,26 79 | wait 250 80 | # block 2 81 | $A0,6B 82 | $B0,29 83 | wait 250 84 | $A0,81 85 | $B0,29 86 | wait 250 87 | $A0,98 88 | $B0,29 89 | wait 250 90 | $A0,B0 91 | $B0,29 92 | wait 250 93 | $A0,CA 94 | $B0,29 95 | wait 250 96 | $A0,E5 97 | $B0,29 98 | wait 250 99 | $A0,2 100 | $B0,2A 101 | wait 250 102 | $A0,20 103 | $B0,2A 104 | wait 250 105 | $A0,41 106 | $B0,2A 107 | wait 250 108 | $A0,63 109 | $B0,2A 110 | wait 250 111 | $A0,87 112 | $B0,2A 113 | wait 250 114 | # block 3 115 | $A0,6B 116 | $B0,2D 117 | wait 250 118 | $A0,81 119 | $B0,2D 120 | wait 250 121 | $A0,98 122 | $B0,2D 123 | wait 250 124 | $A0,B0 125 | $B0,2D 126 | wait 250 127 | $A0,CA 128 | $B0,2D 129 | wait 250 130 | $A0,E5 131 | $B0,2D 132 | wait 250 133 | $A0,2 134 | $B0,2E 135 | wait 250 136 | $A0,20 137 | $B0,2E 138 | wait 250 139 | $A0,41 140 | $B0,2E 141 | wait 250 142 | $A0,63 143 | $B0,2E 144 | wait 250 145 | $A0,87 146 | $B0,2E 147 | wait 250 148 | # block 4 149 | $A0,6B 150 | $B0,31 151 | wait 250 152 | $A0,81 153 | $B0,31 154 | wait 250 155 | $A0,98 156 | $B0,31 157 | wait 250 158 | $A0,B0 159 | $B0,31 160 | wait 250 161 | $A0,CA 162 | $B0,31 163 | wait 250 164 | $A0,E5 165 | $B0,31 166 | wait 250 167 | $A0,2 168 | $B0,32 169 | wait 250 170 | $A0,20 171 | $B0,32 172 | wait 250 173 | $A0,41 174 | $B0,32 175 | wait 250 176 | $A0,63 177 | $B0,32 178 | wait 250 179 | $A0,87 180 | $B0,32 181 | wait 250 182 | # block 5 183 | $A0,6B 184 | $B0,35 185 | wait 250 186 | $A0,81 187 | $B0,35 188 | wait 250 189 | $A0,98 190 | $B0,35 191 | wait 250 192 | $A0,B0 193 | $B0,35 194 | wait 250 195 | $A0,CA 196 | $B0,35 197 | wait 250 198 | $A0,E5 199 | $B0,35 200 | wait 250 201 | $A0,2 202 | $B0,36 203 | wait 250 204 | $A0,20 205 | $B0,36 206 | wait 250 207 | $A0,41 208 | $B0,36 209 | wait 250 210 | $A0,63 211 | $B0,36 212 | wait 250 213 | $A0,87 214 | $B0,36 215 | wait 250 216 | # block 6 217 | $A0,6B 218 | $B0,39 219 | wait 250 220 | $A0,81 221 | $B0,39 222 | wait 250 223 | $A0,98 224 | $B0,39 225 | wait 250 226 | $A0,B0 227 | $B0,39 228 | wait 250 229 | $A0,CA 230 | $B0,39 231 | wait 250 232 | $A0,E5 233 | $B0,39 234 | wait 250 235 | $A0,2 236 | $B0,3A 237 | wait 250 238 | $A0,20 239 | $B0,3A 240 | wait 250 241 | $A0,41 242 | $B0,3A 243 | wait 250 244 | $A0,63 245 | $B0,3A 246 | wait 250 247 | $A0,87 248 | $B0,3A 249 | wait 250 250 | # block 7 251 | $A0,6B 252 | $B0,3D 253 | wait 250 254 | $A0,81 255 | $B0,3D 256 | wait 250 257 | $A0,98 258 | $B0,3D 259 | wait 250 260 | $A0,B0 261 | $B0,3D 262 | wait 250 263 | $A0,CA 264 | $B0,3D 265 | wait 250 266 | $A0,E5 267 | $B0,3D 268 | wait 250 269 | $A0,2 270 | $B0,3E 271 | wait 250 272 | $A0,20 273 | $B0,3E 274 | wait 250 275 | $A0,41 276 | $B0,3E 277 | wait 250 278 | $A0,63 279 | $B0,3E 280 | wait 250 281 | $A0,87 282 | $B0,3E 283 | wait 250 284 | -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/ksl1.jtt: -------------------------------------------------------------------------------- 1 | #No modulation 2 | $C0,1 3 | 4 | #Only operator 1 of channel 0 used (slot 3) 5 | $23,1 6 | # KSL=1 7 | $43,40 8 | $63,F0 9 | $83,F0 10 | 11 | #Sweep 12 | # block 0 13 | $A0,6B 14 | $B0,21 15 | wait 500 16 | $A0,98 17 | $B0,21 18 | wait 500 19 | $A0,CA 20 | $B0,21 21 | wait 500 22 | $A0,2 23 | $B0,22 24 | wait 500 25 | $A0,41 26 | $B0,22 27 | wait 500 28 | $A0,87 29 | $B0,22 30 | wait 500 31 | # block 1 32 | $A0,6B 33 | $B0,25 34 | wait 500 35 | $A0,98 36 | $B0,25 37 | wait 500 38 | $A0,CA 39 | $B0,25 40 | wait 500 41 | $A0,2 42 | $B0,26 43 | wait 500 44 | $A0,41 45 | $B0,26 46 | wait 500 47 | $A0,87 48 | $B0,26 49 | wait 500 50 | # block 2 51 | $A0,6B 52 | $B0,29 53 | wait 500 54 | $A0,98 55 | $B0,29 56 | wait 500 57 | $A0,CA 58 | $B0,29 59 | wait 500 60 | $A0,2 61 | $B0,2A 62 | wait 500 63 | $A0,41 64 | $B0,2A 65 | wait 500 66 | $A0,87 67 | $B0,2A 68 | wait 500 69 | # block 3 70 | $A0,6B 71 | $B0,2D 72 | wait 500 73 | $A0,98 74 | $B0,2D 75 | wait 500 76 | $A0,CA 77 | $B0,2D 78 | wait 500 79 | $A0,2 80 | $B0,2E 81 | wait 500 82 | $A0,41 83 | $B0,2E 84 | wait 500 85 | $A0,87 86 | $B0,2E 87 | wait 500 88 | # block 4 89 | $A0,6B 90 | $B0,31 91 | wait 500 92 | $A0,98 93 | $B0,31 94 | wait 500 95 | $A0,CA 96 | $B0,31 97 | wait 500 98 | $A0,2 99 | $B0,32 100 | wait 500 101 | $A0,41 102 | $B0,32 103 | wait 500 104 | $A0,87 105 | $B0,32 106 | wait 500 107 | # block 5 108 | $A0,6B 109 | $B0,35 110 | wait 500 111 | $A0,98 112 | $B0,35 113 | wait 500 114 | $A0,CA 115 | $B0,35 116 | wait 500 117 | $A0,2 118 | $B0,36 119 | wait 500 120 | $A0,41 121 | $B0,36 122 | wait 500 123 | $A0,87 124 | $B0,36 125 | wait 500 126 | # block 6 127 | $A0,6B 128 | $B0,39 129 | wait 500 130 | $A0,98 131 | $B0,39 132 | wait 500 133 | $A0,CA 134 | $B0,39 135 | wait 500 136 | $A0,2 137 | $B0,3A 138 | wait 500 139 | $A0,41 140 | $B0,3A 141 | wait 500 142 | $A0,87 143 | $B0,3A 144 | wait 500 145 | # block 7 146 | $A0,6B 147 | $B0,3D 148 | wait 500 149 | $A0,98 150 | $B0,3D 151 | wait 500 152 | $A0,CA 153 | $B0,3D 154 | wait 500 155 | $A0,2 156 | $B0,3E 157 | wait 500 158 | $A0,41 159 | $B0,3E 160 | wait 500 161 | $A0,87 162 | $B0,3E 163 | wait 500 164 | -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/ksl2.jtt: -------------------------------------------------------------------------------- 1 | #No modulation 2 | $C0,1 3 | 4 | #Only operator 1 of channel 0 used (slot 3) 5 | $23,1 6 | # KSL=2 7 | $43,80 8 | $63,F0 9 | $83,F0 10 | 11 | #Sweep 12 | # block 0 13 | $A0,6B 14 | $B0,21 15 | wait 500 16 | $A0,98 17 | $B0,21 18 | wait 500 19 | $A0,CA 20 | $B0,21 21 | wait 500 22 | $A0,2 23 | $B0,22 24 | wait 500 25 | $A0,41 26 | $B0,22 27 | wait 500 28 | $A0,87 29 | $B0,22 30 | wait 500 31 | # block 1 32 | $A0,6B 33 | $B0,25 34 | wait 500 35 | $A0,98 36 | $B0,25 37 | wait 500 38 | $A0,CA 39 | $B0,25 40 | wait 500 41 | $A0,2 42 | $B0,26 43 | wait 500 44 | $A0,41 45 | $B0,26 46 | wait 500 47 | $A0,87 48 | $B0,26 49 | wait 500 50 | # block 2 51 | $A0,6B 52 | $B0,29 53 | wait 500 54 | $A0,98 55 | $B0,29 56 | wait 500 57 | $A0,CA 58 | $B0,29 59 | wait 500 60 | $A0,2 61 | $B0,2A 62 | wait 500 63 | $A0,41 64 | $B0,2A 65 | wait 500 66 | $A0,87 67 | $B0,2A 68 | wait 500 69 | # block 3 70 | $A0,6B 71 | $B0,2D 72 | wait 500 73 | $A0,98 74 | $B0,2D 75 | wait 500 76 | $A0,CA 77 | $B0,2D 78 | wait 500 79 | $A0,2 80 | $B0,2E 81 | wait 500 82 | $A0,41 83 | $B0,2E 84 | wait 500 85 | $A0,87 86 | $B0,2E 87 | wait 500 88 | # block 4 89 | $A0,6B 90 | $B0,31 91 | wait 500 92 | $A0,98 93 | $B0,31 94 | wait 500 95 | $A0,CA 96 | $B0,31 97 | wait 500 98 | $A0,2 99 | $B0,32 100 | wait 500 101 | $A0,41 102 | $B0,32 103 | wait 500 104 | $A0,87 105 | $B0,32 106 | wait 500 107 | # block 5 108 | $A0,6B 109 | $B0,35 110 | wait 500 111 | $A0,98 112 | $B0,35 113 | wait 500 114 | $A0,CA 115 | $B0,35 116 | wait 500 117 | $A0,2 118 | $B0,36 119 | wait 500 120 | $A0,41 121 | $B0,36 122 | wait 500 123 | $A0,87 124 | $B0,36 125 | wait 500 126 | # block 6 127 | $A0,6B 128 | $B0,39 129 | wait 500 130 | $A0,98 131 | $B0,39 132 | wait 500 133 | $A0,CA 134 | $B0,39 135 | wait 500 136 | $A0,2 137 | $B0,3A 138 | wait 500 139 | $A0,41 140 | $B0,3A 141 | wait 500 142 | $A0,87 143 | $B0,3A 144 | wait 500 145 | # block 7 146 | $A0,6B 147 | $B0,3D 148 | wait 500 149 | $A0,98 150 | $B0,3D 151 | wait 500 152 | $A0,CA 153 | $B0,3D 154 | wait 500 155 | $A0,2 156 | $B0,3E 157 | wait 500 158 | $A0,41 159 | $B0,3E 160 | wait 500 161 | $A0,87 162 | $B0,3E 163 | wait 500 164 | -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/ksl3.jtt: -------------------------------------------------------------------------------- 1 | #No modulation 2 | $C0,1 3 | 4 | #Only operator 1 of channel 0 used (slot 3) 5 | $23,1 6 | # KSL=3 7 | $43,C0 8 | $63,F0 9 | $83,F0 10 | 11 | #Sweep 12 | # block 0 13 | $A0,6B 14 | $B0,21 15 | wait 500 16 | $A0,98 17 | $B0,21 18 | wait 500 19 | $A0,CA 20 | $B0,21 21 | wait 500 22 | $A0,2 23 | $B0,22 24 | wait 500 25 | $A0,41 26 | $B0,22 27 | wait 500 28 | $A0,87 29 | $B0,22 30 | wait 500 31 | # block 1 32 | $A0,6B 33 | $B0,25 34 | wait 500 35 | $A0,98 36 | $B0,25 37 | wait 500 38 | $A0,CA 39 | $B0,25 40 | wait 500 41 | $A0,2 42 | $B0,26 43 | wait 500 44 | $A0,41 45 | $B0,26 46 | wait 500 47 | $A0,87 48 | $B0,26 49 | wait 500 50 | # block 2 51 | $A0,6B 52 | $B0,29 53 | wait 500 54 | $A0,98 55 | $B0,29 56 | wait 500 57 | $A0,CA 58 | $B0,29 59 | wait 500 60 | $A0,2 61 | $B0,2A 62 | wait 500 63 | $A0,41 64 | $B0,2A 65 | wait 500 66 | $A0,87 67 | $B0,2A 68 | wait 500 69 | # block 3 70 | $A0,6B 71 | $B0,2D 72 | wait 500 73 | $A0,98 74 | $B0,2D 75 | wait 500 76 | $A0,CA 77 | $B0,2D 78 | wait 500 79 | $A0,2 80 | $B0,2E 81 | wait 500 82 | $A0,41 83 | $B0,2E 84 | wait 500 85 | $A0,87 86 | $B0,2E 87 | wait 500 88 | # block 4 89 | $A0,6B 90 | $B0,31 91 | wait 500 92 | $A0,98 93 | $B0,31 94 | wait 500 95 | $A0,CA 96 | $B0,31 97 | wait 500 98 | $A0,2 99 | $B0,32 100 | wait 500 101 | $A0,41 102 | $B0,32 103 | wait 500 104 | $A0,87 105 | $B0,32 106 | wait 500 107 | # block 5 108 | $A0,6B 109 | $B0,35 110 | wait 500 111 | $A0,98 112 | $B0,35 113 | wait 500 114 | $A0,CA 115 | $B0,35 116 | wait 500 117 | $A0,2 118 | $B0,36 119 | wait 500 120 | $A0,41 121 | $B0,36 122 | wait 500 123 | $A0,87 124 | $B0,36 125 | wait 500 126 | # block 6 127 | $A0,6B 128 | $B0,39 129 | wait 500 130 | $A0,98 131 | $B0,39 132 | wait 500 133 | $A0,CA 134 | $B0,39 135 | wait 500 136 | $A0,2 137 | $B0,3A 138 | wait 500 139 | $A0,41 140 | $B0,3A 141 | wait 500 142 | $A0,87 143 | $B0,3A 144 | wait 500 145 | # block 7 146 | $A0,6B 147 | $B0,3D 148 | wait 500 149 | $A0,98 150 | $B0,3D 151 | wait 500 152 | $A0,CA 153 | $B0,3D 154 | wait 500 155 | $A0,2 156 | $B0,3E 157 | wait 500 158 | $A0,41 159 | $B0,3E 160 | wait 500 161 | $A0,87 162 | $B0,3E 163 | wait 500 164 | -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/mod.jtt: -------------------------------------------------------------------------------- 1 | #Attack rate 2 | $60,40 3 | $63,80 4 | # Less level for modulator 5 | $40,10 6 | # Modulator set to 4x frequency 7 | $20,24 8 | # Decay rate 9 | $80,F4 10 | $83,F4 11 | wait 10 12 | 13 | # no FB, FM modulation 14 | $C0,0 15 | 16 | # Issue a key-on 17 | $A0,F0 18 | $B0,2F 19 | wait 3000 20 | 21 | #Disable modulation 22 | $C0,1 23 | wait 1000 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/noteG.jtt: -------------------------------------------------------------------------------- 1 | #Attack rate 2 | $60,F0 3 | # Decay rate 4 | $80,F4 5 | wait 10 6 | 7 | # no FB, No FM modulation 8 | $C0,1 9 | # Set Mul to 1 10 | $20,21 11 | 12 | # Issue a key-on 13 | $A0,02 14 | $B0,32 15 | wait 2000 16 | 17 | # Move one octave down 18 | $B0,12 19 | wait 1000 20 | -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/perc.jtt: -------------------------------------------------------------------------------- 1 | # Tests the percussion envelope 2 | $60,F8 3 | # Decay rate 4 | $80,38 5 | # no FB, FM modulation 6 | $C0,1 7 | #Silent operator 1 8 | $43,3F 9 | 10 | # Normal waveform 11 | $20,21 12 | $23,21 13 | # Issue a key-on 14 | $A0,F0 15 | $B0,2F 16 | wait 1600 17 | # key-off 18 | $B0,F 19 | wait 500 20 | 21 | # Percussion instrument 22 | $20,1 23 | $23,1 24 | #Key on 25 | $B0,2F 26 | wait 1600 27 | # key-off 28 | $B0,F 29 | wait 500 30 | -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/rates.jtt: -------------------------------------------------------------------------------- 1 | #Attack rate 2 | $60,0F 3 | $61,1F 4 | $62,2F 5 | $63,3F 6 | $64,4F 7 | $65,5F 8 | $68,6F 9 | $69,7F 10 | $6a,8F 11 | $6b,9F 12 | $6c,aF 13 | $6d,bF 14 | $70,cF 15 | $71,dF 16 | $72,eF 17 | $73,fF 18 | $74,f6 19 | $75,f7 20 | wait 1000 21 | 22 | # Decay rate 23 | $80,0F 24 | $81,1F 25 | $82,2F 26 | $83,3F 27 | $84,4F 28 | $85,5F 29 | $88,6F 30 | $89,7F 31 | $8a,8F 32 | $8b,9F 33 | $8c,aF 34 | $8d,bF 35 | $90,cF 36 | $91,dF 37 | $92,eF 38 | $93,fF 39 | $94,f6 40 | $95,f7 41 | 42 | # Issue a key-on 43 | $A5,F0 44 | $B5,24 45 | wait 4000 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/slots.jtt: -------------------------------------------------------------------------------- 1 | #Set all to no volume 2 | $40,3F 3 | $41,3F 4 | $42,3F 5 | $43,3F 6 | $44,3F 7 | $45,3F 8 | $48,3F 9 | $49,3F 10 | $4A,3F 11 | $4B,3F 12 | $4C,3F 13 | $4D,3F 14 | $50,3F 15 | $51,3F 16 | $52,3F 17 | $53,3F 18 | $54,3F 19 | $55,3F 20 | # Attack rate to max 21 | $60,F0 22 | $61,F0 23 | $62,F0 24 | $63,F0 25 | $64,F0 26 | $65,F0 27 | $68,F0 28 | $69,F0 29 | $6A,F0 30 | $6B,F0 31 | $6C,F0 32 | $6D,F0 33 | $70,F0 34 | $71,F0 35 | $72,F0 36 | $73,F0 37 | $74,F0 38 | $75,F0 39 | # Release rate to max 40 | $80,FF 41 | $81,FF 42 | $82,FF 43 | $83,FF 44 | $84,FF 45 | $85,FF 46 | $88,FF 47 | $89,FF 48 | $8A,FF 49 | $8B,FF 50 | $8C,FF 51 | $8D,FF 52 | $90,FF 53 | $91,FF 54 | $92,FF 55 | $93,FF 56 | $94,FF 57 | $95,FF 58 | # No FM 59 | $C0,1 60 | $C1,1 61 | $C2,1 62 | $C3,1 63 | $C4,1 64 | $C5,1 65 | $C6,1 66 | $C7,1 67 | $C8,1 68 | # Each channel has a different phase 69 | $A0,02 70 | $A1,12 71 | $A2,22 72 | $A3,32 73 | $A4,42 74 | $A5,52 75 | $A6,62 76 | $A7,72 77 | $A8,82 78 | # Op 0 of each channel has twice the frequency 79 | $20,2 80 | $21,2 81 | $22,2 82 | $28,2 83 | $29,2 84 | $2A,2 85 | $30,2 86 | $31,2 87 | $32,2 88 | # Test slot by slot 89 | 90 | #Channel 0 91 | $B0,22 92 | $40,10 93 | wait 500 94 | $40,3f 95 | 96 | $43,10 97 | wait 500 98 | $43,3f 99 | $B0,2 100 | 101 | #Channel 1 102 | $B1,22 103 | $41,10 104 | wait 500 105 | $41,3f 106 | 107 | $44,10 108 | wait 500 109 | $44,3f 110 | $B1,2 111 | 112 | #Channel 2 113 | $B2,22 114 | $42,10 115 | wait 500 116 | $42,3f 117 | 118 | $45,10 119 | wait 500 120 | $45,3f 121 | $B2,2 122 | 123 | #Channel 3 124 | $B3,22 125 | $48,10 126 | wait 500 127 | $48,3f 128 | 129 | $4b,10 130 | wait 500 131 | $4b,3f 132 | $B3,2 133 | 134 | #Channel 4 135 | $B4,22 136 | $49,10 137 | wait 500 138 | $49,3f 139 | 140 | $4c,10 141 | wait 500 142 | $4c,3f 143 | $B4,2 144 | 145 | #Channel 5 146 | $B5,22 147 | $4a,10 148 | wait 500 149 | $4a,3f 150 | 151 | $4d,10 152 | wait 500 153 | $4d,3f 154 | $B5,2 155 | 156 | #Channel 6 157 | $B6,22 158 | $50,10 159 | wait 500 160 | $50,3f 161 | 162 | $53,10 163 | wait 500 164 | $53,3f 165 | $B6,2 166 | 167 | #Channel 7 168 | $B7,22 169 | $51,10 170 | wait 500 171 | $51,3f 172 | 173 | $54,10 174 | wait 500 175 | $54,3f 176 | $B7,2 177 | 178 | #Channel 8 179 | $B8,22 180 | $52,10 181 | wait 500 182 | $52,3f 183 | 184 | $55,10 185 | wait 500 186 | $55,3f 187 | $B8,2 188 | 189 | # All should be muted 190 | wait 500 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/slots_mod.jtt: -------------------------------------------------------------------------------- 1 | #Set all to no volume 2 | $40,3F 3 | $41,3F 4 | $42,3F 5 | $43,3F 6 | $44,3F 7 | $45,3F 8 | $48,3F 9 | $49,3F 10 | $4A,3F 11 | $4B,3F 12 | $4C,3F 13 | $4D,3F 14 | $50,3F 15 | $51,3F 16 | $52,3F 17 | $53,3F 18 | $54,3F 19 | $55,3F 20 | # Attack rate to max 21 | $60,F0 22 | $61,F0 23 | $62,F0 24 | $63,F0 25 | $64,F0 26 | $65,F0 27 | $68,F0 28 | $69,F0 29 | $6A,F0 30 | $6B,F0 31 | $6C,F0 32 | $6D,F0 33 | $70,F0 34 | $71,F0 35 | $72,F0 36 | $73,F0 37 | $74,F0 38 | $75,F0 39 | # Release rate to max 40 | $80,FF 41 | $81,FF 42 | $82,FF 43 | $83,FF 44 | $84,FF 45 | $85,FF 46 | $88,FF 47 | $89,FF 48 | $8A,FF 49 | $8B,FF 50 | $8C,FF 51 | $8D,FF 52 | $90,FF 53 | $91,FF 54 | $92,FF 55 | $93,FF 56 | $94,FF 57 | $95,FF 58 | # FM 59 | $C0,0 60 | $C1,0 61 | $C2,0 62 | $C3,0 63 | $C4,0 64 | $C5,0 65 | $C6,0 66 | $C7,0 67 | $C8,0 68 | # Each channel has a different phase 69 | $A0,02 70 | $A1,12 71 | $A2,22 72 | $A3,32 73 | $A4,42 74 | $A5,52 75 | $A6,62 76 | $A7,72 77 | $A8,82 78 | # Op 0 of each channel has twice the frequency 79 | $20,2 80 | $21,2 81 | $22,2 82 | $28,2 83 | $29,2 84 | $2A,2 85 | $30,2 86 | $31,2 87 | $32,2 88 | # Test slot by slot 89 | 90 | #Channel 0 91 | $B0,22 92 | $40,10 93 | wait 500 94 | $40,3f 95 | 96 | $43,10 97 | wait 500 98 | $43,3f 99 | $B0,2 100 | 101 | #Channel 1 102 | $B1,22 103 | $41,10 104 | wait 500 105 | $41,3f 106 | 107 | $44,10 108 | wait 500 109 | $44,3f 110 | $B1,2 111 | 112 | #Channel 2 113 | $B2,22 114 | $42,10 115 | wait 500 116 | $42,3f 117 | 118 | $45,10 119 | wait 500 120 | $45,3f 121 | $B2,2 122 | 123 | #Channel 3 124 | $B3,22 125 | $48,10 126 | wait 500 127 | $48,3f 128 | 129 | $4b,10 130 | wait 500 131 | $4b,3f 132 | $B3,2 133 | 134 | #Channel 4 135 | $B4,22 136 | $49,10 137 | wait 500 138 | $49,3f 139 | 140 | $4c,10 141 | wait 500 142 | $4c,3f 143 | $B4,2 144 | 145 | #Channel 5 146 | $B5,22 147 | $4a,10 148 | wait 500 149 | $4a,3f 150 | 151 | $4d,10 152 | wait 500 153 | $4d,3f 154 | $B5,2 155 | 156 | #Channel 6 157 | $B6,22 158 | $50,10 159 | wait 500 160 | $50,3f 161 | 162 | $53,10 163 | wait 500 164 | $53,3f 165 | $B6,2 166 | 167 | #Channel 7 168 | $B7,22 169 | $51,10 170 | wait 500 171 | $51,3f 172 | 173 | $54,10 174 | wait 500 175 | $54,3f 176 | $B7,2 177 | 178 | #Channel 8 179 | $B8,22 180 | $52,10 181 | wait 500 182 | $52,3f 183 | 184 | $55,10 185 | wait 500 186 | $55,3f 187 | $B8,2 188 | 189 | # All should be muted 190 | wait 500 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/timers.jtt: -------------------------------------------------------------------------------- 1 | $2,1F 2 | $3,80 3 | $4,83 4 | wait 1000 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/tl.jtt: -------------------------------------------------------------------------------- 1 | #Attack rate 2 | $60,F0 3 | # Decay rate 4 | $80,F4 5 | wait 10 6 | 7 | # no FB, FM modulation 8 | $C0,1 9 | 10 | # Issue a key-on 11 | $A0,F0 12 | $B0,2F 13 | wait 200 14 | 15 | # Reduce volume in 3dB steps 16 | $40,4 17 | wait 200 18 | $40,8 19 | wait 200 20 | $40,C 21 | wait 200 22 | $40,10 23 | wait 200 24 | $40,14 25 | wait 200 26 | $40,18 27 | wait 200 28 | $40,1C 29 | wait 200 30 | $40,20 31 | wait 200 32 | $40,24 33 | wait 200 34 | $40,28 35 | wait 200 36 | $40,2C 37 | wait 200 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/tone.jtt: -------------------------------------------------------------------------------- 1 | #Attack rate 2 | $60,66 3 | $63,88 4 | # Decay rate 5 | $80,FA 6 | $83,11 7 | wait 10 8 | 9 | # Total level 10 | $40,0 11 | $43,FF 12 | 13 | # No feedback, parallel connection 14 | $C0,1 15 | # Issue a key-on 16 | $A0,F0 17 | $B0,2F 18 | wait 4000 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/tone_w1.jtt: -------------------------------------------------------------------------------- 1 | #Attack rate 2 | $60,66 3 | $63,88 4 | # Decay rate 5 | $80,FA 6 | $83,11 7 | wait 10 8 | 9 | # Total level 10 | $40,0 11 | $43,FF 12 | 13 | 14 | # No feedback, parallel connection 15 | $C0,1 16 | # Wave select 1 17 | $01,20 18 | $E0,1 19 | 20 | 21 | # Issue a key-on 22 | $A0,F0 23 | $B0,2F 24 | wait 4000 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/tone_w2.jtt: -------------------------------------------------------------------------------- 1 | #Attack rate 2 | $60,66 3 | $63,88 4 | # Decay rate 5 | $80,FA 6 | $83,11 7 | wait 10 8 | 9 | # Total level 10 | $40,0 11 | $43,FF 12 | 13 | 14 | # No feedback, parallel connection 15 | $C0,1 16 | # Wave select 3 17 | $01,20 18 | $E0,3 19 | 20 | 21 | # Issue a key-on 22 | $A0,F0 23 | $B0,2F 24 | wait 4000 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/tone_w3.jtt: -------------------------------------------------------------------------------- 1 | #Attack rate 2 | $60,66 3 | $63,88 4 | # Decay rate 5 | $80,FA 6 | $83,11 7 | wait 10 8 | 9 | # Total level 10 | $40,0 11 | $43,FF 12 | 13 | 14 | # No feedback, parallel connection 15 | $C0,1 16 | # Wave select 3 17 | $01,20 18 | $E0,3 19 | 20 | 21 | # Issue a key-on 22 | $A0,F0 23 | $B0,2F 24 | wait 4000 -------------------------------------------------------------------------------- /verilog/jtopl/ver/verilator/tests/vib.jtt: -------------------------------------------------------------------------------- 1 | #No modulation 2 | $C0,1 3 | 4 | #Only operator 1 of channel 0 used (slot 3) 5 | #PM enabled 6 | $23,41 7 | $43,00 8 | $63,F0 9 | $83,F0 10 | 11 | $A0,20 12 | $B0,20 13 | wait 200 14 | 15 | #PM disabled 16 | $23,01 17 | $B0,2A 18 | wait 4000 19 | 20 | #PM enabled 21 | $23,41 22 | # 7 cents default 23 | $B0,2A 24 | wait 4000 25 | 26 | # 14 cents Max 27 | $BD,40 28 | wait 4000 -------------------------------------------------------------------------------- /verilog/mda70_top.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | `default_nettype none 10 | module mda70_top( 11 | // Clocks 12 | input clk_10m, 13 | input clk_14m318, 14 | input clk_bus, 15 | 16 | // Bus reset 17 | input busreset, 18 | 19 | // ISA bus 20 | input[19:0] bus_a, 21 | input bus_ior_l, 22 | input bus_iow_l, 23 | input bus_memr_l, 24 | input bus_memw_l, 25 | inout[7:0] bus_d, 26 | output bus_dir, 27 | output bus_rdy, 28 | output bus_0ws_l, 29 | input bus_aen, 30 | input bus_ale, 31 | 32 | // RAM 33 | output ram_we_l, 34 | output[18:0] ram_a, 35 | inout[7:0] ram_d, 36 | 37 | // Video outputs 38 | output hsync, 39 | output vsync, 40 | output vid_en_l, 41 | output d_r, 42 | output d_g, 43 | output d_b, 44 | output d_r2, 45 | output d_g2, 46 | output d_b2, 47 | output vga_hsync, 48 | output vga_vsync, 49 | output[5:0] red, 50 | output[6:0] green, 51 | output[5:0] blue, 52 | 53 | // Config switches 54 | input switch2, 55 | input switch3 56 | ); 57 | 58 | // Sets up the card to generate a video signal 59 | // that will work with a standard VGA monitor 60 | // connected to the VGA port. 61 | 62 | wire clk_main; 63 | wire pll_lock; 64 | 65 | wire[7:0] bus_out; 66 | 67 | wire video; 68 | wire intensity; 69 | 70 | // Unused pins on video connector 71 | assign bus_rdy = 1'b1; 72 | assign bus_0ws_l = 1'b1; 73 | assign vid_en_l = 1'b0; 74 | assign d_r = 1'b0; 75 | assign d_g = 1'b0; 76 | assign d_b = 1'b0; 77 | assign d_r2 = 1'b0; 78 | 79 | assign d_g2 = intensity; 80 | assign d_b2 = video; 81 | 82 | assign vga_hsync = hsync; 83 | assign vga_vsync = vsync; 84 | 85 | // Set up bus direction 86 | assign bus_d = (bus_dir) ? bus_out : 8'hzz; 87 | 88 | 89 | // Take our incoming 10MHz clock and generate the pixel clock 90 | // 56.875MHz: 0, 90, 4 91 | `ifdef SYNTHESIS 92 | SB_PLL40_PAD #( 93 | .FEEDBACK_PATH("SIMPLE"), 94 | .DIVR(0), 95 | .DIVF(90), 96 | .DIVQ(4), 97 | .FILTER_RANGE(1) 98 | ) mda_pll ( 99 | .LOCK(pll_lock), 100 | .RESETB(1'b1), 101 | .BYPASS(1'b0), 102 | .PACKAGEPIN(clk_10m), 103 | .PLLOUTGLOBAL(clk_main) 104 | ); 105 | `else 106 | assign clk_main = clk_10m; 107 | `endif 108 | 109 | mda_vgaport vga ( 110 | .clk(clk_main), 111 | .video(video), 112 | .intensity(intensity), 113 | .red(red), 114 | .green(green), 115 | .blue(blue) 116 | ); 117 | 118 | mda mda1 ( 119 | .clk(clk_main), 120 | .bus_a(bus_a), 121 | .bus_ior_l(bus_ior_l), 122 | .bus_iow_l(bus_iow_l), 123 | .bus_memr_l(bus_memr_l), 124 | .bus_memw_l(bus_memw_l), 125 | .bus_d(bus_d), 126 | .bus_out(bus_out), 127 | .bus_dir(bus_dir), 128 | .bus_aen(bus_aen), 129 | .ram_we_l(ram_we_l), 130 | .ram_a(ram_a), 131 | .ram_d(ram_d), 132 | .hsync(hsync), 133 | .vsync(vsync), 134 | .intensity(intensity), 135 | .video(video) 136 | ); 137 | 138 | defparam mda1.MDA_70HZ = 1; 139 | // Adjust blink rate 140 | defparam mda1.BLINK_MAX = 24'd9100000; 141 | 142 | endmodule 143 | -------------------------------------------------------------------------------- /verilog/mda_attrib.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | `default_nettype none 10 | module mda_attrib( 11 | input clk, 12 | input[7:0] att_byte, 13 | input[4:0] row_addr, 14 | input display_enable, 15 | input blink_enabled, 16 | input blink, 17 | input cursor, 18 | input pix_in, 19 | output pix_out, 20 | output intensity_out, 21 | input grph_mode, 22 | input pix_750 23 | ); 24 | 25 | reg blinkdiv; 26 | reg[1:0] blink_old; 27 | wire att_inverse; 28 | wire att_underline; 29 | wire att_blink; 30 | wire att_nodisp; 31 | wire[2:0] att_fg; 32 | wire[2:0] att_bg; 33 | wire cursorblink; 34 | wire blink_area; 35 | wire vid_underline; 36 | wire intensity_bg; 37 | wire intensity_fg; 38 | wire alpha_dots; 39 | 40 | // Extract attributes from the attribute byte 41 | assign att_fg = att_byte[2:0]; 42 | assign att_bg = att_byte[6:4]; 43 | assign att_underline = (att_fg == 3'b001) & (row_addr==5'd12); 44 | assign intensity_bg = att_byte[7] & ~blink_enabled; 45 | assign intensity_fg = att_byte[3]; 46 | assign att_inverse = (att_fg == 3'b000) & (att_bg == 3'b111); 47 | assign att_nodisp = (att_fg == 3'b000) & (att_bg == 3'b000); 48 | assign att_blink = att_byte[7]; 49 | 50 | // Character blink is half the rate of the cursor blink 51 | always @ (posedge clk) 52 | begin 53 | blink_old <= {blink_old[0], blink}; 54 | if (blink_old == 2'b01) begin 55 | blinkdiv <= ~blinkdiv; 56 | end 57 | end 58 | 59 | // Assemble all the signals to create the final video signal 60 | assign cursorblink = cursor & blink; 61 | assign blink_area = att_blink & blinkdiv & ~cursor & blink_enabled; 62 | assign vid_underline = (pix_in | att_underline); 63 | assign alpha_dots = (vid_underline & ~att_nodisp & ~blink_area) | cursorblink; 64 | assign pix_out = display_enable ? grph_mode ? pix_750 : (alpha_dots ^ att_inverse) : 1'b0; 65 | 66 | // Assign intensity signal 67 | assign intensity_out = display_enable ? grph_mode ? pix_750 : (alpha_dots ? intensity_fg : intensity_bg) : 1'b0; 68 | 69 | 70 | endmodule 71 | 72 | -------------------------------------------------------------------------------- /verilog/mda_pixel.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | `default_nettype none 10 | module mda_pixel( 11 | input clk, 12 | input[4:0] clk_seq, 13 | input[7:0] vram_data, 14 | input vram_read_char, 15 | input vram_read_att, 16 | input disp_pipeline, 17 | input charrom_read, 18 | input display_enable, 19 | input cursor, 20 | input[4:0] row_addr, 21 | input blink_enabled, 22 | input blink, 23 | input video_enabled, 24 | output video, 25 | output intensity, 26 | input grph_mode 27 | ); 28 | 29 | reg[7:0] attr_byte; 30 | reg[7:0] char_byte; 31 | reg[7:0] char_byte_del; 32 | reg[7:0] char_byte_old; 33 | reg[7:0] attr_byte_del; 34 | reg[7:0] charbits; 35 | reg[1:0] cursor_del; 36 | reg[1:0] display_enable_del; 37 | reg pix; 38 | reg pix_delay; 39 | reg ninth_column; 40 | wire[11:0] rom_addr; 41 | reg[1:0] pix_bits; 42 | wire pix_750; 43 | 44 | // Character ROM 45 | reg[7:0] char_rom[0:4095]; 46 | initial $readmemh("mda.hex", char_rom, 0, 4095); 47 | 48 | 49 | // Latch character and attribute data from VRAM 50 | // at appropriate times 51 | always @ (posedge clk) 52 | begin 53 | if (vram_read_char) begin 54 | char_byte <= vram_data; //ES testing 55 | char_byte_old <= char_byte; 56 | end 57 | if (vram_read_att) begin 58 | attr_byte <= vram_data; //ES testing 59 | end 60 | end 61 | 62 | always @ (posedge clk) 63 | char_byte_del <= char_byte; 64 | 65 | always @ (*) 66 | begin 67 | if (video_enabled) begin 68 | case ((clk_seq[4:2] + 3'd7)) 69 | 3'd0: pix_bits <= char_byte_del[7:6]; 70 | 3'd1: pix_bits <= char_byte_del[5:4]; 71 | 3'd2: pix_bits <= char_byte_del[3:2]; 72 | 3'd3: pix_bits <= char_byte_del[1:0]; 73 | 3'd4: pix_bits <= attr_byte[7:6]; 74 | 3'd5: pix_bits <= attr_byte[5:4]; 75 | 3'd6: pix_bits <= attr_byte[3:2]; 76 | 3'd7: pix_bits <= attr_byte[1:0]; 77 | default: pix_bits <= 2'b0; 78 | endcase 79 | end else begin 80 | pix_bits <= 2'b0; 81 | end 82 | end 83 | 84 | // Add a pipeline delay to the attribute byte data, cursor, and display 85 | // enable so they line up with the displayed character 86 | always @ (posedge clk) 87 | begin 88 | if (disp_pipeline) begin 89 | attr_byte_del <= video_enabled ? attr_byte : 8'd0; 90 | display_enable_del <= {display_enable_del[0], display_enable}; 91 | cursor_del <= {cursor_del[0], cursor}; 92 | end 93 | end 94 | 95 | // Look up character byte in our character ROM table 96 | assign rom_addr = {row_addr[3], char_byte, row_addr[2:0]}; 97 | always @ (posedge clk) 98 | begin 99 | // Only load character bits at this point 100 | if (charrom_read) begin 101 | charbits <= char_rom[rom_addr]; 102 | end 103 | end 104 | 105 | // Pixel shifter 106 | always @ (*) 107 | begin 108 | case (clk_seq[4:1]) 109 | 5'd0: pix <= charbits[0]; 110 | 5'd1: pix <= ninth_column; 111 | 5'd2: pix <= charbits[7]; 112 | 5'd3: pix <= charbits[6]; 113 | 5'd4: pix <= charbits[5]; 114 | 5'd5: pix <= charbits[4]; 115 | 5'd6: pix <= charbits[3]; 116 | 5'd7: pix <= charbits[2]; 117 | 5'd8: pix <= charbits[1]; 118 | default: pix <= 0; 119 | endcase 120 | end 121 | 122 | // In graphics mode, alternate between the two bits from 123 | // the shift register outputs at specific times in the sequence 124 | wire[2:0] tmp_clk_seq; 125 | assign tmp_clk_seq = clk_seq + 3'd7; 126 | assign pix_750 = tmp_clk_seq[1] ? pix_bits[0] : pix_bits[1]; 127 | 128 | // For some characters, duplicate the 8th column as the 9th column 129 | // (Mainly line drawing characters so they span the whole cell) 130 | always @ (posedge clk) 131 | begin 132 | if (charrom_read) begin 133 | ninth_column <= (char_byte_old[7:5] == 3'b110) ? charbits[0] : 0; 134 | end 135 | end 136 | 137 | // Add one clk cycle delay to match up pixel data with attribute byte 138 | // data. 139 | always @ (posedge clk) 140 | begin 141 | pix_delay <= pix; 142 | end 143 | 144 | // Applies video attributes, generates final video 145 | mda_attrib attrib ( 146 | .clk(clk), 147 | .att_byte(attr_byte_del), 148 | .row_addr(row_addr), 149 | .display_enable(display_enable_del[1]), 150 | .blink_enabled(blink_enabled), 151 | .blink(blink), 152 | .cursor(cursor_del[1]), 153 | .pix_in(pix_delay), 154 | .pix_out(video), 155 | .intensity_out(intensity), 156 | .grph_mode(grph_mode), 157 | .pix_750(pix_750) 158 | 159 | ); 160 | 161 | endmodule 162 | -------------------------------------------------------------------------------- /verilog/mda_sequencer.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | `default_nettype none 10 | module mda_sequencer( 11 | input clk, 12 | output[4:0] clk_seq, 13 | output vram_read, 14 | output vram_read_a0, 15 | output vram_read_char, 16 | output vram_read_att, 17 | output crtc_clk, 18 | output charrom_read, 19 | output disp_pipeline, 20 | output isa_op_enable, 21 | input grph_mode 22 | ); 23 | 24 | parameter MDA_70HZ = 0; 25 | 26 | reg crtc_clk_int = 1'b0; 27 | reg[4:0] clkdiv = 5'b0; 28 | 29 | // Sequencer: times internal operations 30 | always @ (posedge clk) 31 | begin 32 | if (grph_mode) 33 | if (clkdiv == 5'd31) begin 34 | clkdiv <= 5'd0; 35 | crtc_clk_int <= 1'b1; 36 | end else begin 37 | clkdiv <= clkdiv + 1; 38 | crtc_clk_int <= 1'b0; 39 | end 40 | else 41 | if (clkdiv == 5'd17) begin 42 | clkdiv <= 5'd0; 43 | crtc_clk_int <= 1'b1; 44 | end else begin 45 | clkdiv <= clkdiv + 1; 46 | crtc_clk_int <= 1'b0; 47 | end 48 | end 49 | 50 | // Control signals based on the sequencer state 51 | assign vram_read = grph_mode ? (clkdiv == 5'd1) || (clkdiv == 5'd2) || (clkdiv == 5'd3) || 52 | (clkdiv == 5'd17) || (clkdiv == 5'd18) || (clkdiv == 5'd19) : 53 | ((clkdiv == 5'd1) || (clkdiv == 5'd2) || (clkdiv == 5'd3) 54 | || (clkdiv == 5'd4)); 55 | 56 | assign vram_read_a0 = grph_mode ? (clkdiv == 5'd2) || (clkdiv == 5'd18) : 57 | (clkdiv == 5'd3); 58 | 59 | assign vram_read_char = grph_mode ? (clkdiv == 5'd2) || (clkdiv == 5'd18) : 60 | (clkdiv == 5'd3); 61 | 62 | assign vram_read_att = grph_mode ? (clkdiv == 5'd3) || (clkdiv == 5'd19) : 63 | (clkdiv == 5'd4); 64 | 65 | assign charrom_read = (clkdiv == 5'd1); // Only for MDA text 66 | assign disp_pipeline = (clkdiv == 5'd4); // Only for MDA text 67 | assign crtc_clk = crtc_clk_int; 68 | assign clk_seq = clkdiv; 69 | // Leave a gap of at least 2 cycles between the end of ISA operation and 70 | // vram_read. This is because an ISA operation takes 3 cycles. 71 | // Stupid hack: 70Hz needs an extra cycle. 50Hz can't tolerate 72 | // an extra cycle. 73 | if (MDA_70HZ) begin 74 | assign isa_op_enable = (clkdiv > 5'd6) && (clkdiv < 5'd16); 75 | end else begin 76 | assign isa_op_enable = (clkdiv > 5'd5) && (clkdiv < 5'd16); 77 | end 78 | 79 | 80 | endmodule 81 | 82 | -------------------------------------------------------------------------------- /verilog/mda_top.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | `default_nettype none 10 | module mda_top( 11 | // Clocks 12 | input clk_10m, 13 | input clk_14m318, 14 | input clk_bus, 15 | 16 | // Bus reset 17 | input busreset, 18 | 19 | // ISA bus 20 | input[19:0] bus_a, 21 | input bus_ior_l, 22 | input bus_iow_l, 23 | input bus_memr_l, 24 | input bus_memw_l, 25 | inout[7:0] bus_d, 26 | output bus_dir, 27 | output bus_rdy, 28 | output bus_0ws_l, 29 | input bus_aen, 30 | input bus_ale, 31 | 32 | // RAM 33 | output ram_we_l, 34 | output[18:0] ram_a, 35 | inout[7:0] ram_d, 36 | 37 | // Video outputs 38 | output hsync, 39 | output vsync, 40 | output vid_en_l, 41 | output d_r, 42 | output d_g, 43 | output d_b, 44 | output d_r2, 45 | output d_g2, 46 | output d_b2, 47 | output vga_hsync, 48 | output vga_vsync, 49 | output[5:0] red, 50 | output[6:0] green, 51 | output[5:0] blue, 52 | 53 | // Config switches 54 | input switch2, 55 | input switch3 56 | ); 57 | 58 | wire clk_main; 59 | wire pll_lock; 60 | 61 | wire[7:0] bus_out; 62 | 63 | wire video; 64 | wire intensity; 65 | 66 | // Unused pins on video connector 67 | assign bus_rdy = 1'b1; 68 | assign bus_0ws_l = 1'b1; 69 | assign vid_en_l = 1'b0; 70 | assign d_r = 1'b0; 71 | assign d_g = 1'b0; 72 | assign d_b = 1'b0; 73 | assign d_r2 = 1'b0; 74 | 75 | assign d_g2 = intensity; 76 | assign d_b2 = video; 77 | 78 | assign vga_hsync = hsync; 79 | assign vga_vsync = vsync; 80 | 81 | // Set up bus direction 82 | assign bus_d = (bus_dir) ? bus_out : 8'hzz; 83 | 84 | 85 | // Take our incoming 10MHz clock and generate the pixel clock 86 | // 33MHz: 0, 105, 5 87 | `ifdef SYNTHESIS 88 | SB_PLL40_PAD #( 89 | .FEEDBACK_PATH("SIMPLE"), 90 | .DIVR(0), 91 | .DIVF(105), 92 | .DIVQ(5), 93 | .FILTER_RANGE(1) 94 | ) mda_pll ( 95 | .LOCK(pll_lock), 96 | .RESETB(1'b1), 97 | .BYPASS(1'b0), 98 | .PACKAGEPIN(clk_10m), 99 | .PLLOUTGLOBAL(clk_main) 100 | ); 101 | `else 102 | assign clk_main = clk_10m; 103 | `endif 104 | 105 | mda_vgaport vga ( 106 | .clk(clk_main), 107 | .video(video), 108 | .intensity(intensity), 109 | .red(red), 110 | .green(green), 111 | .blue(blue) 112 | ); 113 | 114 | mda mda1 ( 115 | .clk(clk_main), 116 | .bus_a(bus_a), 117 | .bus_ior_l(bus_ior_l), 118 | .bus_iow_l(bus_iow_l), 119 | .bus_memr_l(bus_memr_l), 120 | .bus_memw_l(bus_memw_l), 121 | .bus_d(bus_d), 122 | .bus_out(bus_out), 123 | .bus_dir(bus_dir), 124 | .bus_aen(bus_aen), 125 | .ram_we_l(ram_we_l), 126 | .ram_a(ram_a), 127 | .ram_d(ram_d), 128 | .hsync(hsync), 129 | .vsync(vsync), 130 | .intensity(intensity), 131 | .video(video) 132 | ); 133 | 134 | defparam mda1.MDA_70HZ = 0; 135 | defparam mda1.BLINK_MAX = 24'd5280000; 136 | 137 | endmodule 138 | -------------------------------------------------------------------------------- /verilog/mda_vgaport.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | module mda_vgaport( 10 | input clk, 11 | 12 | input video, 13 | input intensity, 14 | 15 | // Analog outputs 16 | output[5:0] red, 17 | output[6:0] green, 18 | output[5:0] blue 19 | ); 20 | 21 | reg[5:0] r; 22 | reg[5:0] g; 23 | 24 | assign red = r; 25 | assign green = {g, 1'b0}; 26 | assign blue = 6'd0; 27 | 28 | always @(posedge clk) 29 | begin 30 | case({video, intensity}) 31 | 2'd0: begin 32 | r <= 6'd0; 33 | g <= 6'd0; 34 | end 35 | 2'd1: begin 36 | r <= 6'd16; 37 | g <= 6'd12; 38 | end 39 | 2'd2: begin 40 | r <= 6'd48; 41 | g <= 6'd21; 42 | end 43 | 2'd3: begin 44 | r <= 6'd63; 45 | g <= 6'd27; 46 | end 47 | default: ; 48 | endcase 49 | end 50 | endmodule 51 | -------------------------------------------------------------------------------- /verilog/mda_vram.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 5 | // International License. To view a copy of this license, visit 6 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 7 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 8 | // 9 | module mda_vram( 10 | // Clock 11 | input clk, 12 | 13 | // Lines from other logic 14 | // Port 0 is read/write 15 | input[18:0] isa_addr, 16 | input[7:0] isa_din, 17 | output[7:0] isa_dout, 18 | input isa_read, 19 | input isa_write, 20 | input isa_op_enable, 21 | 22 | // Port 1 is read only 23 | input[18:0] pixel_addr, 24 | output[7:0] pixel_data, 25 | input pixel_read, 26 | 27 | // Lines to RAM pins 28 | output reg[18:0] ram_a, 29 | inout[7:0] ram_d, 30 | output ram_ce_l, 31 | output ram_oe_l, 32 | output ram_we_l 33 | ); 34 | 35 | parameter MDA_70HZ = 1; 36 | 37 | wire ram_write; 38 | reg[2:0] isa_phase = 3'd0; 39 | reg isa_write_old = 0; 40 | reg isa_read_old = 0; 41 | reg[19:0] op_addr = 20'd0; 42 | reg[7:0] op_data = 8'd0; 43 | reg op_write_queued = 0; 44 | reg op_read_queued = 0; 45 | reg[7:0] read_data_isa = 8'h0; 46 | reg[7:0] read_data_pixel = 8'h0; 47 | reg[7:0] ram_data_out = 8'h00; 48 | reg[2:0] write_del = 0; 49 | 50 | assign ram_ce_l = 0; 51 | assign ram_oe_l = 0; 52 | 53 | assign ram_write = (isa_phase == 3'd2) || (isa_phase == 3'd4); 54 | assign ram_we_l = ~(ram_write & ~pixel_read); 55 | assign isa_dout = read_data_isa; 56 | assign pixel_data = read_data_pixel; 57 | 58 | // Gated by clock so that we give the SRAM chip 59 | // some time to tristate its data output after 60 | // we begin the write operation. (tHZWE) 61 | assign ram_d = (~ram_we_l & (~clk | (isa_phase == 3'd4))) ? ram_data_out : 8'hZZ; 62 | 63 | // RAM address pin mux 64 | always @ (*) 65 | begin 66 | if (pixel_read) begin 67 | ram_a <= pixel_addr; 68 | end else if ((isa_phase == 3'd2) || (isa_phase == 3'd4)) begin 69 | ram_a <= op_addr; 70 | end else if (isa_read && isa_op_enable) begin 71 | ram_a <= isa_addr; 72 | end else begin 73 | ram_a <= 19'h0; 74 | end 75 | end 76 | 77 | // For edge detector 78 | always @ (posedge clk) 79 | begin 80 | isa_write_old <= isa_write; 81 | isa_read_old <= isa_read; 82 | end 83 | 84 | // Address is latched on initial edge of read or write signal 85 | always @ (posedge clk) 86 | begin 87 | if ((isa_write && ~isa_write_old) || (isa_read && ~isa_read_old)) begin 88 | op_addr <= isa_addr; 89 | end 90 | end 91 | 92 | // Wait a few cycles before latching data from ISA 93 | // bus, since the data isn't valid right away. 94 | always @ (posedge clk) 95 | begin 96 | if (isa_write && !isa_write_old) begin 97 | write_del <= 3'd1; 98 | end else if (write_del != 3'd0) begin 99 | if (write_del == 3'd7) begin 100 | write_del <= 3'd0; 101 | end else begin 102 | write_del <= write_del + 1; 103 | end 104 | end 105 | end 106 | 107 | // Write data (from host PC) is latched on final edge of write signal 108 | // We cheat and latch it after the initial edge plus a delay 109 | always @ (posedge clk) 110 | begin 111 | if (write_del == 3'd2) begin 112 | op_data <= isa_din; 113 | op_write_queued <= 1; 114 | end else if ((isa_phase == 3'd4)) begin 115 | op_write_queued <= 0; 116 | end 117 | end 118 | 119 | // Read operation triggered on initial edge of read signal 120 | always @ (posedge clk) 121 | begin 122 | if (isa_read && !isa_read_old) begin 123 | op_read_queued <= 1; 124 | end else if ((isa_phase == 3'd5)) begin 125 | op_read_queued <= 0; 126 | end 127 | end 128 | 129 | // ISA bus access state machine 130 | // State 0: idle, waiting for read or write to trip. 131 | // reads data for slower clocks 132 | // State 1: read addr phase (only for faster clocks) 133 | // State 2: write addr phase 134 | // State 4: write completion phase 135 | // State 5: read completion phase 136 | 137 | always @ (posedge clk) 138 | begin 139 | if (!isa_op_enable) begin 140 | isa_phase <= 3'd0; 141 | end else begin 142 | case (isa_phase) 143 | 3'd0: begin 144 | // Read signal is active, so start read phase 145 | if (op_read_queued) begin 146 | if (MDA_70HZ == 1) begin 147 | // At faster PLL clock, delay SRAM 148 | // read by 1 cycle to allow for more 149 | // address setup time. 150 | isa_phase <= 3'd1; 151 | end else begin 152 | // At slower PLL clock, shorten SRAM 153 | // read cycle so we don't run out 154 | // of ISA bus cycle time. 155 | read_data_isa <= ram_d; 156 | isa_phase <= 3'd5; // was 1 157 | end 158 | // A write is queued, so start write phase 159 | end else if (op_write_queued) begin 160 | isa_phase <= 3'd2; 161 | ram_data_out <= op_data; 162 | end 163 | end 164 | 3'd1: begin // Extra read cycle for fast PLL clocks 165 | read_data_isa <= ram_d; 166 | isa_phase <= 3'd5; 167 | end 168 | 3'd2: begin // Write phase 169 | isa_phase <= 3'd4; 170 | end 171 | 3'd4: isa_phase <= 3'd0; 172 | 3'd5: isa_phase <= 3'd0; 173 | default: isa_phase <= 3'd0; 174 | endcase 175 | end 176 | end 177 | 178 | // Pixel read port is much simpler. 179 | always @ (posedge clk) 180 | begin 181 | if (pixel_read) begin 182 | read_data_pixel <= ram_d; 183 | end 184 | end 185 | 186 | endmodule 187 | -------------------------------------------------------------------------------- /verilog/sound.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // Copyright (c) 2023 Aitor Gomez Garcia (spark2k06) 5 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 6 | // International License. To view a copy of this license, visit 7 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 8 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 9 | // 10 | `default_nettype wire 11 | module sound( 12 | input reset, 13 | // Clocks 14 | input clk, 15 | 16 | // ISA bus 17 | input[19:0] bus_a, 18 | input bus_ior_l, 19 | input bus_iow_l, 20 | input[7:0] bus_d, 21 | output[7:0] bus_out, 22 | output bus_dir, 23 | input bus_aen, 24 | output bus_rdy = 1, 25 | output [6:0] snd 26 | ); 27 | 28 | reg bus_ior_synced_l; 29 | reg bus_iow_synced_l; 30 | wire opl_388_cs; 31 | wire cms_220_cs; 32 | reg[7:0] bus_int_out; 33 | 34 | // Mapped IO 35 | assign opl_388_cs = (bus_a[15:1] == (16'h0388 >> 1)) & ~bus_aen; // 0x388 .. 0x389 (Adlib) 36 | assign cms_220_cs = (bus_a[15:4] == (16'h0220 >> 4)) & ~bus_aen; // 0x220 .. 0x22F (CMS Audio) 37 | 38 | always @ (*) 39 | begin 40 | 41 | if (opl_388_cs & ~bus_ior_synced_l) 42 | bus_int_out <= jtopl2_dout; 43 | else if (cms_rd && ~bus_ior_synced_l) 44 | bus_int_out <= data_from_cms; 45 | else 46 | bus_int_out <= 8'h00; 47 | 48 | end 49 | 50 | // Synchronize ISA bus control lines to our clock 51 | always @ (posedge clk) 52 | begin 53 | bus_ior_synced_l <= bus_ior_l; 54 | bus_iow_synced_l <= bus_iow_l; 55 | end 56 | 57 | // Only for read operations does bus_dir go high. 58 | assign bus_dir = ((opl_388_cs | cms_rd) & ~bus_ior_synced_l); 59 | assign bus_out = bus_int_out; 60 | 61 | wire clk_en_opl2; 62 | wire ce_saa; 63 | reg [1:0] counter; 64 | 65 | always @(posedge clk) begin 66 | counter <= counter + 1; 67 | end 68 | 69 | assign clk_en_opl2 = (counter == 2'b10); 70 | assign ce_saa = (counter == 2'b01) || (counter == 2'b11); 71 | 72 | 73 | // Game Blaster (CMS) 74 | wire cms_rd = (bus_a[3:0] == 4'h4 || bus_a[3:0] == 4'hB) && cms_220_cs; 75 | wire [7:0] data_from_cms = bus_a[3] ? cms_det : 8'h7F; 76 | 77 | wire cms_wr = ~bus_a[3] & cms_220_cs; 78 | 79 | reg [7:0] cms_det; 80 | always @(posedge clk) if(~bus_iow_synced_l && cms_wr && &bus_a[2:1]) cms_det <= bus_d; 81 | 82 | reg [15:0] o_cms; 83 | wire [7:0] saa1_l,saa1_r; 84 | saa1099 ssa1 85 | ( 86 | .clk_sys(clk), 87 | .ce(ce_saa), 88 | .rst_n(~reset), 89 | .cs_n(~(cms_wr && (bus_a[2:1] == 0))), 90 | .a0(bus_a[0]), 91 | .wr_n(bus_iow_synced_l), 92 | .din(bus_d), 93 | .out_l(saa1_l), 94 | .out_r(saa1_r) 95 | ); 96 | 97 | wire [7:0] saa2_l,saa2_r; 98 | saa1099 ssa2 99 | ( 100 | .clk_sys(clk), 101 | .ce(ce_saa), 102 | .rst_n(~reset), 103 | .cs_n(~(cms_wr && (bus_a[2:1] == 1))), 104 | .a0(bus_a[0]), 105 | .wr_n(bus_iow_synced_l), 106 | .din(bus_d), 107 | .out_l(saa2_l), 108 | .out_r(saa2_r) 109 | ); 110 | 111 | wire [8:0] cms_l = {1'b0, saa1_l} + {1'b0, saa2_l}; 112 | wire [8:0] cms_r = {1'b0, saa1_r} + {1'b0, saa2_r}; 113 | 114 | reg [15:0] sample_pre; 115 | always @(posedge clk) begin 116 | sample_pre <= {1'b0, cms_l, cms_l[8:4], 1'b0} + {1'b0, cms_r, cms_r[8:4], 1'b0}; 117 | end 118 | 119 | always @(posedge clk) begin 120 | o_cms <= $signed(sample_pre) >>> ~{3'd7}; 121 | end 122 | 123 | // OPL2 sound 124 | wire [15:0]jtopl2_snd_e; 125 | reg [31:0]sndval; 126 | 127 | wire [16:0]sndmix = (({jtopl2_snd_e[15], jtopl2_snd_e}) << 1) + (({o_cms[15], o_cms}) << 1) ; // signed mixer 128 | wire [15:0]sndamp = (~|sndmix[16:15] | &sndmix[16:15]) ? {!sndmix[15], sndmix[14:0]} : {16{!sndmix[16]}}; // clamp to [-32768..32767] and add 32878 129 | wire sndsign = sndval[31:16] < sndamp; 130 | 131 | always @(posedge clk) begin 132 | sndval <= sndval - sndval[31:7] + (sndsign << 25); 133 | end 134 | 135 | assign snd = {7{sndsign}}; 136 | 137 | wire [7:0] jtopl2_dout; 138 | 139 | jtopl2 jtopl2_inst 140 | ( 141 | .rst(reset), 142 | .clk(clk), 143 | .cen(clk_en_opl2), 144 | .din(bus_d), 145 | .dout(jtopl2_dout), 146 | .addr(bus_a[0]), 147 | .cs_n(~opl_388_cs), 148 | .wr_n(bus_iow_synced_l), 149 | .irq_n(), 150 | .snd(jtopl2_snd_e), 151 | .sample() 152 | ); 153 | 154 | endmodule 155 | -------------------------------------------------------------------------------- /verilog/sound_top.v: -------------------------------------------------------------------------------- 1 | // Graphics Gremlin 2 | // 3 | // Copyright (c) 2021 Eric Schlaepfer 4 | // Copyright (c) 2023 Aitor Gomez Garcia (spark2k06) 5 | // This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 6 | // International License. To view a copy of this license, visit 7 | // http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative 8 | // Commons, PO Box 1866, Mountain View, CA 94042, USA. 9 | // 10 | `default_nettype none 11 | module sound_top( 12 | // Clocks 13 | input clk_10m, 14 | input clk_14m318, 15 | input clk_bus, 16 | 17 | // Bus reset 18 | input busreset, 19 | 20 | // ISA bus 21 | input[19:0] bus_a, 22 | input bus_ior_l, 23 | input bus_iow_l, 24 | input bus_memr_l, 25 | input bus_memw_l, 26 | inout[7:0] bus_d, 27 | output bus_dir, 28 | output reg bus_rdy = 1'b1, 29 | output bus_0ws_l, 30 | input bus_aen, 31 | input bus_ale, 32 | 33 | // RAM 34 | output reg ram_we_l = 1'b0, 35 | output reg [18:0] ram_a = 19'd0, 36 | inout [7:0] ram_d = 8'hzz, 37 | 38 | // Video outputs 39 | output reg hsync = 1'b0, 40 | output reg vsync = 1'b0, 41 | output reg vid_en_l = 1'b0, 42 | output reg d_r = 1'b0, 43 | output reg d_g = 1'b0, 44 | output reg d_b = 1'b0, 45 | output reg d_r2 = 1'b0, 46 | output reg d_g2 = 1'b0, 47 | output reg d_b2 = 1'b0, 48 | output reg vga_hsync = 1'b0, 49 | output reg vga_vsync = 1'b0, 50 | output reg [5:0] red = 6'd0, 51 | output [6:0] green, 52 | output reg [5:0] blue = 6'd0, 53 | 54 | // Config switches 55 | input switch2, 56 | input switch3 57 | ); 58 | 59 | wire pll_lock; 60 | 61 | wire[7:0] bus_out; 62 | 63 | // Set up bus direction 64 | assign bus_d = (bus_dir) ? bus_out : 8'hzz; 65 | 66 | wire [6:0]snd; 67 | assign green = snd; 68 | 69 | sound sound1 ( 70 | .reset(busreset), 71 | .clk(clk_14m318), 72 | .bus_a(bus_a), 73 | .bus_ior_l(bus_ior_l), 74 | .bus_iow_l(bus_iow_l), 75 | .bus_d(bus_d), 76 | .bus_out(bus_out), 77 | .bus_dir(bus_dir), 78 | .bus_aen(bus_aen), 79 | .snd(snd) 80 | ); 81 | 82 | endmodule 83 | --------------------------------------------------------------------------------