├── .gitattributes ├── .gitignore ├── README.md ├── boards ├── a2n20v1 │ ├── README.md │ ├── a2n20v1.gprj │ ├── hdl │ │ ├── a2n20v1.cst │ │ ├── a2n20v1.sdc │ │ ├── bus │ │ │ └── apple_bus.sv │ │ ├── gowin │ │ │ ├── clk_hdmi │ │ │ │ ├── clk_hdmi.ipc │ │ │ │ ├── clk_hdmi.v │ │ │ │ └── clk_hdmi_tmp.v │ │ │ └── clk_logic │ │ │ │ ├── clk_logic.ipc │ │ │ │ ├── clk_logic.v │ │ │ │ └── clk_logic_tmp.v │ │ └── top.sv │ ├── impl │ │ ├── pnr │ │ │ ├── a2n20v1.fs │ │ │ ├── a2n20v1.pin.html │ │ │ ├── a2n20v1.power.html │ │ │ ├── a2n20v1.rpt.html │ │ │ ├── a2n20v1.rpt.txt │ │ │ ├── a2n20v1.tr.html │ │ │ ├── a2n20v1_tr_cata.html │ │ │ ├── a2n20v1_tr_content.html │ │ │ └── device.cfg │ │ └── project_process_config.json │ ├── photos │ │ └── a2n20v1.png │ └── sch │ │ └── a2n20v1.pdf ├── a2n20v2-Enhanced │ ├── README.md │ ├── a2n20v2_enhanced.gprj │ ├── hdl │ │ ├── a2n20v2_enhanced.cst │ │ ├── a2n20v2_enhanced.sdc │ │ ├── bus │ │ │ └── apple_bus.sv │ │ ├── gowin │ │ │ ├── clk_hdmi │ │ │ │ ├── clk_hdmi.ipc │ │ │ │ ├── clk_hdmi.v │ │ │ │ └── clk_hdmi_tmp.v │ │ │ └── clk_logic │ │ │ │ ├── clk_logic.ipc │ │ │ │ ├── clk_logic.v │ │ │ │ └── clk_logic_tmp.v │ │ ├── memory │ │ │ └── apple_memory.sv │ │ └── top.sv │ └── impl │ │ ├── pnr │ │ ├── a2n20v2_enhanced.fs │ │ ├── a2n20v2_enhanced.pin.html │ │ ├── a2n20v2_enhanced.power.html │ │ ├── a2n20v2_enhanced.rpt.html │ │ ├── a2n20v2_enhanced.rpt.txt │ │ ├── a2n20v2_enhanced.tr.html │ │ ├── a2n20v2_enhanced_tr_cata.html │ │ ├── a2n20v2_enhanced_tr_content.html │ │ └── device.cfg │ │ └── project_process_config.json ├── a2n20v2 │ ├── README.md │ ├── a2n20v2.gprj │ ├── hdl │ │ ├── a2n20v2.cst │ │ ├── a2n20v2.sdc │ │ ├── bus │ │ │ └── apple_bus.sv │ │ ├── gowin │ │ │ ├── clk_hdmi │ │ │ │ ├── clk_hdmi.ipc │ │ │ │ ├── clk_hdmi.v │ │ │ │ └── clk_hdmi_tmp.v │ │ │ └── clk_logic │ │ │ │ ├── clk_logic.ipc │ │ │ │ ├── clk_logic.v │ │ │ │ └── clk_logic_tmp.v │ │ └── top.sv │ ├── impl │ │ ├── a2n20v2_process_config.json │ │ ├── pnr │ │ │ ├── a2n20v2.fs │ │ │ ├── a2n20v2.pin.html │ │ │ ├── a2n20v2.power.html │ │ │ ├── a2n20v2.rpt.html │ │ │ ├── a2n20v2.rpt.txt │ │ │ ├── a2n20v2.tr.html │ │ │ ├── a2n20v2_tr_cata.html │ │ │ ├── a2n20v2_tr_content.html │ │ │ └── device.cfg │ │ └── project_process_config.json │ ├── photos │ │ └── a2n20v2.png │ └── sch │ │ └── a2n20v2.pdf └── a2n9 │ ├── README.md │ ├── a2n9.gprj │ ├── hdl │ ├── a2n9.cst │ ├── a2n9.sdc │ ├── bus │ │ └── apple_bus.sv │ ├── gowin │ │ ├── clk_hdmi │ │ │ ├── clk_hdmi.ipc │ │ │ ├── clk_hdmi.v │ │ │ └── clk_hdmi_tmp.v │ │ └── clk_logic │ │ │ ├── clk_logic.ipc │ │ │ ├── clk_logic.v │ │ │ └── clk_logic_tmp.v │ └── top.sv │ ├── impl │ ├── pnr │ │ ├── a2n9.fs │ │ ├── a2n9.pin.html │ │ ├── a2n9.power.html │ │ ├── a2n9.rpt.html │ │ ├── a2n9.rpt.txt │ │ ├── a2n9.tr.html │ │ ├── a2n9_tr_cata.html │ │ ├── a2n9_tr_content.html │ │ └── device.cfg │ └── project_process_config.json │ ├── photos │ └── a2n9.png │ └── sch │ └── a2n9.pdf ├── hdl ├── bus │ ├── a2bus_control_if.sv │ └── a2bus_if.sv ├── disk │ ├── apple_disk.sv │ ├── diskii.hex │ ├── drive_ii.sv │ └── drive_volume_if.sv ├── f18a │ ├── f18a.sv │ ├── f18a_color.vhd │ ├── f18a_core.vhd │ ├── f18a_counters.vhd │ ├── f18a_cpu.vhd │ ├── f18a_div32x16.vhd │ ├── f18a_gpu.vhd │ ├── f18a_gpu_if.sv │ ├── f18a_single_port_ram.vhd │ ├── f18a_sprites.vhd │ ├── f18a_tile_linebuf.vhd │ ├── f18a_tiles.vhd │ ├── f18a_top.vhd │ ├── f18a_version.vhd │ ├── f18a_vga_cont_640_60.vhd │ └── f18a_vram.vhd ├── hdmi │ ├── audio_clock_regeneration_packet.sv │ ├── audio_info_frame.sv │ ├── audio_sample_packet.sv │ ├── auxiliary_video_information_info_frame.sv │ ├── hdmi.sv │ ├── packet_assembler.sv │ ├── packet_picker.sv │ ├── serializer.sv │ ├── source_product_description_info_frame.sv │ └── tmds_channel.sv ├── memory │ ├── a2mem_if.sv │ └── apple_memory.sv ├── mockingboard │ └── mockingboard.sv ├── picosoc │ ├── firmware.hex │ ├── peripherals │ │ ├── a2disk │ │ │ └── picosoc_a2disk.sv │ │ ├── a2fpga │ │ │ └── picosoc_a2fpga.sv │ │ ├── a2slots │ │ │ └── picosoc_a2slots.sv │ │ ├── gpio │ │ │ └── picosoc_gpio.sv │ │ ├── sdcard │ │ │ ├── picosoc_sdcard.sv │ │ │ └── spi_master.v │ │ ├── sdram │ │ │ ├── fast_cache.sv │ │ │ └── picosoc_sdram.sv │ │ ├── sram │ │ │ └── picosoc_sram.sv │ │ └── uart │ │ │ ├── picosoc_uart.sv │ │ │ └── simpleuart.v │ ├── picorv32 │ │ └── picorv32.v │ └── picosoc.sv ├── sdram │ ├── sdram.sv │ ├── sdram_if_cdc.sv │ ├── sdram_if_mux.sv │ ├── sdram_port_if.sv │ └── sdram_ports.sv ├── slots │ ├── slot_if.sv │ ├── slotmaker.sv │ ├── slotmaker_config_if.sv │ └── slots.hex ├── sound │ ├── apple_speaker.sv │ ├── audio_out.v │ ├── doc5503.sv │ ├── doc5503_register_ram.sv │ └── sound_glu.sv ├── ssc │ ├── ssc_rom.vhd │ └── super_serial_card.sv ├── supersprite │ └── supersprite.sv ├── support │ ├── TMS5220.vhd │ ├── YM2149.sv │ ├── bell.sv │ ├── cdc.sv │ ├── cdc_fifo.sv │ ├── clock_enable_counter.sv │ ├── countdown.sv │ ├── dual_set_reg.sv │ ├── iir_filter.v │ ├── pulse_arbiter.v │ ├── pulse_crossing.v │ ├── pulse_generator.v │ ├── rising_edge.sv │ ├── rom.v │ ├── sdpram32.sv │ ├── srff.v │ ├── timer.sv │ ├── uart_6551.v │ ├── uart_rx.v │ ├── uart_tx.v │ ├── via6522.vhd │ └── ws2812.sv └── video │ ├── apple_video.sv │ ├── vgc.sv │ ├── video.hex │ └── video_control_if.sv ├── releases ├── README.pdf ├── a2n20v2-08-17-2024-DEFAULT.fs ├── a2n20v2-08-17-2024-NOSPRITE7.fs └── a2n20v2-08-17-2024-VIDEO-ONLY.fs └── src └── picosoc ├── README.md ├── boot ├── Makefile ├── boot.S ├── boot.lds └── main.c ├── firmware ├── Makefile ├── firmware.S ├── firmware.lds ├── main.c └── makehex.py └── libraries ├── a2disk └── a2disk.h ├── a2fpga ├── a2fpga.c └── a2fpga.h ├── a2mem ├── a2mem.c └── a2mem.h ├── a2slots ├── a2slots.c └── a2slots.h ├── ff ├── diskio.h ├── ff.c ├── ff.h ├── ffconf.h ├── ffsystem.c ├── ffunicode.c └── sdmm.c ├── gpio └── gpio.h ├── pff ├── diskio.h ├── mmcbbp.c ├── pff.c ├── pff.h └── pffconf.h ├── soc ├── soc.c └── soc.h ├── uart ├── uart.c └── uart.h └── xprintf ├── xprintf.c └── xprintf.h /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | *.gprj linguist-vendored 5 | *.fs linguist-vendored 6 | impl/** linguist-vendored 7 | boards/a2n9/impl/** linguist-vendored 8 | boards/a2n20v1/impl/** linguist-vendored 9 | boards/a2n20v2/impl/** linguist-vendored 10 | boards/a2n20v2_enhanced/impl/** linguist-vendored 11 | releases/** linguist-vendored 12 | 13 | src/picosoc/libraries/ff/** linguist-vendored 14 | src/picosoc/libraries/pff/** linguist-vendored 15 | src/picosoc/libraries/xprintf/** linguist-vendored 16 | 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | *.user 3 | impl/gwsynthesis/* 4 | !impl/gwsynthesis/*.cfg 5 | impl/temp/* 6 | impl/pnr/* 7 | !impl/pnr/*.cfg 8 | !impl/pnr/*.fs 9 | impl/synthesize/* 10 | !impl/synthesize/*.cfg 11 | 12 | #ModelSim 13 | sim/work/ 14 | sim/modelsim.ini 15 | sim/*.wlf 16 | sim/*.log 17 | sim/transcript 18 | gwsynthesis 19 | temp 20 | *.user 21 | *.do 22 | *.bin 23 | *.binx 24 | *.db 25 | *.log 26 | *.timing_paths 27 | *.vcd 28 | *.vvp 29 | *.bak 30 | *.elf 31 | *.map 32 | .DS_Store 33 | 34 | src/picosoc/firmware/firmware.hex 35 | !src/picosoc/boot/boot.bin 36 | -------------------------------------------------------------------------------- /boards/a2n20v1/README.md: -------------------------------------------------------------------------------- 1 | # A2N20v1 Card 2 | 3 |

4 | 5 |

6 | 7 | This is the project version that builds the FPGA bitstream for the 8 | [Tang Nano 20K](https://wiki.sipeed.com/hardware/en/tang/tang-nano-20k/nano-20k.html) 9 | version of the A2FPGA Apple II card. 10 | 11 | The A2N20v1 version only supports Apple II and //e models. The card will not 12 | work correctly in a IIgs. The v1 card uses a 64-pin "a2bridge" CPLD to interface 13 | and level-shift the Apple II bus that unfortunately does not capture the Apple IIgs 14 | M2SEL and M2B0 signals necessary for correctly capturing IIgs memory addresses on the bus. 15 | 16 | [A2N20v1 Schematics](sch/a2n20v1.pdf) 17 | 18 | It supports all graphics modes on all Apple II models, although software written 19 | for //e double-hires will not usually run on a II, nor will IIgs software run on 20 | a II or //e. However, the soft switches and display modes are supported on all 21 | models for software you write yourself. 22 | 23 | To update the bitstream on the A2N20v1, the most convenient way is to use [OpenFPGALoader](https://github.com/trabucayre/openFPGALoader) 24 | Mac users with [Homebrew](https://brew.sh/) can just type `brew install openfpgaloader` in the Terminal to install it 25 | Use OpenFPGALoader to program the Tang Nano 20K board via USB with the [a2n20v1.fs](impl/pnr/a2n20v1.fs) bistream file and run `openfpgaloader -b tangnano20k -f a2n20v1.fs` 26 | 27 | The project can also be opened and built with the Gowin IDE, either educational 28 | or commercial editions. Use the `a2n20v1.gprj` file in this folder. 29 | 30 | Note: When using the Gowin IDE, do not add or remove files from the project or it will 31 | turn the relative file paths into absolute file paths. 32 | 33 | -------------------------------------------------------------------------------- /boards/a2n20v1/hdl/a2n20v1.cst: -------------------------------------------------------------------------------- 1 | // Nano 9K Clock & RC Power-On-Reset/Button S1 2 | IO_LOC "clk" 4; 3 | 4 | //IO_LOC "clk_1" 10; 5 | //IO_LOC "clk_2" 11; 6 | //IO_LOC "clk_3" 13; 7 | 8 | IO_LOC "s1" 88; 9 | IO_PORT "s1" PULL_MODE=NONE; 10 | 11 | IO_LOC "s2" 87; 12 | IO_PORT "s2" PULL_MODE=NONE; 13 | 14 | // Nano 20K UART 15 | 16 | IO_LOC "uart_tx" 69; 17 | IO_PORT "uart_tx" IO_TYPE=LVCMOS33 PULL_MODE=UP; 18 | 19 | IO_LOC "uart_rx" 70; 20 | IO_PORT "uart_rx" IO_TYPE=LVCMOS33 PULL_MODE=UP; 21 | 22 | // Nano 20K HDMI 23 | 24 | IO_LOC "tmds_clk_p" 33,34; 25 | IO_PORT "tmds_clk_p" IO_TYPE=LVCMOS33D PULL_MODE=NONE DRIVE=8; 26 | 27 | IO_LOC "tmds_d_p[0]" 35,36; 28 | IO_PORT "tmds_d_p[0]" IO_TYPE=LVCMOS33D PULL_MODE=NONE DRIVE=8; 29 | 30 | IO_LOC "tmds_d_p[1]" 37,38; 31 | IO_PORT "tmds_d_p[1]" IO_TYPE=LVCMOS33D PULL_MODE=NONE DRIVE=8; 32 | 33 | IO_LOC "tmds_d_p[2]" 39,40; 34 | IO_PORT "tmds_d_p[2]" IO_TYPE=LVCMOS33D PULL_MODE=NONE DRIVE=8; 35 | 36 | // Nano 20K LEDs (renumbered, using led[0] for reset) 37 | 38 | IO_LOC "led[4]" 20; 39 | IO_PORT "led[4]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 40 | 41 | IO_LOC "led[3]" 19; 42 | IO_PORT "led[3]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 43 | 44 | IO_LOC "led[2]" 18; 45 | IO_PORT "led[2]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 46 | 47 | IO_LOC "led[1]" 17; 48 | IO_PORT "led[1]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 49 | 50 | IO_LOC "led[0]" 16; 51 | IO_PORT "led[0]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 52 | 53 | // A2N20 GPIO 54 | 55 | IO_LOC "a2_phi1" 73; 56 | IO_PORT "a2_phi1" IO_TYPE=LVCMOS33; 57 | 58 | IO_LOC "a2_7M" 74; 59 | IO_PORT "a2_7M" IO_TYPE=LVCMOS33; 60 | 61 | IO_LOC "a2_bridge_rd" 77; 62 | IO_PORT "a2_bridge_rd" IO_TYPE=LVCMOS33; 63 | 64 | IO_LOC "a2_reset_n" 15; 65 | IO_PORT "a2_reset_n" IO_TYPE=LVCMOS33; 66 | 67 | IO_LOC "a2_bridge_sel[1]" 27; 68 | IO_PORT "a2_bridge_sel[1]" IO_TYPE=LVCMOS33; 69 | 70 | IO_LOC "a2_bridge_bus_a_oe" 28; 71 | IO_PORT "a2_bridge_bus_a_oe" IO_TYPE=LVCMOS33; 72 | 73 | IO_LOC "a2_bridge_sel[0]" 29; 74 | IO_PORT "a2_bridge_sel[0]" IO_TYPE=LVCMOS33; 75 | 76 | IO_LOC "a2_bridge_bus_d_oe" 30; 77 | IO_PORT "a2_bridge_bus_d_oe" IO_TYPE=LVCMOS33; 78 | 79 | //IO_LOC "a2_bridge_clk" 31; 80 | //IO_PORT "a2_bridge_clk" IO_TYPE=LVCMOS33; 81 | 82 | IO_LOC "a2_bridge_d[7]" 42; 83 | IO_PORT "a2_bridge_d[7]" IO_TYPE=LVCMOS33; 84 | 85 | IO_LOC "a2_bridge_d[6]" 41; 86 | IO_PORT "a2_bridge_d[6]" IO_TYPE=LVCMOS33; 87 | 88 | IO_LOC "a2_bridge_d[5]" 56; 89 | IO_PORT "a2_bridge_d[5]" IO_TYPE=LVCMOS33; 90 | 91 | IO_LOC "a2_bridge_d[4]" 54; 92 | IO_PORT "a2_bridge_d[4]" IO_TYPE=LVCMOS33; 93 | 94 | IO_LOC "a2_bridge_d[3]" 48; 95 | IO_PORT "a2_bridge_d[3]" IO_TYPE=LVCMOS33; 96 | 97 | IO_LOC "a2_bridge_d[2]" 55; 98 | IO_PORT "a2_bridge_d[2]" IO_TYPE=LVCMOS33; 99 | 100 | IO_LOC "a2_bridge_d[1]" 49; 101 | IO_PORT "a2_bridge_d[1]" IO_TYPE=LVCMOS33; 102 | 103 | IO_LOC "a2_bridge_d[0]" 72; 104 | IO_PORT "a2_bridge_d[0]" IO_TYPE=LVCMOS33; 105 | 106 | IO_LOC "a2_bridge_wr" 71; 107 | IO_PORT "a2_bridge_wr" IO_TYPE=LVCMOS33; 108 | 109 | 110 | -------------------------------------------------------------------------------- /boards/a2n20v1/hdl/a2n20v1.sdc: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 GOWIN Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: Timing Constraints file 4 | //GOWIN Version: 1.9.8.11 Education 5 | //Created Time: 2023-06-02 16:47:45 6 | 7 | create_clock -name clk -period 37.037 -waveform {0 18.518} [get_ports {clk}] -add 8 | 9 | create_generated_clock -name clk_logic -source [get_ports {clk}] -master_clock clk -divide_by 1 -multiply_by 2 -add [get_nets {clk_logic_w}] 10 | create_generated_clock -name clk_pixel -source [get_nets {clk_logic_w}] -master_clock clk_logic -divide_by 2 -multiply_by 1 -add [get_nets {clk_pixel_w}] 11 | create_generated_clock -name clk_hdmi -source [get_nets {clk_pixel_w}] -master_clock clk_pixel -divide_by 1 -multiply_by 5 -add [get_nets {clk_hdmi_w}] 12 | 13 | -------------------------------------------------------------------------------- /boards/a2n20v1/hdl/gowin/clk_hdmi/clk_hdmi.ipc: -------------------------------------------------------------------------------- 1 | [General] 2 | ipc_version=4 3 | file=clk_hdmi 4 | module=clk_hdmi 5 | target_device=gw2ar18c-000 6 | type=clock_rpll 7 | version=1.0 8 | 9 | [Config] 10 | CKLOUTD3=false 11 | CLKFB_SOURCE=0 12 | CLKIN_FREQ=27 13 | CLKOUTD=false 14 | CLKOUTP=false 15 | CLKOUT_BYPASS=false 16 | CLKOUT_DIVIDE_DYN=true 17 | CLKOUT_FREQ=135 18 | CLKOUT_TOLERANCE=0 19 | DYNAMIC=true 20 | LANG=0 21 | LOCK_EN=true 22 | MODE_GENERAL=true 23 | PLL_PWD=false 24 | RESET_PLL=true 25 | -------------------------------------------------------------------------------- /boards/a2n20v1/hdl/gowin/clk_hdmi/clk_hdmi.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: IP file 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW2AR-LV18QN88C8/I7 6 | //Device: GW2AR-18 7 | //Device Version: C 8 | //Created Time: Fri Jan 19 22:04:22 2024 9 | 10 | module clk_hdmi (clkout, lock, reset, clkin); 11 | 12 | output clkout; 13 | output lock; 14 | input reset; 15 | input clkin; 16 | 17 | wire clkoutp_o; 18 | wire clkoutd_o; 19 | wire clkoutd3_o; 20 | wire gw_gnd; 21 | 22 | assign gw_gnd = 1'b0; 23 | 24 | rPLL rpll_inst ( 25 | .CLKOUT(clkout), 26 | .LOCK(lock), 27 | .CLKOUTP(clkoutp_o), 28 | .CLKOUTD(clkoutd_o), 29 | .CLKOUTD3(clkoutd3_o), 30 | .RESET(reset), 31 | .RESET_P(gw_gnd), 32 | .CLKIN(clkin), 33 | .CLKFB(gw_gnd), 34 | .FBDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 35 | .IDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 36 | .ODSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 37 | .PSDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 38 | .DUTYDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 39 | .FDLY({gw_gnd,gw_gnd,gw_gnd,gw_gnd}) 40 | ); 41 | 42 | defparam rpll_inst.FCLKIN = "27"; 43 | defparam rpll_inst.DYN_IDIV_SEL = "false"; 44 | defparam rpll_inst.IDIV_SEL = 0; 45 | defparam rpll_inst.DYN_FBDIV_SEL = "false"; 46 | defparam rpll_inst.FBDIV_SEL = 4; 47 | defparam rpll_inst.DYN_ODIV_SEL = "false"; 48 | defparam rpll_inst.ODIV_SEL = 4; 49 | defparam rpll_inst.PSDA_SEL = "0000"; 50 | defparam rpll_inst.DYN_DA_EN = "true"; 51 | defparam rpll_inst.DUTYDA_SEL = "1000"; 52 | defparam rpll_inst.CLKOUT_FT_DIR = 1'b1; 53 | defparam rpll_inst.CLKOUTP_FT_DIR = 1'b1; 54 | defparam rpll_inst.CLKOUT_DLY_STEP = 0; 55 | defparam rpll_inst.CLKOUTP_DLY_STEP = 0; 56 | defparam rpll_inst.CLKFB_SEL = "internal"; 57 | defparam rpll_inst.CLKOUT_BYPASS = "false"; 58 | defparam rpll_inst.CLKOUTP_BYPASS = "false"; 59 | defparam rpll_inst.CLKOUTD_BYPASS = "false"; 60 | defparam rpll_inst.DYN_SDIV_SEL = 2; 61 | defparam rpll_inst.CLKOUTD_SRC = "CLKOUT"; 62 | defparam rpll_inst.CLKOUTD3_SRC = "CLKOUT"; 63 | defparam rpll_inst.DEVICE = "GW2AR-18C"; 64 | 65 | endmodule //clk_hdmi 66 | -------------------------------------------------------------------------------- /boards/a2n20v1/hdl/gowin/clk_hdmi/clk_hdmi_tmp.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: Template file for instantiation 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW2AR-LV18QN88C8/I7 6 | //Device: GW2AR-18 7 | //Device Version: C 8 | //Created Time: Fri Jan 19 22:04:22 2024 9 | 10 | //Change the instance name and port connections to the signal names 11 | //--------Copy here to design-------- 12 | 13 | clk_hdmi your_instance_name( 14 | .clkout(clkout_o), //output clkout 15 | .lock(lock_o), //output lock 16 | .reset(reset_i), //input reset 17 | .clkin(clkin_i) //input clkin 18 | ); 19 | 20 | //--------Copy end------------------- 21 | -------------------------------------------------------------------------------- /boards/a2n20v1/hdl/gowin/clk_logic/clk_logic.ipc: -------------------------------------------------------------------------------- 1 | [General] 2 | ipc_version=4 3 | file=clk_logic 4 | module=clk_logic 5 | target_device=gw2ar18c-000 6 | type=clock_rpll 7 | version=1.0 8 | 9 | [Config] 10 | CKLOUTD3=false 11 | CLKFB_SOURCE=0 12 | CLKIN_FREQ=27 13 | CLKOUTD=true 14 | CLKOUTD_BYPASS=false 15 | CLKOUTD_FREQ=27 16 | CLKOUTD_SOURCE_CLKOUT=true 17 | CLKOUTD_TOLERANCE=0 18 | CLKOUTP=true 19 | CLKOUTP_BYPASS=false 20 | CLKOUTP_DUTY_CYCLE=6 21 | CLKOUTP_PHASE=8 22 | CLKOUT_BYPASS=false 23 | CLKOUT_DIVIDE_DYN=true 24 | CLKOUT_FREQ=54 25 | CLKOUT_TOLERANCE=0 26 | DYNAMIC=false 27 | LANG=0 28 | LOCK_EN=true 29 | MODE_GENERAL=true 30 | PLL_PWD=false 31 | RESET_PLL=true 32 | -------------------------------------------------------------------------------- /boards/a2n20v1/hdl/gowin/clk_logic/clk_logic.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: IP file 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW2AR-LV18QN88C8/I7 6 | //Device: GW2AR-18 7 | //Device Version: C 8 | //Created Time: Fri Jan 19 22:03:13 2024 9 | 10 | module clk_logic (clkout, lock, clkoutp, clkoutd, reset, clkin); 11 | 12 | output clkout; 13 | output lock; 14 | output clkoutp; 15 | output clkoutd; 16 | input reset; 17 | input clkin; 18 | 19 | wire clkoutd3_o; 20 | wire gw_vcc; 21 | wire gw_gnd; 22 | 23 | assign gw_vcc = 1'b1; 24 | assign gw_gnd = 1'b0; 25 | 26 | rPLL rpll_inst ( 27 | .CLKOUT(clkout), 28 | .LOCK(lock), 29 | .CLKOUTP(clkoutp), 30 | .CLKOUTD(clkoutd), 31 | .CLKOUTD3(clkoutd3_o), 32 | .RESET(reset), 33 | .RESET_P(gw_gnd), 34 | .CLKIN(clkin), 35 | .CLKFB(gw_gnd), 36 | .FBDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 37 | .IDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 38 | .ODSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 39 | .PSDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 40 | .DUTYDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 41 | .FDLY({gw_vcc,gw_vcc,gw_vcc,gw_vcc}) 42 | ); 43 | 44 | defparam rpll_inst.FCLKIN = "27"; 45 | defparam rpll_inst.DYN_IDIV_SEL = "false"; 46 | defparam rpll_inst.IDIV_SEL = 0; 47 | defparam rpll_inst.DYN_FBDIV_SEL = "false"; 48 | defparam rpll_inst.FBDIV_SEL = 1; 49 | defparam rpll_inst.DYN_ODIV_SEL = "false"; 50 | defparam rpll_inst.ODIV_SEL = 16; 51 | defparam rpll_inst.PSDA_SEL = "1000"; 52 | defparam rpll_inst.DYN_DA_EN = "false"; 53 | defparam rpll_inst.DUTYDA_SEL = "1000"; 54 | defparam rpll_inst.CLKOUT_FT_DIR = 1'b1; 55 | defparam rpll_inst.CLKOUTP_FT_DIR = 1'b1; 56 | defparam rpll_inst.CLKOUT_DLY_STEP = 0; 57 | defparam rpll_inst.CLKOUTP_DLY_STEP = 0; 58 | defparam rpll_inst.CLKFB_SEL = "internal"; 59 | defparam rpll_inst.CLKOUT_BYPASS = "false"; 60 | defparam rpll_inst.CLKOUTP_BYPASS = "false"; 61 | defparam rpll_inst.CLKOUTD_BYPASS = "false"; 62 | defparam rpll_inst.DYN_SDIV_SEL = 2; 63 | defparam rpll_inst.CLKOUTD_SRC = "CLKOUT"; 64 | defparam rpll_inst.CLKOUTD3_SRC = "CLKOUT"; 65 | defparam rpll_inst.DEVICE = "GW2AR-18C"; 66 | 67 | endmodule //clk_logic 68 | -------------------------------------------------------------------------------- /boards/a2n20v1/hdl/gowin/clk_logic/clk_logic_tmp.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: Template file for instantiation 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW2AR-LV18QN88C8/I7 6 | //Device: GW2AR-18 7 | //Device Version: C 8 | //Created Time: Fri Jan 19 22:03:13 2024 9 | 10 | //Change the instance name and port connections to the signal names 11 | //--------Copy here to design-------- 12 | 13 | clk_logic your_instance_name( 14 | .clkout(clkout_o), //output clkout 15 | .lock(lock_o), //output lock 16 | .clkoutp(clkoutp_o), //output clkoutp 17 | .clkoutd(clkoutd_o), //output clkoutd 18 | .reset(reset_i), //input reset 19 | .clkin(clkin_i) //input clkin 20 | ); 21 | 22 | //--------Copy end------------------- 23 | -------------------------------------------------------------------------------- /boards/a2n20v1/impl/pnr/a2n20v1.tr.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Timing Analysis Report 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /boards/a2n20v1/impl/pnr/device.cfg: -------------------------------------------------------------------------------- 1 | set JTAG regular_io = false 2 | set SSPI regular_io = true 3 | set MSPI regular_io = true 4 | set READY regular_io = false 5 | set DONE regular_io = false 6 | set RECONFIG_N regular_io = false 7 | set I2C regular_io = false 8 | set CRC_check = true 9 | set compress = false 10 | set encryption = false 11 | set security_bit_enable = true 12 | set bsram_init_fuse_print = true 13 | set background_programming = off 14 | set secure_mode = false 15 | set program_done_bypass = false 16 | set wake_up = 0 17 | set format = binary 18 | set power_on_reset_monitor = true 19 | set multiboot_spi_flash_address = 0x00000000 20 | set vccx = 3.3 21 | set unused_pin = default 22 | -------------------------------------------------------------------------------- /boards/a2n20v1/impl/project_process_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Allow_Duplicate_Modules" : false, 3 | "Annotated_Properties_for_Analyst" : true, 4 | "BACKGROUND_PROGRAMMING" : "off", 5 | "CMSER" : false, 6 | "CMSER_CHECKSUM" : false, 7 | "CMSER_MODE" : "auto", 8 | "COMPRESS" : false, 9 | "CPU" : false, 10 | "CRC_CHECK" : true, 11 | "Clock_Conversion" : true, 12 | "Clock_Route_Order" : 0, 13 | "Correct_Hold_Violation" : true, 14 | "DONE" : false, 15 | "DOWNLOAD_SPEED" : "default", 16 | "Default_Enum_Encoding" : "default", 17 | "Disable_Insert_Pad" : false, 18 | "ENABLE_MERGE_MODE" : false, 19 | "ENCRYPTION_KEY" : false, 20 | "ENCRYPTION_KEY_TEXT" : "00000000000000000000000000000000", 21 | "ERROR_DECTION_AND_CORRECTION" : false, 22 | "ERROR_DECTION_ONLY" : false, 23 | "ERROR_INJECTION" : false, 24 | "EXTERNAL_MASTER_CONFIG_CLOCK" : false, 25 | "FORMAT" : "binary", 26 | "FREQUENCY_DIVIDER" : "", 27 | "FSM Compiler" : true, 28 | "Fanout_Guide" : 10000, 29 | "Frequency" : "Auto", 30 | "Generate_Constraint_File_of_Ports" : false, 31 | "Generate_IBIS_File" : false, 32 | "Generate_Plain_Text_Timing_Report" : false, 33 | "Generate_Post_PNR_Simulation_Model_File" : false, 34 | "Generate_Post_Place_File" : false, 35 | "Generate_SDF_File" : false, 36 | "Generate_VHDL_Post_PNR_Simulation_Model_File" : false, 37 | "GwSyn_Loop_Limit" : 2000, 38 | "HOTBOOT" : false, 39 | "I2C" : false, 40 | "I2C_SLAVE_ADDR" : "00", 41 | "Implicit_Initial_Value_Support" : false, 42 | "IncludePath" : [ 43 | 44 | ], 45 | "Incremental_Compile" : "", 46 | "Initialize_Primitives" : false, 47 | "JTAG" : false, 48 | "MODE_IO" : false, 49 | "MSPI" : true, 50 | "MSPI_JUMP" : false, 51 | "MULTIBOOT_ADDRESS_WIDTH" : "24", 52 | "MULTIBOOT_MODE" : "Normal", 53 | "MULTIBOOT_SPI_FLASH_ADDRESS" : "00000000", 54 | "MULTIJUMP_ADDRESS_WIDTH" : "24", 55 | "MULTIJUMP_MODE" : "Normal", 56 | "MULTIJUMP_SPI_FLASH_ADDRESS" : "000000", 57 | "Multi_Boot" : true, 58 | "Multiple_File_Compilation_Unit" : true, 59 | "Number_of_Critical_Paths" : "", 60 | "Number_of_Start/End_Points" : "", 61 | "OSC_DIVIDER" : "8", 62 | "OUTPUT_BASE_NAME" : "a2n20v1", 63 | "POWER_ON_RESET_MONITOR" : true, 64 | "PRINT_BSRAM_VALUE" : true, 65 | "PROGRAM_DONE_BYPASS" : false, 66 | "Pipelining" : true, 67 | "PlaceInRegToIob" : true, 68 | "PlaceIoRegToIob" : true, 69 | "PlaceOutRegToIob" : true, 70 | "Place_Option" : "0", 71 | "Process_Configuration_Verion" : "1.0", 72 | "Promote_Physical_Constraint_Warning_to_Error" : true, 73 | "Push_Tristates" : true, 74 | "READY" : false, 75 | "RECONFIG_N" : false, 76 | "Ram_RW_Check" : true, 77 | "Replicate_Resources" : false, 78 | "Report_Auto-Placed_Io_Information" : false, 79 | "Resolve_Mixed_Drivers" : false, 80 | "Resource_Sharing" : true, 81 | "Retiming" : false, 82 | "Route_Maxfan" : 23, 83 | "Route_Option" : "1", 84 | "Run_Timing_Driven" : true, 85 | "SECURE_MODE" : false, 86 | "SECURITY_BIT" : true, 87 | "SSPI" : true, 88 | "STOP_CMSER" : false, 89 | "Show_All_Warnings" : false, 90 | "Synthesis On/Off Implemented as Translate On/Off" : false, 91 | "Synthesize_tool" : "GowinSyn", 92 | "TclPre" : "", 93 | "TopModule" : "top", 94 | "USERCODE" : "default", 95 | "Unused_Pin" : "As_input_tri_stated_with_pull_up", 96 | "Update_Compile_Point_Timing_Data" : false, 97 | "Use_Clock_Period_for_Unconstrainted IO" : false, 98 | "VCCAUX" : 3.3, 99 | "VCCX" : "3.3", 100 | "VHDL_Standard" : "VHDL_Std_2008", 101 | "Verilog_Standard" : "Vlg_Std_Sysv2017", 102 | "WAKE_UP" : "0", 103 | "Write_Vendor_Constraint_File" : true, 104 | "show_all_warnings" : true, 105 | "turn_off_bg" : false 106 | } -------------------------------------------------------------------------------- /boards/a2n20v1/photos/a2n20v1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a2fpga/a2fpga_core/20291afa7f7f9e438615e2cbe1d8e29de5e1f835/boards/a2n20v1/photos/a2n20v1.png -------------------------------------------------------------------------------- /boards/a2n20v1/sch/a2n20v1.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a2fpga/a2fpga_core/20291afa7f7f9e438615e2cbe1d8e29de5e1f835/boards/a2n20v1/sch/a2n20v1.pdf -------------------------------------------------------------------------------- /boards/a2n20v2-Enhanced/README.md: -------------------------------------------------------------------------------- 1 | # A2N20v2 Card Enhanced (Work In Progress) 2 | 3 | This is the project version that builds the FPGA bitstream for the 4 | [Tang Nano 20K](https://wiki.sipeed.com/hardware/en/tang/tang-nano-20k/nano-20k.html) 5 | version of the A2FPGA Apple II card. It is intended to provide an advanced 6 | feature set that includes a RiscV SoftCore that requires the use of the 7 | Tang Nano 20K's 8MB of SDRAM and SD Card slot. 8 | 9 | The A2N20v2 version supports Apple II, //e, and IIgs models. The v2 card uses a 100-pin 10 | "a2bridge" CPLD that captures all Apple II, //e, and IIgs signals including the 11 | M2SEL and M2B0 signals necessary for interfacing to the IIgs bus. 12 | 13 | It supports all graphics modes on all Apple II models, although software written 14 | for //e double-hires will not usually run on a II, nor will IIgs software run on 15 | a II or //e. However, the soft switches and display modes are supported on all 16 | models for software you write yourself. 17 | 18 | NOTE: This version is considered experimental but will eventually become the 19 | main A2N20v2 release. 20 | 21 | New features that this project provides include: 22 | 23 | - Persistent storage of configuration settings such as enabling and disabling virtual 24 | cards without requiring different firmware builds, making it easier to resolve compatibility 25 | issues with installed physical cards. 26 | 27 | - Moving Apple II Graphics VRAM to SDRAM for more efficient use of FPGA resources, enabling 28 | more features to be implemented in the FPGA. (IIgs graphics still use FPGA BlockRam 29 | for performance) 30 | 31 | - A PicoRV32 RiscV 32-bit co-processor that provides SD-Card support for mounting 32 | Apple II disk images from FAT32 volumes via an on-screen display for selecting and 33 | mounting disk images. 34 | 35 | - Apple II Disk Support using a RAMDISK-mechanism. Disk images are loaded into SDRAM 36 | and presented as standard Disk II Controller Card connected drives. 37 | 38 | - Ensoniq DOC 5503 sound support with 128K of dedicated sound memory for 32 oscillators 39 | 40 | The A2N20v2 has a 4-switch DIP switch that controls the following settings: 41 | 42 | 1. Enable Scanline effect when set to on 43 | 2. Enable Apple II speaker sounds via HDMI when set to on 44 | 3. Power-on-Reset Hold - Delay Apple II start-up until FPGA is initialized and running 45 | 4. Apple IIgs - Set to on when installed in an Apple IIgs 46 | 47 | For ROM 00/01 IIgs models (such as the Woz edition), the A2N20v2 must be placed in Slot 3. For ROM 03 models, it should work in any slot. This is because it requires the M2B0 signal which is only present in Slot 3 of the original IIgs models, but which is present in slots 1 to size of the ROM 03 model. 48 | 49 | To update the bitstream on the A2N20v2, the most convenient way is to use [OpenFPGALoader](https://github.com/trabucayre/openFPGALoader) 50 | Mac users with [Homebrew](https://brew.sh/) can just type `brew install openfpgaloader` in the Terminal to install it 51 | Use OpenFPGALoader to program the Tang Nano 20K board via USB with the [a2n20v2_enhanced.fs](impl/pnr/a2n20v2_enhanced.fs) bistream file and run `openfpgaloader -b tangnano20k -f a2n20v2_enhanced.fs` 52 | 53 | The project can also be opened and built with the Gowin IDE, either educational 54 | or commercial editions. Use the `a2n20v2_enhanced.gprj` file in this folder. 55 | 56 | Note: When using the Gowin IDE, do not add or remove files from the project or it will 57 | turn the relative file paths into absolute file paths. 58 | -------------------------------------------------------------------------------- /boards/a2n20v2-Enhanced/hdl/a2n20v2_enhanced.cst: -------------------------------------------------------------------------------- 1 | // Nano 9K Clock & RC Power-On-Reset/Button S1 2 | IO_LOC "clk" 4; 3 | 4 | //IO_LOC "clk_1" 10; 5 | //IO_LOC "clk_2" 11; 6 | //IO_LOC "clk_3" 13; 7 | 8 | IO_LOC "s1" 88; 9 | IO_PORT "s1" PULL_MODE=NONE; 10 | 11 | IO_LOC "s2" 87; 12 | IO_PORT "s2" PULL_MODE=NONE; 13 | 14 | // Nano 20K UART 15 | 16 | IO_LOC "uart_tx" 69; 17 | IO_PORT "uart_tx" IO_TYPE=LVCMOS33 PULL_MODE=UP; 18 | 19 | IO_LOC "uart_rx" 70; 20 | IO_PORT "uart_rx" IO_TYPE=LVCMOS33 PULL_MODE=UP; 21 | 22 | // Nano 20K HDMI 23 | 24 | IO_LOC "tmds_clk_p" 33,34; 25 | IO_PORT "tmds_clk_p" IO_TYPE=LVCMOS33D PULL_MODE=NONE DRIVE=8; 26 | 27 | IO_LOC "tmds_d_p[0]" 35,36; 28 | IO_PORT "tmds_d_p[0]" IO_TYPE=LVCMOS33D PULL_MODE=NONE DRIVE=8; 29 | 30 | IO_LOC "tmds_d_p[1]" 37,38; 31 | IO_PORT "tmds_d_p[1]" IO_TYPE=LVCMOS33D PULL_MODE=NONE DRIVE=8; 32 | 33 | IO_LOC "tmds_d_p[2]" 39,40; 34 | IO_PORT "tmds_d_p[2]" IO_TYPE=LVCMOS33D PULL_MODE=NONE DRIVE=8; 35 | 36 | // Nano 20K LEDs (renumbered, using led[0] for reset) 37 | 38 | IO_LOC "led[4]" 20; 39 | IO_PORT "led[4]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 40 | 41 | IO_LOC "led[3]" 19; 42 | IO_PORT "led[3]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 43 | 44 | IO_LOC "led[2]" 18; 45 | IO_PORT "led[2]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 46 | 47 | IO_LOC "led[1]" 17; 48 | IO_PORT "led[1]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 49 | 50 | IO_LOC "led[0]" 16; 51 | IO_PORT "led[0]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 52 | 53 | IO_LOC "ws2812" 79; 54 | IO_PORT "ws2812" IO_TYPE=LVCMOS33 DRIVE=8; 55 | 56 | // A2N20 GPIO 57 | 58 | IO_LOC "a2_phi1" 31; 59 | IO_PORT "a2_phi1" IO_TYPE=LVCMOS33; 60 | 61 | IO_LOC "a2_7M" 73; 62 | IO_PORT "a2_7M" IO_TYPE=LVCMOS33; 63 | 64 | IO_LOC "a2_bridge_rd_n" 74; 65 | IO_PORT "a2_bridge_rd_n" IO_TYPE=LVCMOS33; 66 | 67 | IO_LOC "a2_reset_n" 15; 68 | IO_PORT "a2_reset_n" IO_TYPE=LVCMOS33; 69 | 70 | IO_LOC "a2_bridge_sel[1]" 29; 71 | IO_PORT "a2_bridge_sel[1]" IO_TYPE=LVCMOS33; 72 | 73 | IO_LOC "a2_bridge_bus_a_oe_n" 27; 74 | IO_PORT "a2_bridge_bus_a_oe_n" IO_TYPE=LVCMOS33; 75 | 76 | IO_LOC "a2_bridge_sel[0]" 30; 77 | IO_PORT "a2_bridge_sel[0]" IO_TYPE=LVCMOS33; 78 | 79 | IO_LOC "a2_bridge_bus_d_oe_n" 77; 80 | IO_PORT "a2_bridge_bus_d_oe_n" IO_TYPE=LVCMOS33; 81 | 82 | IO_LOC "a2_bridge_sel[2]" 28; 83 | IO_PORT "a2_bridge_sel[2]" IO_TYPE=LVCMOS33; 84 | 85 | IO_LOC "a2_bridge_d[7]" 42; 86 | IO_PORT "a2_bridge_d[7]" IO_TYPE=LVCMOS33; 87 | 88 | IO_LOC "a2_bridge_d[6]" 41; 89 | IO_PORT "a2_bridge_d[6]" IO_TYPE=LVCMOS33; 90 | 91 | IO_LOC "a2_bridge_d[5]" 56; 92 | IO_PORT "a2_bridge_d[5]" IO_TYPE=LVCMOS33; 93 | 94 | IO_LOC "a2_bridge_d[4]" 54; 95 | IO_PORT "a2_bridge_d[4]" IO_TYPE=LVCMOS33; 96 | 97 | IO_LOC "a2_bridge_d[3]" 48; 98 | IO_PORT "a2_bridge_d[3]" IO_TYPE=LVCMOS33; 99 | 100 | IO_LOC "a2_bridge_d[2]" 55; 101 | IO_PORT "a2_bridge_d[2]" IO_TYPE=LVCMOS33; 102 | 103 | IO_LOC "a2_bridge_d[1]" 49; 104 | IO_PORT "a2_bridge_d[1]" IO_TYPE=LVCMOS33; 105 | 106 | IO_LOC "a2_bridge_d[0]" 72; 107 | IO_PORT "a2_bridge_d[0]" IO_TYPE=LVCMOS33; 108 | 109 | IO_LOC "a2_bridge_wr_n" 71; 110 | IO_PORT "a2_bridge_wr_n" IO_TYPE=LVCMOS33; 111 | 112 | // SDCard 113 | 114 | IO_LOC "sd_clk" 83; 115 | IO_PORT "sd_clk" PULL_MODE=NONE IO_TYPE=LVCMOS33; 116 | IO_LOC "sd_cmd" 82; // MOSI 117 | IO_PORT "sd_cmd" PULL_MODE=NONE IO_TYPE=LVCMOS33; 118 | IO_LOC "sd_dat0" 84; // MISO 119 | IO_PORT "sd_dat0" PULL_MODE=NONE IO_TYPE=LVCMOS33; 120 | //IO_LOC "sd_dat1" 85; // 1 121 | //IO_PORT "sd_dat1" PULL_MODE=NONE IO_TYPE=LVCMOS33; 122 | //IO_LOC "sd_dat2" 80; // 1 123 | //IO_PORT "sd_dat2" PULL_MODE=NONE IO_TYPE=LVCMOS33; 124 | IO_LOC "sd_dat3" 81; // 1 125 | IO_PORT "sd_dat3" PULL_MODE=NONE IO_TYPE=LVCMOS33; 126 | -------------------------------------------------------------------------------- /boards/a2n20v2-Enhanced/hdl/a2n20v2_enhanced.sdc: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 GOWIN Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: Timing Constraints file 4 | //GOWIN Version: 1.9.8.11 Education 5 | //Created Time: 2023-06-02 16:47:45 6 | 7 | create_clock -name clk -period 37.037 -waveform {0 18.518} [get_ports {clk}] -add 8 | 9 | create_generated_clock -name clk_logic -source [get_ports {clk}] -master_clock clk -divide_by 1 -multiply_by 2 -add [get_nets {clk_logic_w}] 10 | create_generated_clock -name clk_pixel -source [get_nets {clk_logic_w}] -master_clock clk_logic -divide_by 2 -multiply_by 1 -add [get_nets {clk_pixel_w}] 11 | create_generated_clock -name clk_hdmi -source [get_nets {clk_pixel_w}] -master_clock clk_pixel -divide_by 1 -multiply_by 5 -add [get_nets {clk_hdmi_w}] 12 | 13 | -------------------------------------------------------------------------------- /boards/a2n20v2-Enhanced/hdl/gowin/clk_hdmi/clk_hdmi.ipc: -------------------------------------------------------------------------------- 1 | [General] 2 | ipc_version=4 3 | file=clk_hdmi 4 | module=clk_hdmi 5 | target_device=gw2ar18c-000 6 | type=clock_rpll 7 | version=1.0 8 | 9 | [Config] 10 | CKLOUTD3=false 11 | CLKFB_SOURCE=0 12 | CLKIN_FREQ=27 13 | CLKOUTD=false 14 | CLKOUTP=false 15 | CLKOUT_BYPASS=false 16 | CLKOUT_DIVIDE_DYN=true 17 | CLKOUT_FREQ=135 18 | CLKOUT_TOLERANCE=0 19 | DYNAMIC=true 20 | LANG=0 21 | LOCK_EN=true 22 | MODE_GENERAL=true 23 | PLL_PWD=false 24 | RESET_PLL=true 25 | -------------------------------------------------------------------------------- /boards/a2n20v2-Enhanced/hdl/gowin/clk_hdmi/clk_hdmi.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: IP file 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW2AR-LV18QN88C8/I7 6 | //Device: GW2AR-18 7 | //Device Version: C 8 | //Created Time: Fri Jan 19 22:04:22 2024 9 | 10 | module clk_hdmi (clkout, lock, reset, clkin); 11 | 12 | output clkout; 13 | output lock; 14 | input reset; 15 | input clkin; 16 | 17 | wire clkoutp_o; 18 | wire clkoutd_o; 19 | wire clkoutd3_o; 20 | wire gw_gnd; 21 | 22 | assign gw_gnd = 1'b0; 23 | 24 | rPLL rpll_inst ( 25 | .CLKOUT(clkout), 26 | .LOCK(lock), 27 | .CLKOUTP(clkoutp_o), 28 | .CLKOUTD(clkoutd_o), 29 | .CLKOUTD3(clkoutd3_o), 30 | .RESET(reset), 31 | .RESET_P(gw_gnd), 32 | .CLKIN(clkin), 33 | .CLKFB(gw_gnd), 34 | .FBDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 35 | .IDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 36 | .ODSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 37 | .PSDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 38 | .DUTYDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 39 | .FDLY({gw_gnd,gw_gnd,gw_gnd,gw_gnd}) 40 | ); 41 | 42 | defparam rpll_inst.FCLKIN = "27"; 43 | defparam rpll_inst.DYN_IDIV_SEL = "false"; 44 | defparam rpll_inst.IDIV_SEL = 0; 45 | defparam rpll_inst.DYN_FBDIV_SEL = "false"; 46 | defparam rpll_inst.FBDIV_SEL = 4; 47 | defparam rpll_inst.DYN_ODIV_SEL = "false"; 48 | defparam rpll_inst.ODIV_SEL = 4; 49 | defparam rpll_inst.PSDA_SEL = "0000"; 50 | defparam rpll_inst.DYN_DA_EN = "true"; 51 | defparam rpll_inst.DUTYDA_SEL = "1000"; 52 | defparam rpll_inst.CLKOUT_FT_DIR = 1'b1; 53 | defparam rpll_inst.CLKOUTP_FT_DIR = 1'b1; 54 | defparam rpll_inst.CLKOUT_DLY_STEP = 0; 55 | defparam rpll_inst.CLKOUTP_DLY_STEP = 0; 56 | defparam rpll_inst.CLKFB_SEL = "internal"; 57 | defparam rpll_inst.CLKOUT_BYPASS = "false"; 58 | defparam rpll_inst.CLKOUTP_BYPASS = "false"; 59 | defparam rpll_inst.CLKOUTD_BYPASS = "false"; 60 | defparam rpll_inst.DYN_SDIV_SEL = 2; 61 | defparam rpll_inst.CLKOUTD_SRC = "CLKOUT"; 62 | defparam rpll_inst.CLKOUTD3_SRC = "CLKOUT"; 63 | defparam rpll_inst.DEVICE = "GW2AR-18C"; 64 | 65 | endmodule //clk_hdmi 66 | -------------------------------------------------------------------------------- /boards/a2n20v2-Enhanced/hdl/gowin/clk_hdmi/clk_hdmi_tmp.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: Template file for instantiation 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW2AR-LV18QN88C8/I7 6 | //Device: GW2AR-18 7 | //Device Version: C 8 | //Created Time: Fri Jan 19 22:04:22 2024 9 | 10 | //Change the instance name and port connections to the signal names 11 | //--------Copy here to design-------- 12 | 13 | clk_hdmi your_instance_name( 14 | .clkout(clkout_o), //output clkout 15 | .lock(lock_o), //output lock 16 | .reset(reset_i), //input reset 17 | .clkin(clkin_i) //input clkin 18 | ); 19 | 20 | //--------Copy end------------------- 21 | -------------------------------------------------------------------------------- /boards/a2n20v2-Enhanced/hdl/gowin/clk_logic/clk_logic.ipc: -------------------------------------------------------------------------------- 1 | [General] 2 | ipc_version=4 3 | file=clk_logic 4 | module=clk_logic 5 | target_device=gw2ar18c-000 6 | type=clock_rpll 7 | version=1.0 8 | 9 | [Config] 10 | CKLOUTD3=false 11 | CLKFB_SOURCE=0 12 | CLKIN_FREQ=27 13 | CLKOUTD=true 14 | CLKOUTD_BYPASS=false 15 | CLKOUTD_FREQ=27 16 | CLKOUTD_SOURCE_CLKOUT=true 17 | CLKOUTD_TOLERANCE=0 18 | CLKOUTP=true 19 | CLKOUTP_BYPASS=false 20 | CLKOUTP_DUTY_CYCLE=6 21 | CLKOUTP_PHASE=8 22 | CLKOUT_BYPASS=false 23 | CLKOUT_DIVIDE_DYN=true 24 | CLKOUT_FREQ=54 25 | CLKOUT_TOLERANCE=0 26 | DYNAMIC=false 27 | LANG=0 28 | LOCK_EN=true 29 | MODE_GENERAL=true 30 | PLL_PWD=false 31 | RESET_PLL=true 32 | -------------------------------------------------------------------------------- /boards/a2n20v2-Enhanced/hdl/gowin/clk_logic/clk_logic.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: IP file 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW2AR-LV18QN88C8/I7 6 | //Device: GW2AR-18 7 | //Device Version: C 8 | //Created Time: Fri Jan 19 22:03:13 2024 9 | 10 | module clk_logic (clkout, lock, clkoutp, clkoutd, reset, clkin); 11 | 12 | output clkout; 13 | output lock; 14 | output clkoutp; 15 | output clkoutd; 16 | input reset; 17 | input clkin; 18 | 19 | wire clkoutd3_o; 20 | wire gw_vcc; 21 | wire gw_gnd; 22 | 23 | assign gw_vcc = 1'b1; 24 | assign gw_gnd = 1'b0; 25 | 26 | rPLL rpll_inst ( 27 | .CLKOUT(clkout), 28 | .LOCK(lock), 29 | .CLKOUTP(clkoutp), 30 | .CLKOUTD(clkoutd), 31 | .CLKOUTD3(clkoutd3_o), 32 | .RESET(reset), 33 | .RESET_P(gw_gnd), 34 | .CLKIN(clkin), 35 | .CLKFB(gw_gnd), 36 | .FBDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 37 | .IDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 38 | .ODSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 39 | .PSDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 40 | .DUTYDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 41 | .FDLY({gw_vcc,gw_vcc,gw_vcc,gw_vcc}) 42 | ); 43 | 44 | defparam rpll_inst.FCLKIN = "27"; 45 | defparam rpll_inst.DYN_IDIV_SEL = "false"; 46 | defparam rpll_inst.IDIV_SEL = 0; 47 | defparam rpll_inst.DYN_FBDIV_SEL = "false"; 48 | defparam rpll_inst.FBDIV_SEL = 1; 49 | defparam rpll_inst.DYN_ODIV_SEL = "false"; 50 | defparam rpll_inst.ODIV_SEL = 16; 51 | defparam rpll_inst.PSDA_SEL = "1000"; 52 | defparam rpll_inst.DYN_DA_EN = "false"; 53 | defparam rpll_inst.DUTYDA_SEL = "1000"; 54 | defparam rpll_inst.CLKOUT_FT_DIR = 1'b1; 55 | defparam rpll_inst.CLKOUTP_FT_DIR = 1'b1; 56 | defparam rpll_inst.CLKOUT_DLY_STEP = 0; 57 | defparam rpll_inst.CLKOUTP_DLY_STEP = 0; 58 | defparam rpll_inst.CLKFB_SEL = "internal"; 59 | defparam rpll_inst.CLKOUT_BYPASS = "false"; 60 | defparam rpll_inst.CLKOUTP_BYPASS = "false"; 61 | defparam rpll_inst.CLKOUTD_BYPASS = "false"; 62 | defparam rpll_inst.DYN_SDIV_SEL = 2; 63 | defparam rpll_inst.CLKOUTD_SRC = "CLKOUT"; 64 | defparam rpll_inst.CLKOUTD3_SRC = "CLKOUT"; 65 | defparam rpll_inst.DEVICE = "GW2AR-18C"; 66 | 67 | endmodule //clk_logic 68 | -------------------------------------------------------------------------------- /boards/a2n20v2-Enhanced/hdl/gowin/clk_logic/clk_logic_tmp.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: Template file for instantiation 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW2AR-LV18QN88C8/I7 6 | //Device: GW2AR-18 7 | //Device Version: C 8 | //Created Time: Fri Jan 19 22:03:13 2024 9 | 10 | //Change the instance name and port connections to the signal names 11 | //--------Copy here to design-------- 12 | 13 | clk_logic your_instance_name( 14 | .clkout(clkout_o), //output clkout 15 | .lock(lock_o), //output lock 16 | .clkoutp(clkoutp_o), //output clkoutp 17 | .clkoutd(clkoutd_o), //output clkoutd 18 | .reset(reset_i), //input reset 19 | .clkin(clkin_i) //input clkin 20 | ); 21 | 22 | //--------Copy end------------------- 23 | -------------------------------------------------------------------------------- /boards/a2n20v2-Enhanced/impl/pnr/a2n20v2_enhanced.tr.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Timing Analysis Report 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /boards/a2n20v2-Enhanced/impl/pnr/device.cfg: -------------------------------------------------------------------------------- 1 | set JTAG regular_io = false 2 | set SSPI regular_io = true 3 | set MSPI regular_io = true 4 | set READY regular_io = false 5 | set DONE regular_io = false 6 | set RECONFIG_N regular_io = false 7 | set I2C regular_io = false 8 | set CRC_check = true 9 | set compress = false 10 | set encryption = false 11 | set security_bit_enable = true 12 | set bsram_init_fuse_print = true 13 | set background_programming = off 14 | set secure_mode = false 15 | set program_done_bypass = false 16 | set wake_up = 0 17 | set format = binary 18 | set power_on_reset_monitor = true 19 | set multiboot_spi_flash_address = 0x00000000 20 | set vccx = 3.3 21 | set unused_pin = default 22 | -------------------------------------------------------------------------------- /boards/a2n20v2-Enhanced/impl/project_process_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Allow_Duplicate_Modules" : false, 3 | "Annotated_Properties_for_Analyst" : true, 4 | "BACKGROUND_PROGRAMMING" : "off", 5 | "CMSER" : false, 6 | "CMSER_CHECKSUM" : false, 7 | "CMSER_MODE" : "auto", 8 | "COMPRESS" : false, 9 | "CPU" : false, 10 | "CRC_CHECK" : true, 11 | "Clock_Conversion" : true, 12 | "Clock_Route_Order" : 0, 13 | "Correct_Hold_Violation" : true, 14 | "DONE" : false, 15 | "DOWNLOAD_SPEED" : "default", 16 | "Default_Enum_Encoding" : "default", 17 | "Disable_Insert_Pad" : false, 18 | "ENABLE_MERGE_MODE" : false, 19 | "ENCRYPTION_KEY" : false, 20 | "ENCRYPTION_KEY_TEXT" : "00000000000000000000000000000000", 21 | "ERROR_DECTION_AND_CORRECTION" : false, 22 | "ERROR_DECTION_ONLY" : false, 23 | "ERROR_INJECTION" : false, 24 | "EXTERNAL_MASTER_CONFIG_CLOCK" : false, 25 | "FORMAT" : "binary", 26 | "FREQUENCY_DIVIDER" : "", 27 | "FSM Compiler" : true, 28 | "Fanout_Guide" : 10000, 29 | "Frequency" : "Auto", 30 | "Generate_Constraint_File_of_Ports" : false, 31 | "Generate_IBIS_File" : false, 32 | "Generate_Plain_Text_Timing_Report" : false, 33 | "Generate_Post_PNR_Simulation_Model_File" : false, 34 | "Generate_Post_Place_File" : false, 35 | "Generate_SDF_File" : false, 36 | "Generate_VHDL_Post_PNR_Simulation_Model_File" : false, 37 | "GwSyn_Loop_Limit" : 2000, 38 | "HOTBOOT" : false, 39 | "I2C" : false, 40 | "I2C_SLAVE_ADDR" : "00", 41 | "Implicit_Initial_Value_Support" : false, 42 | "IncludePath" : [ 43 | 44 | ], 45 | "Incremental_Compile" : "", 46 | "Initialize_Primitives" : false, 47 | "JTAG" : false, 48 | "MODE_IO" : false, 49 | "MSPI" : true, 50 | "MSPI_JUMP" : false, 51 | "MULTIBOOT_ADDRESS_WIDTH" : "24", 52 | "MULTIBOOT_MODE" : "Normal", 53 | "MULTIBOOT_SPI_FLASH_ADDRESS" : "00000000", 54 | "MULTIJUMP_ADDRESS_WIDTH" : "24", 55 | "MULTIJUMP_MODE" : "Normal", 56 | "MULTIJUMP_SPI_FLASH_ADDRESS" : "000000", 57 | "Multi_Boot" : true, 58 | "Multiple_File_Compilation_Unit" : true, 59 | "Number_of_Critical_Paths" : "", 60 | "Number_of_Start/End_Points" : "", 61 | "OSC_DIVIDER" : "8", 62 | "OUTPUT_BASE_NAME" : "a2n20v2_enhanced", 63 | "POWER_ON_RESET_MONITOR" : true, 64 | "PRINT_BSRAM_VALUE" : true, 65 | "PROGRAM_DONE_BYPASS" : false, 66 | "Pipelining" : true, 67 | "PlaceInRegToIob" : true, 68 | "PlaceIoRegToIob" : true, 69 | "PlaceOutRegToIob" : true, 70 | "Place_Option" : "0", 71 | "Process_Configuration_Verion" : "1.0", 72 | "Promote_Physical_Constraint_Warning_to_Error" : true, 73 | "Push_Tristates" : true, 74 | "READY" : false, 75 | "RECONFIG_N" : false, 76 | "Ram_RW_Check" : true, 77 | "Replicate_Resources" : false, 78 | "Report_Auto-Placed_Io_Information" : false, 79 | "Resolve_Mixed_Drivers" : false, 80 | "Resource_Sharing" : true, 81 | "Retiming" : false, 82 | "Route_Maxfan" : 23, 83 | "Route_Option" : "1", 84 | "Run_Timing_Driven" : true, 85 | "SECURE_MODE" : false, 86 | "SECURITY_BIT" : true, 87 | "SSPI" : true, 88 | "STOP_CMSER" : false, 89 | "Show_All_Warnings" : false, 90 | "Synthesis On/Off Implemented as Translate On/Off" : false, 91 | "Synthesize_tool" : "GowinSyn", 92 | "TclPre" : "", 93 | "TopModule" : "top", 94 | "USERCODE" : "default", 95 | "Unused_Pin" : "As_input_tri_stated_with_pull_up", 96 | "Update_Compile_Point_Timing_Data" : false, 97 | "Use_Clock_Period_for_Unconstrainted IO" : false, 98 | "VCCAUX" : 3.3, 99 | "VCCX" : "3.3", 100 | "VHDL_Standard" : "VHDL_Std_1993", 101 | "Verilog_Standard" : "Vlg_Std_Sysv2017", 102 | "WAKE_UP" : "0", 103 | "Write_Vendor_Constraint_File" : true, 104 | "show_all_warnings" : true, 105 | "turn_off_bg" : false 106 | } -------------------------------------------------------------------------------- /boards/a2n20v2/README.md: -------------------------------------------------------------------------------- 1 | # A2N20v2 Card 2 | 3 |

4 | 5 |

6 | 7 | This is the project version that builds the FPGA bitstream for the 8 | [Tang Nano 20K](https://wiki.sipeed.com/hardware/en/tang/tang-nano-20k/nano-20k.html) 9 | version of the A2FPGA Apple II card. 10 | 11 | The A2N20v2 version supports Apple II, //e, and IIgs models. The v2 card uses a 100-pin 12 | "a2bridge" CPLD that captures and level-shifts all Apple II, //e, and IIgs signals including the 13 | M2SEL and M2B0 signals necessary for interfacing to the IIgs bus. 14 | 15 | [A2N20v2 Schematics](sch/a2n20v2.pdf) 16 | 17 | It supports all graphics modes on all Apple II models, although software written 18 | for //e double-hires will not usually run on a II, nor will IIgs software run on 19 | a II or //e. However, the soft switches and display modes are supported on all 20 | models for software you write yourself. 21 | 22 | The A2N20v2 has a 4-switch DIP switch that controls the following settings: 23 | 24 | 1. Enable Scanline effect when set to on 25 | 2. Enable Apple II speaker sounds via HDMI when set to on 26 | 3. Power-on-Reset Hold - Delay Apple II start-up until FPGA is initialized and running 27 | 4. Apple IIgs - Set to on when installed in an Apple IIgs 28 | 29 | For ROM 00/01 IIgs models (such as the Woz edition), the A2N20v2 must be placed in Slot 3. For ROM 03 models, it should work in any slot. This is because it requires the M2B0 signal which is only present in Slot 3 of the original IIgs models, but which is present in slots 1 to size of the ROM 03 model. 30 | 31 | To update the bitstream on the A2N20v2, the most convenient way is to use [OpenFPGALoader](https://github.com/trabucayre/openFPGALoader) 32 | Mac users with [Homebrew](https://brew.sh/) can just type `brew install openfpgaloader` in the Terminal to install it 33 | Use OpenFPGALoader to program the Tang Nano 20K board via USB with the [a2n20v2.fs](impl/pnr/a2n20v2.fs) bistream file and run `openfpgaloader -b tangnano20k -f a2n20v2.fs` 34 | 35 | The project can also be opened and built with the Gowin IDE, either educational 36 | or commercial editions. Use the `a2n20v2.gprj` file in this folder. 37 | 38 | Note: When using the Gowin IDE, do not add or remove files from the project or it will 39 | turn the relative file paths into absolute file paths. 40 | -------------------------------------------------------------------------------- /boards/a2n20v2/hdl/a2n20v2.cst: -------------------------------------------------------------------------------- 1 | // Nano 9K Clock & RC Power-On-Reset/Button S1 2 | IO_LOC "clk" 4; 3 | 4 | //IO_LOC "clk_1" 10; 5 | //IO_LOC "clk_2" 11; 6 | //IO_LOC "clk_3" 13; 7 | 8 | IO_LOC "s1" 88; 9 | IO_PORT "s1" PULL_MODE=NONE; 10 | 11 | IO_LOC "s2" 87; 12 | IO_PORT "s2" PULL_MODE=NONE; 13 | 14 | // Nano 20K UART 15 | 16 | IO_LOC "uart_tx" 69; 17 | IO_PORT "uart_tx" IO_TYPE=LVCMOS33 PULL_MODE=UP; 18 | 19 | IO_LOC "uart_rx" 70; 20 | IO_PORT "uart_rx" IO_TYPE=LVCMOS33 PULL_MODE=UP; 21 | 22 | // Nano 20K HDMI 23 | 24 | IO_LOC "tmds_clk_p" 33,34; 25 | IO_PORT "tmds_clk_p" IO_TYPE=LVCMOS33D PULL_MODE=NONE DRIVE=8; 26 | 27 | IO_LOC "tmds_d_p[0]" 35,36; 28 | IO_PORT "tmds_d_p[0]" IO_TYPE=LVCMOS33D PULL_MODE=NONE DRIVE=8; 29 | 30 | IO_LOC "tmds_d_p[1]" 37,38; 31 | IO_PORT "tmds_d_p[1]" IO_TYPE=LVCMOS33D PULL_MODE=NONE DRIVE=8; 32 | 33 | IO_LOC "tmds_d_p[2]" 39,40; 34 | IO_PORT "tmds_d_p[2]" IO_TYPE=LVCMOS33D PULL_MODE=NONE DRIVE=8; 35 | 36 | // Nano 20K LEDs (renumbered, using led[0] for reset) 37 | 38 | IO_LOC "led[4]" 20; 39 | IO_PORT "led[4]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 40 | 41 | IO_LOC "led[3]" 19; 42 | IO_PORT "led[3]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 43 | 44 | IO_LOC "led[2]" 18; 45 | IO_PORT "led[2]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 46 | 47 | IO_LOC "led[1]" 17; 48 | IO_PORT "led[1]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 49 | 50 | IO_LOC "led[0]" 16; 51 | IO_PORT "led[0]" IO_TYPE=LVCMOS33 PULL_MODE=UP DRIVE=8; 52 | 53 | // A2N20 GPIO 54 | 55 | IO_LOC "a2_phi1" 31; 56 | IO_PORT "a2_phi1" IO_TYPE=LVCMOS33; 57 | 58 | IO_LOC "a2_7M" 73; 59 | IO_PORT "a2_7M" IO_TYPE=LVCMOS33; 60 | 61 | IO_LOC "a2_bridge_rd_n" 74; 62 | IO_PORT "a2_bridge_rd_n" IO_TYPE=LVCMOS33; 63 | 64 | IO_LOC "a2_reset_n" 15; 65 | IO_PORT "a2_reset_n" IO_TYPE=LVCMOS33; 66 | 67 | IO_LOC "a2_bridge_sel[1]" 29; 68 | IO_PORT "a2_bridge_sel[1]" IO_TYPE=LVCMOS33; 69 | 70 | IO_LOC "a2_bridge_bus_a_oe_n" 27; 71 | IO_PORT "a2_bridge_bus_a_oe_n" IO_TYPE=LVCMOS33; 72 | 73 | IO_LOC "a2_bridge_sel[0]" 30; 74 | IO_PORT "a2_bridge_sel[0]" IO_TYPE=LVCMOS33; 75 | 76 | IO_LOC "a2_bridge_bus_d_oe_n" 77; 77 | IO_PORT "a2_bridge_bus_d_oe_n" IO_TYPE=LVCMOS33; 78 | 79 | IO_LOC "a2_bridge_sel[2]" 28; 80 | IO_PORT "a2_bridge_sel[2]" IO_TYPE=LVCMOS33; 81 | 82 | IO_LOC "a2_bridge_d[7]" 42; 83 | IO_PORT "a2_bridge_d[7]" IO_TYPE=LVCMOS33; 84 | 85 | IO_LOC "a2_bridge_d[6]" 41; 86 | IO_PORT "a2_bridge_d[6]" IO_TYPE=LVCMOS33; 87 | 88 | IO_LOC "a2_bridge_d[5]" 56; 89 | IO_PORT "a2_bridge_d[5]" IO_TYPE=LVCMOS33; 90 | 91 | IO_LOC "a2_bridge_d[4]" 54; 92 | IO_PORT "a2_bridge_d[4]" IO_TYPE=LVCMOS33; 93 | 94 | IO_LOC "a2_bridge_d[3]" 48; 95 | IO_PORT "a2_bridge_d[3]" IO_TYPE=LVCMOS33; 96 | 97 | IO_LOC "a2_bridge_d[2]" 55; 98 | IO_PORT "a2_bridge_d[2]" IO_TYPE=LVCMOS33; 99 | 100 | IO_LOC "a2_bridge_d[1]" 49; 101 | IO_PORT "a2_bridge_d[1]" IO_TYPE=LVCMOS33; 102 | 103 | IO_LOC "a2_bridge_d[0]" 72; 104 | IO_PORT "a2_bridge_d[0]" IO_TYPE=LVCMOS33; 105 | 106 | IO_LOC "a2_bridge_wr_n" 71; 107 | IO_PORT "a2_bridge_wr_n" IO_TYPE=LVCMOS33; 108 | 109 | 110 | -------------------------------------------------------------------------------- /boards/a2n20v2/hdl/a2n20v2.sdc: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 GOWIN Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: Timing Constraints file 4 | //GOWIN Version: 1.9.8.11 Education 5 | //Created Time: 2023-06-02 16:47:45 6 | 7 | create_clock -name clk -period 37.037 -waveform {0 18.518} [get_ports {clk}] -add 8 | 9 | create_generated_clock -name clk_logic -source [get_ports {clk}] -master_clock clk -divide_by 1 -multiply_by 2 -add [get_nets {clk_logic_w}] 10 | create_generated_clock -name clk_pixel -source [get_nets {clk_logic_w}] -master_clock clk_logic -divide_by 2 -multiply_by 1 -add [get_nets {clk_pixel_w}] 11 | create_generated_clock -name clk_hdmi -source [get_nets {clk_pixel_w}] -master_clock clk_pixel -divide_by 1 -multiply_by 5 -add [get_nets {clk_hdmi_w}] 12 | -------------------------------------------------------------------------------- /boards/a2n20v2/hdl/gowin/clk_hdmi/clk_hdmi.ipc: -------------------------------------------------------------------------------- 1 | [General] 2 | ipc_version=4 3 | file=clk_hdmi 4 | module=clk_hdmi 5 | target_device=gw2ar18c-000 6 | type=clock_rpll 7 | version=1.0 8 | 9 | [Config] 10 | CKLOUTD3=false 11 | CLKFB_SOURCE=0 12 | CLKIN_FREQ=27 13 | CLKOUTD=false 14 | CLKOUTP=false 15 | CLKOUT_BYPASS=false 16 | CLKOUT_DIVIDE_DYN=true 17 | CLKOUT_FREQ=135 18 | CLKOUT_TOLERANCE=0 19 | DYNAMIC=true 20 | LANG=0 21 | LOCK_EN=true 22 | MODE_GENERAL=true 23 | PLL_PWD=false 24 | RESET_PLL=true 25 | -------------------------------------------------------------------------------- /boards/a2n20v2/hdl/gowin/clk_hdmi/clk_hdmi.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: IP file 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW2AR-LV18QN88C8/I7 6 | //Device: GW2AR-18 7 | //Device Version: C 8 | //Created Time: Fri Jan 19 22:04:22 2024 9 | 10 | module clk_hdmi (clkout, lock, reset, clkin); 11 | 12 | output clkout; 13 | output lock; 14 | input reset; 15 | input clkin; 16 | 17 | wire clkoutp_o; 18 | wire clkoutd_o; 19 | wire clkoutd3_o; 20 | wire gw_gnd; 21 | 22 | assign gw_gnd = 1'b0; 23 | 24 | rPLL rpll_inst ( 25 | .CLKOUT(clkout), 26 | .LOCK(lock), 27 | .CLKOUTP(clkoutp_o), 28 | .CLKOUTD(clkoutd_o), 29 | .CLKOUTD3(clkoutd3_o), 30 | .RESET(reset), 31 | .RESET_P(gw_gnd), 32 | .CLKIN(clkin), 33 | .CLKFB(gw_gnd), 34 | .FBDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 35 | .IDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 36 | .ODSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 37 | .PSDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 38 | .DUTYDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 39 | .FDLY({gw_gnd,gw_gnd,gw_gnd,gw_gnd}) 40 | ); 41 | 42 | defparam rpll_inst.FCLKIN = "27"; 43 | defparam rpll_inst.DYN_IDIV_SEL = "false"; 44 | defparam rpll_inst.IDIV_SEL = 0; 45 | defparam rpll_inst.DYN_FBDIV_SEL = "false"; 46 | defparam rpll_inst.FBDIV_SEL = 4; 47 | defparam rpll_inst.DYN_ODIV_SEL = "false"; 48 | defparam rpll_inst.ODIV_SEL = 4; 49 | defparam rpll_inst.PSDA_SEL = "0000"; 50 | defparam rpll_inst.DYN_DA_EN = "true"; 51 | defparam rpll_inst.DUTYDA_SEL = "1000"; 52 | defparam rpll_inst.CLKOUT_FT_DIR = 1'b1; 53 | defparam rpll_inst.CLKOUTP_FT_DIR = 1'b1; 54 | defparam rpll_inst.CLKOUT_DLY_STEP = 0; 55 | defparam rpll_inst.CLKOUTP_DLY_STEP = 0; 56 | defparam rpll_inst.CLKFB_SEL = "internal"; 57 | defparam rpll_inst.CLKOUT_BYPASS = "false"; 58 | defparam rpll_inst.CLKOUTP_BYPASS = "false"; 59 | defparam rpll_inst.CLKOUTD_BYPASS = "false"; 60 | defparam rpll_inst.DYN_SDIV_SEL = 2; 61 | defparam rpll_inst.CLKOUTD_SRC = "CLKOUT"; 62 | defparam rpll_inst.CLKOUTD3_SRC = "CLKOUT"; 63 | defparam rpll_inst.DEVICE = "GW2AR-18C"; 64 | 65 | endmodule //clk_hdmi 66 | -------------------------------------------------------------------------------- /boards/a2n20v2/hdl/gowin/clk_hdmi/clk_hdmi_tmp.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: Template file for instantiation 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW2AR-LV18QN88C8/I7 6 | //Device: GW2AR-18 7 | //Device Version: C 8 | //Created Time: Fri Jan 19 22:04:22 2024 9 | 10 | //Change the instance name and port connections to the signal names 11 | //--------Copy here to design-------- 12 | 13 | clk_hdmi your_instance_name( 14 | .clkout(clkout_o), //output clkout 15 | .lock(lock_o), //output lock 16 | .reset(reset_i), //input reset 17 | .clkin(clkin_i) //input clkin 18 | ); 19 | 20 | //--------Copy end------------------- 21 | -------------------------------------------------------------------------------- /boards/a2n20v2/hdl/gowin/clk_logic/clk_logic.ipc: -------------------------------------------------------------------------------- 1 | [General] 2 | ipc_version=4 3 | file=clk_logic 4 | module=clk_logic 5 | target_device=gw2ar18c-000 6 | type=clock_rpll 7 | version=1.0 8 | 9 | [Config] 10 | CKLOUTD3=false 11 | CLKFB_SOURCE=0 12 | CLKIN_FREQ=27 13 | CLKOUTD=true 14 | CLKOUTD_BYPASS=false 15 | CLKOUTD_FREQ=27 16 | CLKOUTD_SOURCE_CLKOUT=true 17 | CLKOUTD_TOLERANCE=0 18 | CLKOUTP=true 19 | CLKOUTP_BYPASS=false 20 | CLKOUTP_DUTY_CYCLE=6 21 | CLKOUTP_PHASE=8 22 | CLKOUT_BYPASS=false 23 | CLKOUT_DIVIDE_DYN=true 24 | CLKOUT_FREQ=54 25 | CLKOUT_TOLERANCE=0 26 | DYNAMIC=false 27 | LANG=0 28 | LOCK_EN=true 29 | MODE_GENERAL=true 30 | PLL_PWD=false 31 | RESET_PLL=true 32 | -------------------------------------------------------------------------------- /boards/a2n20v2/hdl/gowin/clk_logic/clk_logic.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: IP file 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW2AR-LV18QN88C8/I7 6 | //Device: GW2AR-18 7 | //Device Version: C 8 | //Created Time: Fri Jan 19 22:03:13 2024 9 | 10 | module clk_logic (clkout, lock, clkoutp, clkoutd, reset, clkin); 11 | 12 | output clkout; 13 | output lock; 14 | output clkoutp; 15 | output clkoutd; 16 | input reset; 17 | input clkin; 18 | 19 | wire clkoutd3_o; 20 | wire gw_vcc; 21 | wire gw_gnd; 22 | 23 | assign gw_vcc = 1'b1; 24 | assign gw_gnd = 1'b0; 25 | 26 | rPLL rpll_inst ( 27 | .CLKOUT(clkout), 28 | .LOCK(lock), 29 | .CLKOUTP(clkoutp), 30 | .CLKOUTD(clkoutd), 31 | .CLKOUTD3(clkoutd3_o), 32 | .RESET(reset), 33 | .RESET_P(gw_gnd), 34 | .CLKIN(clkin), 35 | .CLKFB(gw_gnd), 36 | .FBDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 37 | .IDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 38 | .ODSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 39 | .PSDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 40 | .DUTYDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 41 | .FDLY({gw_vcc,gw_vcc,gw_vcc,gw_vcc}) 42 | ); 43 | 44 | defparam rpll_inst.FCLKIN = "27"; 45 | defparam rpll_inst.DYN_IDIV_SEL = "false"; 46 | defparam rpll_inst.IDIV_SEL = 0; 47 | defparam rpll_inst.DYN_FBDIV_SEL = "false"; 48 | defparam rpll_inst.FBDIV_SEL = 1; 49 | defparam rpll_inst.DYN_ODIV_SEL = "false"; 50 | defparam rpll_inst.ODIV_SEL = 16; 51 | defparam rpll_inst.PSDA_SEL = "1000"; 52 | defparam rpll_inst.DYN_DA_EN = "false"; 53 | defparam rpll_inst.DUTYDA_SEL = "1000"; 54 | defparam rpll_inst.CLKOUT_FT_DIR = 1'b1; 55 | defparam rpll_inst.CLKOUTP_FT_DIR = 1'b1; 56 | defparam rpll_inst.CLKOUT_DLY_STEP = 0; 57 | defparam rpll_inst.CLKOUTP_DLY_STEP = 0; 58 | defparam rpll_inst.CLKFB_SEL = "internal"; 59 | defparam rpll_inst.CLKOUT_BYPASS = "false"; 60 | defparam rpll_inst.CLKOUTP_BYPASS = "false"; 61 | defparam rpll_inst.CLKOUTD_BYPASS = "false"; 62 | defparam rpll_inst.DYN_SDIV_SEL = 2; 63 | defparam rpll_inst.CLKOUTD_SRC = "CLKOUT"; 64 | defparam rpll_inst.CLKOUTD3_SRC = "CLKOUT"; 65 | defparam rpll_inst.DEVICE = "GW2AR-18C"; 66 | 67 | endmodule //clk_logic 68 | -------------------------------------------------------------------------------- /boards/a2n20v2/hdl/gowin/clk_logic/clk_logic_tmp.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: Template file for instantiation 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW2AR-LV18QN88C8/I7 6 | //Device: GW2AR-18 7 | //Device Version: C 8 | //Created Time: Fri Jan 19 22:03:13 2024 9 | 10 | //Change the instance name and port connections to the signal names 11 | //--------Copy here to design-------- 12 | 13 | clk_logic your_instance_name( 14 | .clkout(clkout_o), //output clkout 15 | .lock(lock_o), //output lock 16 | .clkoutp(clkoutp_o), //output clkoutp 17 | .clkoutd(clkoutd_o), //output clkoutd 18 | .reset(reset_i), //input reset 19 | .clkin(clkin_i) //input clkin 20 | ); 21 | 22 | //--------Copy end------------------- 23 | -------------------------------------------------------------------------------- /boards/a2n20v2/impl/a2n20v2_process_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "BACKGROUND_PROGRAMMING" : "off", 3 | "COMPRESS" : false, 4 | "CPU" : false, 5 | "CRC_CHECK" : true, 6 | "Clock_Route_Order" : 0, 7 | "Correct_Hold_Violation" : true, 8 | "DONE" : false, 9 | "DOWNLOAD_SPEED" : "default", 10 | "Disable_Insert_Pad" : false, 11 | "ENABLE_CTP" : false, 12 | "ENABLE_MERGE_MODE" : false, 13 | "ENCRYPTION_KEY" : false, 14 | "ENCRYPTION_KEY_TEXT" : "00000000000000000000000000000000", 15 | "ERROR_DECTION_AND_CORRECTION" : false, 16 | "ERROR_DECTION_ONLY" : false, 17 | "ERROR_INJECTION" : false, 18 | "EXTERNAL_MASTER_CONFIG_CLOCK" : false, 19 | "Enable_DSRM" : false, 20 | "FORMAT" : "binary", 21 | "FREQUENCY_DIVIDER" : "", 22 | "Generate_Constraint_File_of_Ports" : false, 23 | "Generate_IBIS_File" : false, 24 | "Generate_Plain_Text_Timing_Report" : false, 25 | "Generate_Post_PNR_Simulation_Model_File" : false, 26 | "Generate_Post_Place_File" : false, 27 | "Generate_SDF_File" : false, 28 | "Generate_VHDL_Post_PNR_Simulation_Model_File" : false, 29 | "Global_Freq" : "default", 30 | "GwSyn_Loop_Limit" : 2000, 31 | "HOTBOOT" : false, 32 | "I2C" : false, 33 | "I2C_SLAVE_ADDR" : "00", 34 | "IncludePath" : [ 35 | 36 | ], 37 | "Incremental_Compile" : "", 38 | "Initialize_Primitives" : false, 39 | "JTAG" : false, 40 | "MODE_IO" : false, 41 | "MSPI" : true, 42 | "MSPI_JUMP" : false, 43 | "MULTIBOOT_ADDRESS_WIDTH" : "24", 44 | "MULTIBOOT_MODE" : "Normal", 45 | "MULTIBOOT_SPI_FLASH_ADDRESS" : "00000000", 46 | "MULTIJUMP_ADDRESS_WIDTH" : "24", 47 | "MULTIJUMP_MODE" : "Normal", 48 | "MULTIJUMP_SPI_FLASH_ADDRESS" : "000000", 49 | "Multi_Boot" : true, 50 | "OUTPUT_BASE_NAME" : "a2n20v2", 51 | "POWER_ON_RESET_MONITOR" : true, 52 | "PRINT_BSRAM_VALUE" : true, 53 | "PROGRAM_DONE_BYPASS" : false, 54 | "PlaceInRegToIob" : true, 55 | "PlaceIoRegToIob" : true, 56 | "PlaceOutRegToIob" : true, 57 | "Place_Option" : "0", 58 | "Process_Configuration_Verion" : "1.0", 59 | "Promote_Physical_Constraint_Warning_to_Error" : true, 60 | "READY" : false, 61 | "RECONFIG_N" : false, 62 | "Ram_RW_Check" : true, 63 | "Replicate_Resources" : false, 64 | "Report_Auto-Placed_Io_Information" : false, 65 | "Route_Maxfan" : 23, 66 | "Route_Option" : "1", 67 | "Run_Timing_Driven" : true, 68 | "SECURE_MODE" : false, 69 | "SECURITY_BIT" : true, 70 | "SEU_HANDLER" : false, 71 | "SEU_HANDLER_CHECKSUM" : false, 72 | "SEU_HANDLER_MODE" : "auto", 73 | "SSPI" : true, 74 | "STOP_SEU_HANDLER" : false, 75 | "Show_All_Warnings" : false, 76 | "Synthesize_tool" : "GowinSyn", 77 | "TclPre" : "", 78 | "TopModule" : "top", 79 | "USERCODE" : "default", 80 | "Unused_Pin" : "As_input_tri_stated_with_pull_up", 81 | "VCCAUX" : 3.3, 82 | "VCCX" : "3.3", 83 | "VHDL_Standard" : "VHDL_Std_1993", 84 | "Verilog_Standard" : "Vlg_Std_Sysv2017", 85 | "WAKE_UP" : "0", 86 | "show_all_warnings" : true, 87 | "turn_off_bg" : false 88 | } -------------------------------------------------------------------------------- /boards/a2n20v2/impl/pnr/a2n20v2.tr.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Timing Analysis Report 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /boards/a2n20v2/impl/pnr/device.cfg: -------------------------------------------------------------------------------- 1 | set JTAG regular_io = false 2 | set SSPI regular_io = true 3 | set MSPI regular_io = true 4 | set READY regular_io = false 5 | set DONE regular_io = false 6 | set I2C regular_io = false 7 | set RECONFIG_N regular_io = false 8 | set CRC_check = true 9 | set compress = false 10 | set encryption = false 11 | set security_bit_enable = true 12 | set bsram_init_fuse_print = true 13 | set background_programming = off 14 | set secure_mode = false 15 | set program_done_bypass = false 16 | set wake_up = 0 17 | set format = binary 18 | set power_on_reset_monitor = true 19 | set multiboot_spi_flash_address = 0x00000000 20 | set vccx = 3.3 21 | set vcc = 1.0 22 | set unused_pin = default 23 | -------------------------------------------------------------------------------- /boards/a2n20v2/impl/project_process_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Allow_Duplicate_Modules" : false, 3 | "Annotated_Properties_for_Analyst" : true, 4 | "BACKGROUND_PROGRAMMING" : "off", 5 | "CMSER" : false, 6 | "CMSER_CHECKSUM" : false, 7 | "CMSER_MODE" : "auto", 8 | "COMPRESS" : false, 9 | "CPU" : false, 10 | "CRC_CHECK" : true, 11 | "Clock_Conversion" : true, 12 | "Clock_Route_Order" : 0, 13 | "Correct_Hold_Violation" : true, 14 | "DONE" : false, 15 | "DOWNLOAD_SPEED" : "default", 16 | "Default_Enum_Encoding" : "default", 17 | "Disable_Insert_Pad" : false, 18 | "ENABLE_MERGE_MODE" : false, 19 | "ENCRYPTION_KEY" : false, 20 | "ENCRYPTION_KEY_TEXT" : "00000000000000000000000000000000", 21 | "ERROR_DECTION_AND_CORRECTION" : false, 22 | "ERROR_DECTION_ONLY" : false, 23 | "ERROR_INJECTION" : false, 24 | "EXTERNAL_MASTER_CONFIG_CLOCK" : false, 25 | "FORMAT" : "binary", 26 | "FREQUENCY_DIVIDER" : "", 27 | "FSM Compiler" : true, 28 | "Fanout_Guide" : 10000, 29 | "Frequency" : "Auto", 30 | "Generate_Constraint_File_of_Ports" : false, 31 | "Generate_IBIS_File" : false, 32 | "Generate_Plain_Text_Timing_Report" : false, 33 | "Generate_Post_PNR_Simulation_Model_File" : false, 34 | "Generate_Post_Place_File" : false, 35 | "Generate_SDF_File" : false, 36 | "Generate_VHDL_Post_PNR_Simulation_Model_File" : false, 37 | "GwSyn_Loop_Limit" : 2000, 38 | "HOTBOOT" : false, 39 | "I2C" : false, 40 | "I2C_SLAVE_ADDR" : "00", 41 | "Implicit_Initial_Value_Support" : false, 42 | "IncludePath" : [ 43 | 44 | ], 45 | "Incremental_Compile" : "", 46 | "Initialize_Primitives" : false, 47 | "JTAG" : false, 48 | "MODE_IO" : false, 49 | "MSPI" : true, 50 | "MSPI_JUMP" : false, 51 | "MULTIBOOT_ADDRESS_WIDTH" : "24", 52 | "MULTIBOOT_MODE" : "Normal", 53 | "MULTIBOOT_SPI_FLASH_ADDRESS" : "00000000", 54 | "MULTIJUMP_ADDRESS_WIDTH" : "24", 55 | "MULTIJUMP_MODE" : "Normal", 56 | "MULTIJUMP_SPI_FLASH_ADDRESS" : "000000", 57 | "Multi_Boot" : true, 58 | "Multiple_File_Compilation_Unit" : true, 59 | "Number_of_Critical_Paths" : "", 60 | "Number_of_Start/End_Points" : "", 61 | "OSC_DIVIDER" : "8", 62 | "OUTPUT_BASE_NAME" : "a2n20v2", 63 | "POWER_ON_RESET_MONITOR" : true, 64 | "PRINT_BSRAM_VALUE" : true, 65 | "PROGRAM_DONE_BYPASS" : false, 66 | "Pipelining" : true, 67 | "PlaceInRegToIob" : true, 68 | "PlaceIoRegToIob" : true, 69 | "PlaceOutRegToIob" : true, 70 | "Place_Option" : "0", 71 | "Process_Configuration_Verion" : "1.0", 72 | "Promote_Physical_Constraint_Warning_to_Error" : true, 73 | "Push_Tristates" : true, 74 | "READY" : false, 75 | "RECONFIG_N" : false, 76 | "Ram_RW_Check" : true, 77 | "Replicate_Resources" : false, 78 | "Report_Auto-Placed_Io_Information" : false, 79 | "Resolve_Mixed_Drivers" : false, 80 | "Resource_Sharing" : true, 81 | "Retiming" : false, 82 | "Route_Maxfan" : 23, 83 | "Route_Option" : "1", 84 | "Run_Timing_Driven" : true, 85 | "SECURE_MODE" : false, 86 | "SECURITY_BIT" : true, 87 | "SSPI" : true, 88 | "STOP_CMSER" : false, 89 | "Show_All_Warnings" : false, 90 | "Synthesis On/Off Implemented as Translate On/Off" : false, 91 | "Synthesize_tool" : "GowinSyn", 92 | "TclPre" : "", 93 | "TopModule" : "top", 94 | "USERCODE" : "default", 95 | "Unused_Pin" : "As_input_tri_stated_with_pull_up", 96 | "Update_Compile_Point_Timing_Data" : false, 97 | "Use_Clock_Period_for_Unconstrainted IO" : false, 98 | "VCCAUX" : 3.3, 99 | "VCCX" : "3.3", 100 | "VHDL_Standard" : "VHDL_Std_1993", 101 | "Verilog_Standard" : "Vlg_Std_Sysv2017", 102 | "WAKE_UP" : "0", 103 | "Write_Vendor_Constraint_File" : true, 104 | "show_all_warnings" : true, 105 | "turn_off_bg" : false 106 | } -------------------------------------------------------------------------------- /boards/a2n20v2/photos/a2n20v2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a2fpga/a2fpga_core/20291afa7f7f9e438615e2cbe1d8e29de5e1f835/boards/a2n20v2/photos/a2n20v2.png -------------------------------------------------------------------------------- /boards/a2n20v2/sch/a2n20v2.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a2fpga/a2fpga_core/20291afa7f7f9e438615e2cbe1d8e29de5e1f835/boards/a2n20v2/sch/a2n20v2.pdf -------------------------------------------------------------------------------- /boards/a2n9/README.md: -------------------------------------------------------------------------------- 1 | # A2N9 Card 2 | 3 |

4 | 5 |

6 | 7 | This is the project version that builds the FPGA bitstream for the 8 | [Tang Nano 9K](https://wiki.sipeed.com/hardware/en/tang/Tang-Nano-9K/Nano-9K.html) 9 | version of the A2FPGA Apple II card. 10 | 11 | The A2N9 version only supports Apple II and //e models. The card will not 12 | work correctly in a IIgs. It uses discrete 74* series logic to interface 13 | and level-shift the necessary Apple II bus signals to the FPGA module. 14 | 15 | [A2N9 Schematics](sch/a2n9.pdf) 16 | 17 | The A2N9 does the build have support for IIgs graphics modes. However all II and //e modes and 18 | soft switches are supported on any II or //e model even those most software will not use //e 19 | features on non-//e models. 20 | 21 | It also does not have the SuperSprite capability included. 22 | 23 | To update the bitstream on the A2N9, the most convenient way is to use [OpenFPGALoader](https://github.com/trabucayre/openFPGALoader) 24 | Mac users with [Homebrew](https://brew.sh/) can just type `brew install openfpgaloader` in the Terminal to install it 25 | Use OpenFPGALoader to program the Tang Nano 9K board via USB with the [a2n9.fs](impl/pnr/a2n9.fs) bistream file and run `openfpgaloader -b tangnano9k -f a2n9.fs` 26 | 27 | The project can also be opened and built with the Gowin IDE, either educational 28 | or commercial editions. Use the `a2n9.gprj` file in this folder. 29 | 30 | Note: When using the Gowin IDE, do not add or remove files from the project or it will 31 | turn the relative file paths into absolute file paths. 32 | 33 | -------------------------------------------------------------------------------- /boards/a2n9/a2n9.gprj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 5 6 | gw1nr9c-004 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /boards/a2n9/hdl/a2n9.cst: -------------------------------------------------------------------------------- 1 | // Nano 9K Clock & RC Power-On-Reset/Button S1 2 | 3 | IO_LOC "clk" 52; 4 | IO_PORT "clk" IO_TYPE=LVCMOS33; 5 | 6 | IO_LOC "rst_n" 4; 7 | IO_PORT "rst_n" IO_TYPE=LVCMOS18; 8 | 9 | IO_LOC "button" 3; 10 | IO_PORT "button" PULL_MODE=UP; 11 | 12 | // Nano 9K UART 13 | 14 | IO_LOC "uart_tx" 17; 15 | IO_PORT "uart_tx" IO_TYPE=LVCMOS33 PULL_MODE=UP; 16 | 17 | IO_LOC "uart_rx" 18; 18 | IO_PORT "uart_rx" IO_TYPE=LVCMOS33 PULL_MODE=UP; 19 | 20 | // Nano 9K SPI Flash 21 | 22 | IO_LOC "spi_clk" 59; 23 | IO_PORT "spi_clk" IO_TYPE=LVCMOS33; 24 | 25 | IO_LOC "spi_cs_n" 60; 26 | IO_PORT "spi_cs_n" IO_TYPE=LVCMOS33; 27 | 28 | IO_LOC "spi_miso" 62; 29 | IO_PORT "spi_miso" IO_TYPE=LVCMOS33; 30 | 31 | IO_LOC "spi_mosi" 61; 32 | IO_PORT "spi_mosi" IO_TYPE=LVCMOS33; 33 | 34 | // Nano 9K HDMI 35 | 36 | IO_LOC "tmds_clk_p" 69,68; 37 | IO_PORT "tmds_clk_p" IO_TYPE=LVCMOS33D; 38 | 39 | IO_LOC "tmds_d_p[0]" 71,70; 40 | IO_PORT "tmds_d_p[0]" IO_TYPE=LVCMOS33D; 41 | 42 | IO_LOC "tmds_d_p[1]" 73,72; 43 | IO_PORT "tmds_d_p[1]" IO_TYPE=LVCMOS33D; 44 | 45 | IO_LOC "tmds_d_p[2]" 75,74; 46 | IO_PORT "tmds_d_p[2]" IO_TYPE=LVCMOS33D; 47 | 48 | // Nano 9K LEDs 49 | 50 | IO_LOC "led[5]" 16; 51 | IO_PORT "led[5]" PULL_MODE=UP DRIVE=8; 52 | 53 | IO_LOC "led[4]" 15; 54 | IO_PORT "led[4]" PULL_MODE=UP DRIVE=8; 55 | 56 | IO_LOC "led[3]" 14; 57 | IO_PORT "led[3]" PULL_MODE=UP DRIVE=8; 58 | 59 | IO_LOC "led[2]" 13; 60 | IO_PORT "led[2]" PULL_MODE=UP DRIVE=8; 61 | 62 | IO_LOC "led[1]" 11; 63 | IO_PORT "led[1]" PULL_MODE=UP DRIVE=8; 64 | 65 | IO_LOC "led[0]" 10; 66 | IO_PORT "led[0]" PULL_MODE=UP DRIVE=8; 67 | 68 | // Nano 9K SD Card Select/A2N9 A2 Bus Enable 69 | // '0' to select SD Card, 'x' or '0' to disable A2 Bus, '1' to enable A2 Bus 70 | IO_LOC "a2_bus_oe" 38; 71 | IO_PORT "a2_bus_oe" IO_TYPE=LVCMOS33; 72 | 73 | // A2N9 GPIO 74 | 75 | IO_LOC "a2_a_dir" 76; 76 | IO_PORT "a2_a_dir" IO_TYPE=LVCMOS33; 77 | 78 | IO_LOC "a2_d_dir" 63; 79 | IO_PORT "a2_d_dir" IO_TYPE=LVCMOS33; 80 | 81 | IO_LOC "a2_dma_n" 86; 82 | IO_PORT "a2_dma_n" IO_TYPE=LVCMOS18 PULL_MODE=UP; 83 | 84 | IO_LOC "a2_irq_n" 85; 85 | IO_PORT "a2_irq_n" IO_TYPE=LVCMOS18 PULL_MODE=UP; 86 | 87 | IO_LOC "a2_rdy_n" 84; 88 | IO_PORT "a2_rdy_n" IO_TYPE=LVCMOS18 PULL_MODE=UP; 89 | 90 | IO_LOC "a2_reset_n" 83; 91 | IO_PORT "a2_reset_n" IO_TYPE=LVCMOS18 PULL_MODE=UP; 92 | 93 | IO_LOC "a2_inh_n" 82; 94 | IO_PORT "a2_inh_n" IO_TYPE=LVCMOS18 PULL_MODE=UP; 95 | 96 | IO_LOC "a2_rw_n" 81; 97 | IO_PORT "a2_rw_n" IO_TYPE=LVCMOS18 PULL_MODE=UP; 98 | 99 | IO_LOC "a2_sync_n" 80; 100 | IO_PORT "a2_sync_n" IO_TYPE=LVCMOS18 PULL_MODE=UP; 101 | 102 | IO_LOC "a2_color_ref" 79; 103 | IO_PORT "a2_color_ref" IO_TYPE=LVCMOS33; 104 | 105 | IO_LOC "a2_phi1" 77; 106 | IO_PORT "a2_phi1" IO_TYPE=LVCMOS33; 107 | 108 | IO_LOC "a2_7M" 35; 109 | IO_PORT "a2_7M" IO_TYPE=LVCMOS33; 110 | 111 | IO_LOC "a2_d[0]" 29; 112 | IO_PORT "a2_d[0]" IO_TYPE=LVCMOS33; 113 | 114 | IO_LOC "a2_d[1]" 28; 115 | IO_PORT "a2_d[1]" IO_TYPE=LVCMOS33; 116 | 117 | IO_LOC "a2_d[2]" 27; 118 | IO_PORT "a2_d[2]" IO_TYPE=LVCMOS33; 119 | 120 | IO_LOC "a2_d[3]" 26; 121 | IO_PORT "a2_d[3]" IO_TYPE=LVCMOS33; 122 | 123 | IO_LOC "a2_d[4]" 25; 124 | IO_PORT "a2_d[4]" IO_TYPE=LVCMOS33; 125 | 126 | IO_LOC "a2_d[5]" 39; 127 | IO_PORT "a2_d[5]" IO_TYPE=LVCMOS33; 128 | 129 | IO_LOC "a2_d[6]" 36; 130 | IO_PORT "a2_d[6]" IO_TYPE=LVCMOS33; 131 | 132 | IO_LOC "a2_d[7]" 37; 133 | IO_PORT "a2_d[7]" IO_TYPE=LVCMOS33; 134 | 135 | IO_LOC "a2_a[0]" 57; 136 | IO_PORT "a2_a[0]" IO_TYPE=LVCMOS33; 137 | 138 | IO_LOC "a2_a[1]" 32; 139 | IO_PORT "a2_a[1]" IO_TYPE=LVCMOS33; 140 | 141 | IO_LOC "a2_a[2]" 56; 142 | IO_PORT "a2_a[2]" IO_TYPE=LVCMOS33; 143 | 144 | IO_LOC "a2_a[3]" 31; 145 | IO_PORT "a2_a[3]" IO_TYPE=LVCMOS33; 146 | 147 | IO_LOC "a2_a[4]" 55; 148 | IO_PORT "a2_a[4]" IO_TYPE=LVCMOS33; 149 | 150 | IO_LOC "a2_a[5]" 49; 151 | IO_PORT "a2_a[5]" IO_TYPE=LVCMOS33; 152 | 153 | IO_LOC "a2_a[6]" 54; 154 | IO_PORT "a2_a[6]" IO_TYPE=LVCMOS33; 155 | 156 | IO_LOC "a2_a[7]" 48; 157 | IO_PORT "a2_a[7]" IO_TYPE=LVCMOS33; 158 | 159 | IO_LOC "a2_a[8]" 53; 160 | IO_PORT "a2_a[8]" IO_TYPE=LVCMOS33; 161 | 162 | IO_LOC "a2_a[9]" 51; 163 | IO_PORT "a2_a[9]" IO_TYPE=LVCMOS33; 164 | 165 | IO_LOC "a2_a[10]" 42; 166 | IO_PORT "a2_a[10]" IO_TYPE=LVCMOS33; 167 | 168 | IO_LOC "a2_a[11]" 41; 169 | IO_PORT "a2_a[11]" IO_TYPE=LVCMOS33; 170 | 171 | IO_LOC "a2_a[12]" 40; 172 | IO_PORT "a2_a[12]" IO_TYPE=LVCMOS33; 173 | 174 | IO_LOC "a2_a[13]" 34; 175 | IO_PORT "a2_a[13]" IO_TYPE=LVCMOS33; 176 | 177 | IO_LOC "a2_a[14]" 33; 178 | IO_PORT "a2_a[14]" IO_TYPE=LVCMOS33; 179 | 180 | IO_LOC "a2_a[15]" 30; 181 | IO_PORT "a2_a[15]" IO_TYPE=LVCMOS33; 182 | 183 | -------------------------------------------------------------------------------- /boards/a2n9/hdl/a2n9.sdc: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 GOWIN Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: Timing Constraints file 4 | //GOWIN Version: 1.9.8.11 Education 5 | //Created Time: 2023-06-02 16:47:45 6 | 7 | create_clock -name clk -period 37.037 -waveform {0 18.518} [get_ports {clk}] -add 8 | 9 | create_generated_clock -name clk_logic -source [get_ports {clk}] -master_clock clk -divide_by 1 -multiply_by 2 -add [get_nets {clk_logic_w}] 10 | create_generated_clock -name clk_pixel -source [get_nets {clk_logic_w}] -master_clock clk_logic -divide_by 2 -multiply_by 1 -add [get_nets {clk_pixel_w}] 11 | create_generated_clock -name clk_hdmi -source [get_nets {clk_pixel_w}] -master_clock clk_pixel -divide_by 1 -multiply_by 5 -add [get_nets {clk_hdmi_w}] 12 | 13 | -------------------------------------------------------------------------------- /boards/a2n9/hdl/bus/apple_bus.sv: -------------------------------------------------------------------------------- 1 | // A2N9 - Apple II Bus Interface 2 | // 3 | // (c) 2023,2024 Ed Anuff 4 | // 5 | // Permission to use, copy, modify, and/or distribute this software for any 6 | // purpose with or without fee is hereby granted, provided that the above 7 | // copyright notice and this permission notice appear in all copies. 8 | // 9 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | // 17 | // Description: 18 | // 19 | // Interface with the Apple II Bus and sample the address and data lines 20 | // at specific timings per the Apple II bus timing diagram in 21 | // The Apple II Circuit Description. 22 | // Hold the address, data, and control lines until the next sample. 23 | // Provide control strobes that indicate when these values have been 24 | // sampled. 25 | // 26 | 27 | module apple_bus #( 28 | parameter int CLOCK_SPEED_HZ = 50_000_000, 29 | parameter int APPLE_HZ = 14_318_181, 30 | parameter int CPU_HZ = APPLE_HZ / 14, // 1_022_727 31 | parameter int CYCLE_COUNT = CLOCK_SPEED_HZ / CPU_HZ, // 49 32 | parameter int PHASE_COUNT = CYCLE_COUNT / 2, // 24 33 | parameter int READ_COUNT = CYCLE_COUNT / 3, // 16 34 | parameter int WRITE_COUNT = CYCLE_COUNT / 5 // 10 35 | ) ( 36 | a2bus_if.master a2bus_if, 37 | 38 | input [15:0] a2_a_i, 39 | input [7:0] a2_d_i, 40 | input a2_rw_n_i, 41 | 42 | output sleep_o 43 | 44 | ); 45 | 46 | assign a2bus_if.sw_gs = 1'b0; 47 | assign a2bus_if.m2sel_n = 1'b0; 48 | assign a2bus_if.m2b0 = 1'b0; 49 | 50 | 51 | // data and address latches on input 52 | reg [15:0] addr_r; 53 | reg [7:0] data_r; 54 | reg rw_n_r; 55 | 56 | assign a2bus_if.addr = addr_r; 57 | assign a2bus_if.data = data_r; 58 | assign a2bus_if.rw_n = rw_n_r; 59 | 60 | reg [5:0] phase_cycles_r = 0; 61 | assign sleep_o = phase_cycles_r == 6'b111111; 62 | 63 | always @(posedge a2bus_if.clk_logic) begin 64 | 65 | // capture phase transtitions and count cycles 66 | if (a2bus_if.phi1_posedge || a2bus_if.phi1_negedge) begin 67 | phase_cycles_r <= 6'b0; 68 | end else if (phase_cycles_r != 6'b111111) begin 69 | phase_cycles_r <= phase_cycles_r + 1'b1; 70 | end 71 | 72 | end 73 | 74 | // tuned bus timings 75 | 76 | // sample address from bus at 350ns from Phi1 rising edge 77 | wire a2_addr_in_start_w = a2bus_if.phi1 && (phase_cycles_r == 18); 78 | 79 | always @(posedge a2bus_if.clk_logic) begin 80 | 81 | if (a2_addr_in_start_w) begin 82 | addr_r <= a2_a_i; 83 | rw_n_r <= a2_rw_n_i; 84 | end 85 | 86 | end 87 | 88 | // sample data from bus at 419ns from Phi0 rising edge 89 | // /CAS goes high 90 | // tuned to 300ns from Phi0 rising edge (15 cycles) 91 | wire a2_data_in_valid_w = a2bus_if.phi0 && (phase_cycles_r == 15); 92 | //wire a2_data_in_start_w = a2_data_in_valid_w && !rw_n_r; 93 | reg data_in_strobe_r; 94 | 95 | always @(posedge a2bus_if.clk_logic) begin 96 | data_in_strobe_r <= 1'b0; 97 | if (a2_data_in_valid_w) begin 98 | if (!rw_n_r) data_r <= a2_d_i; 99 | data_in_strobe_r <= 1'b1; 100 | end 101 | 102 | end 103 | 104 | assign a2bus_if.data_in_strobe = data_in_strobe_r; 105 | 106 | 107 | endmodule 108 | -------------------------------------------------------------------------------- /boards/a2n9/hdl/gowin/clk_hdmi/clk_hdmi.ipc: -------------------------------------------------------------------------------- 1 | [General] 2 | ipc_version=4 3 | file=clk_hdmi 4 | module=clk_hdmi 5 | target_device=gw1nr9c-004 6 | type=clock_rpll 7 | version=1.0 8 | 9 | [Config] 10 | CKLOUTD3=false 11 | CLKFB_SOURCE=0 12 | CLKIN_FREQ=27 13 | CLKOUTD=false 14 | CLKOUTP=false 15 | CLKOUT_BYPASS=false 16 | CLKOUT_DIVIDE_DYN=true 17 | CLKOUT_FREQ=135 18 | CLKOUT_TOLERANCE=0 19 | DYNAMIC=true 20 | LANG=0 21 | LOCK_EN=true 22 | MODE_GENERAL=true 23 | PLL_PWD=false 24 | RESET_PLL=true 25 | -------------------------------------------------------------------------------- /boards/a2n9/hdl/gowin/clk_hdmi/clk_hdmi.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: IP file 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW1NR-LV9QN88PC6/I5 6 | //Device: GW1NR-9 7 | //Device Version: C 8 | //Created Time: Fri Jan 26 21:45:33 2024 9 | 10 | module clk_hdmi (clkout, lock, reset, clkin); 11 | 12 | output clkout; 13 | output lock; 14 | input reset; 15 | input clkin; 16 | 17 | wire clkoutp_o; 18 | wire clkoutd_o; 19 | wire clkoutd3_o; 20 | wire gw_gnd; 21 | 22 | assign gw_gnd = 1'b0; 23 | 24 | rPLL rpll_inst ( 25 | .CLKOUT(clkout), 26 | .LOCK(lock), 27 | .CLKOUTP(clkoutp_o), 28 | .CLKOUTD(clkoutd_o), 29 | .CLKOUTD3(clkoutd3_o), 30 | .RESET(reset), 31 | .RESET_P(gw_gnd), 32 | .CLKIN(clkin), 33 | .CLKFB(gw_gnd), 34 | .FBDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 35 | .IDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 36 | .ODSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 37 | .PSDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 38 | .DUTYDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 39 | .FDLY({gw_gnd,gw_gnd,gw_gnd,gw_gnd}) 40 | ); 41 | 42 | defparam rpll_inst.FCLKIN = "27"; 43 | defparam rpll_inst.DYN_IDIV_SEL = "false"; 44 | defparam rpll_inst.IDIV_SEL = 0; 45 | defparam rpll_inst.DYN_FBDIV_SEL = "false"; 46 | defparam rpll_inst.FBDIV_SEL = 4; 47 | defparam rpll_inst.DYN_ODIV_SEL = "false"; 48 | defparam rpll_inst.ODIV_SEL = 4; 49 | defparam rpll_inst.PSDA_SEL = "0000"; 50 | defparam rpll_inst.DYN_DA_EN = "true"; 51 | defparam rpll_inst.DUTYDA_SEL = "1000"; 52 | defparam rpll_inst.CLKOUT_FT_DIR = 1'b1; 53 | defparam rpll_inst.CLKOUTP_FT_DIR = 1'b1; 54 | defparam rpll_inst.CLKOUT_DLY_STEP = 0; 55 | defparam rpll_inst.CLKOUTP_DLY_STEP = 0; 56 | defparam rpll_inst.CLKFB_SEL = "internal"; 57 | defparam rpll_inst.CLKOUT_BYPASS = "false"; 58 | defparam rpll_inst.CLKOUTP_BYPASS = "false"; 59 | defparam rpll_inst.CLKOUTD_BYPASS = "false"; 60 | defparam rpll_inst.DYN_SDIV_SEL = 2; 61 | defparam rpll_inst.CLKOUTD_SRC = "CLKOUT"; 62 | defparam rpll_inst.CLKOUTD3_SRC = "CLKOUT"; 63 | defparam rpll_inst.DEVICE = "GW1NR-9C"; 64 | 65 | endmodule //clk_hdmi 66 | -------------------------------------------------------------------------------- /boards/a2n9/hdl/gowin/clk_hdmi/clk_hdmi_tmp.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: Template file for instantiation 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW1NR-LV9QN88PC6/I5 6 | //Device: GW1NR-9 7 | //Device Version: C 8 | //Created Time: Fri Jan 26 21:45:33 2024 9 | 10 | //Change the instance name and port connections to the signal names 11 | //--------Copy here to design-------- 12 | 13 | clk_hdmi your_instance_name( 14 | .clkout(clkout_o), //output clkout 15 | .lock(lock_o), //output lock 16 | .reset(reset_i), //input reset 17 | .clkin(clkin_i) //input clkin 18 | ); 19 | 20 | //--------Copy end------------------- 21 | -------------------------------------------------------------------------------- /boards/a2n9/hdl/gowin/clk_logic/clk_logic.ipc: -------------------------------------------------------------------------------- 1 | [General] 2 | ipc_version=4 3 | file=clk_logic 4 | module=clk_logic 5 | target_device=gw1nr9c-004 6 | type=clock_rpll 7 | version=1.0 8 | 9 | [Config] 10 | CKLOUTD3=false 11 | CLKFB_SOURCE=0 12 | CLKIN_FREQ=27 13 | CLKOUTD=true 14 | CLKOUTD_BYPASS=false 15 | CLKOUTD_FREQ=27 16 | CLKOUTD_SOURCE_CLKOUT=true 17 | CLKOUTD_TOLERANCE=0 18 | CLKOUTP=false 19 | CLKOUT_BYPASS=false 20 | CLKOUT_DIVIDE_DYN=true 21 | CLKOUT_FREQ=54 22 | CLKOUT_TOLERANCE=0 23 | DYNAMIC=true 24 | LANG=0 25 | LOCK_EN=true 26 | MODE_GENERAL=true 27 | PLL_PWD=false 28 | RESET_PLL=true 29 | -------------------------------------------------------------------------------- /boards/a2n9/hdl/gowin/clk_logic/clk_logic.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: IP file 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW1NR-LV9QN88PC6/I5 6 | //Device: GW1NR-9 7 | //Device Version: C 8 | //Created Time: Fri Jan 26 21:40:08 2024 9 | 10 | module clk_logic (clkout, lock, clkoutd, reset, clkin); 11 | 12 | output clkout; 13 | output lock; 14 | output clkoutd; 15 | input reset; 16 | input clkin; 17 | 18 | wire clkoutp_o; 19 | wire clkoutd3_o; 20 | wire gw_gnd; 21 | 22 | assign gw_gnd = 1'b0; 23 | 24 | rPLL rpll_inst ( 25 | .CLKOUT(clkout), 26 | .LOCK(lock), 27 | .CLKOUTP(clkoutp_o), 28 | .CLKOUTD(clkoutd), 29 | .CLKOUTD3(clkoutd3_o), 30 | .RESET(reset), 31 | .RESET_P(gw_gnd), 32 | .CLKIN(clkin), 33 | .CLKFB(gw_gnd), 34 | .FBDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 35 | .IDSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 36 | .ODSEL({gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 37 | .PSDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 38 | .DUTYDA({gw_gnd,gw_gnd,gw_gnd,gw_gnd}), 39 | .FDLY({gw_gnd,gw_gnd,gw_gnd,gw_gnd}) 40 | ); 41 | 42 | defparam rpll_inst.FCLKIN = "27"; 43 | defparam rpll_inst.DYN_IDIV_SEL = "false"; 44 | defparam rpll_inst.IDIV_SEL = 0; 45 | defparam rpll_inst.DYN_FBDIV_SEL = "false"; 46 | defparam rpll_inst.FBDIV_SEL = 1; 47 | defparam rpll_inst.DYN_ODIV_SEL = "false"; 48 | defparam rpll_inst.ODIV_SEL = 8; 49 | defparam rpll_inst.PSDA_SEL = "0000"; 50 | defparam rpll_inst.DYN_DA_EN = "true"; 51 | defparam rpll_inst.DUTYDA_SEL = "1000"; 52 | defparam rpll_inst.CLKOUT_FT_DIR = 1'b1; 53 | defparam rpll_inst.CLKOUTP_FT_DIR = 1'b1; 54 | defparam rpll_inst.CLKOUT_DLY_STEP = 0; 55 | defparam rpll_inst.CLKOUTP_DLY_STEP = 0; 56 | defparam rpll_inst.CLKFB_SEL = "internal"; 57 | defparam rpll_inst.CLKOUT_BYPASS = "false"; 58 | defparam rpll_inst.CLKOUTP_BYPASS = "false"; 59 | defparam rpll_inst.CLKOUTD_BYPASS = "false"; 60 | defparam rpll_inst.DYN_SDIV_SEL = 2; 61 | defparam rpll_inst.CLKOUTD_SRC = "CLKOUT"; 62 | defparam rpll_inst.CLKOUTD3_SRC = "CLKOUT"; 63 | defparam rpll_inst.DEVICE = "GW1NR-9C"; 64 | 65 | endmodule //clk_logic 66 | -------------------------------------------------------------------------------- /boards/a2n9/hdl/gowin/clk_logic/clk_logic_tmp.v: -------------------------------------------------------------------------------- 1 | //Copyright (C)2014-2023 Gowin Semiconductor Corporation. 2 | //All rights reserved. 3 | //File Title: Template file for instantiation 4 | //GOWIN Version: V1.9.9 Beta-4 Education 5 | //Part Number: GW1NR-LV9QN88PC6/I5 6 | //Device: GW1NR-9 7 | //Device Version: C 8 | //Created Time: Fri Jan 26 21:40:08 2024 9 | 10 | //Change the instance name and port connections to the signal names 11 | //--------Copy here to design-------- 12 | 13 | clk_logic your_instance_name( 14 | .clkout(clkout_o), //output clkout 15 | .lock(lock_o), //output lock 16 | .clkoutd(clkoutd_o), //output clkoutd 17 | .reset(reset_i), //input reset 18 | .clkin(clkin_i) //input clkin 19 | ); 20 | 21 | //--------Copy end------------------- 22 | -------------------------------------------------------------------------------- /boards/a2n9/impl/pnr/a2n9.tr.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Timing Analysis Report 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /boards/a2n9/impl/pnr/device.cfg: -------------------------------------------------------------------------------- 1 | set JTAG regular_io = false 2 | set SSPI regular_io = true 3 | set MSPI regular_io = true 4 | set READY regular_io = false 5 | set DONE regular_io = false 6 | set RECONFIG_N regular_io = false 7 | set I2C regular_io = false 8 | set CRC_check = true 9 | set compress = false 10 | set encryption = false 11 | set security_bit_enable = true 12 | set bsram_init_fuse_print = true 13 | set background_programming = off 14 | set secure_mode = false 15 | set program_done_bypass = false 16 | set wake_up = 0 17 | set format = binary 18 | set power_on_reset_monitor = true 19 | set multiboot_spi_flash_address = 0x00000000 20 | set vccx = 3.3 21 | set unused_pin = default 22 | -------------------------------------------------------------------------------- /boards/a2n9/impl/project_process_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Allow_Duplicate_Modules" : false, 3 | "Annotated_Properties_for_Analyst" : true, 4 | "BACKGROUND_PROGRAMMING" : "off", 5 | "CMSER" : false, 6 | "CMSER_CHECKSUM" : false, 7 | "CMSER_MODE" : "auto", 8 | "COMPRESS" : false, 9 | "CPU" : false, 10 | "CRC_CHECK" : true, 11 | "Clock_Conversion" : true, 12 | "Clock_Route_Order" : 0, 13 | "Correct_Hold_Violation" : true, 14 | "DONE" : false, 15 | "DOWNLOAD_SPEED" : "default", 16 | "Default_Enum_Encoding" : "default", 17 | "Disable_Insert_Pad" : false, 18 | "ENABLE_MERGE_MODE" : false, 19 | "ENCRYPTION_KEY" : false, 20 | "ENCRYPTION_KEY_TEXT" : "00000000000000000000000000000000", 21 | "ERROR_DECTION_AND_CORRECTION" : false, 22 | "ERROR_DECTION_ONLY" : false, 23 | "ERROR_INJECTION" : false, 24 | "EXTERNAL_MASTER_CONFIG_CLOCK" : false, 25 | "FORMAT" : "binary", 26 | "FREQUENCY_DIVIDER" : "", 27 | "FSM Compiler" : true, 28 | "Fanout_Guide" : 10000, 29 | "Frequency" : "Auto", 30 | "Generate_Constraint_File_of_Ports" : false, 31 | "Generate_IBIS_File" : false, 32 | "Generate_Plain_Text_Timing_Report" : false, 33 | "Generate_Post_PNR_Simulation_Model_File" : false, 34 | "Generate_Post_Place_File" : false, 35 | "Generate_SDF_File" : false, 36 | "Generate_VHDL_Post_PNR_Simulation_Model_File" : false, 37 | "GwSyn_Loop_Limit" : 2000, 38 | "HOTBOOT" : false, 39 | "I2C" : false, 40 | "I2C_SLAVE_ADDR" : "00", 41 | "Implicit_Initial_Value_Support" : false, 42 | "IncludePath" : [ 43 | 44 | ], 45 | "Incremental_Compile" : "", 46 | "Initialize_Primitives" : false, 47 | "JTAG" : false, 48 | "MODE_IO" : false, 49 | "MSPI" : true, 50 | "MSPI_JUMP" : false, 51 | "MULTIBOOT_ADDRESS_WIDTH" : "24", 52 | "MULTIBOOT_MODE" : "Normal", 53 | "MULTIBOOT_SPI_FLASH_ADDRESS" : "00000000", 54 | "MULTIJUMP_ADDRESS_WIDTH" : "24", 55 | "MULTIJUMP_MODE" : "Normal", 56 | "MULTIJUMP_SPI_FLASH_ADDRESS" : "000000", 57 | "Multi_Boot" : true, 58 | "Multiple_File_Compilation_Unit" : true, 59 | "Number_of_Critical_Paths" : "", 60 | "Number_of_Start/End_Points" : "", 61 | "OSC_DIVIDER" : "8", 62 | "OUTPUT_BASE_NAME" : "a2n9", 63 | "POWER_ON_RESET_MONITOR" : true, 64 | "PRINT_BSRAM_VALUE" : true, 65 | "PROGRAM_DONE_BYPASS" : false, 66 | "Pipelining" : true, 67 | "PlaceInRegToIob" : true, 68 | "PlaceIoRegToIob" : true, 69 | "PlaceOutRegToIob" : true, 70 | "Place_Option" : "0", 71 | "Process_Configuration_Verion" : "1.0", 72 | "Promote_Physical_Constraint_Warning_to_Error" : true, 73 | "Push_Tristates" : true, 74 | "READY" : false, 75 | "RECONFIG_N" : false, 76 | "Ram_RW_Check" : false, 77 | "Replicate_Resources" : false, 78 | "Report_Auto-Placed_Io_Information" : false, 79 | "Resolve_Mixed_Drivers" : false, 80 | "Resource_Sharing" : true, 81 | "Retiming" : false, 82 | "Route_Maxfan" : 23, 83 | "Route_Option" : "1", 84 | "Run_Timing_Driven" : true, 85 | "SECURE_MODE" : false, 86 | "SECURITY_BIT" : true, 87 | "SSPI" : true, 88 | "STOP_CMSER" : false, 89 | "Show_All_Warnings" : false, 90 | "Synthesis On/Off Implemented as Translate On/Off" : false, 91 | "Synthesize_tool" : "GowinSyn", 92 | "TclPre" : "", 93 | "TopModule" : "top", 94 | "USERCODE" : "default", 95 | "Unused_Pin" : "As_input_tri_stated_with_pull_up", 96 | "Update_Compile_Point_Timing_Data" : false, 97 | "Use_Clock_Period_for_Unconstrainted IO" : false, 98 | "VCCAUX" : 3.3, 99 | "VCCX" : "3.3", 100 | "VHDL_Standard" : "VHDL_Std_2008", 101 | "Verilog_Standard" : "Vlg_Std_Sysv2017", 102 | "WAKE_UP" : "0", 103 | "Write_Vendor_Constraint_File" : true, 104 | "show_all_warnings" : false, 105 | "turn_off_bg" : false 106 | } -------------------------------------------------------------------------------- /boards/a2n9/photos/a2n9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a2fpga/a2fpga_core/20291afa7f7f9e438615e2cbe1d8e29de5e1f835/boards/a2n9/photos/a2n9.png -------------------------------------------------------------------------------- /boards/a2n9/sch/a2n9.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a2fpga/a2fpga_core/20291afa7f7f9e438615e2cbe1d8e29de5e1f835/boards/a2n9/sch/a2n9.pdf -------------------------------------------------------------------------------- /hdl/bus/a2bus_control_if.sv: -------------------------------------------------------------------------------- 1 | // 2 | // Apple II Bus Control Interface 3 | // 4 | // (c) 2023,2024 Ed Anuff 5 | // 6 | // Permission to use, copy, modify, and/or distribute this software for any 7 | // purpose with or without fee is hereby granted, provided that the above 8 | // copyright notice and this permission notice appear in all copies. 9 | // 10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | // 18 | // Description: 19 | // 20 | // SystemVerilog interface for the bus control interface, used by the 21 | // PicoSoC to control the Apple II bus 22 | // 23 | 24 | interface a2bus_control_if; 25 | 26 | logic ready; 27 | 28 | modport a2bus ( 29 | input ready 30 | ); 31 | 32 | modport control ( 33 | output ready 34 | ); 35 | 36 | endinterface: a2bus_control_if 37 | 38 | -------------------------------------------------------------------------------- /hdl/bus/a2bus_if.sv: -------------------------------------------------------------------------------- 1 | // 2 | // Apple II Bus Interface 3 | // 4 | // (c) 2023,2024 Ed Anuff 5 | // 6 | // Permission to use, copy, modify, and/or distribute this software for any 7 | // purpose with or without fee is hereby granted, provided that the above 8 | // copyright notice and this permission notice appear in all copies. 9 | // 10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | // 18 | // Description: 19 | // 20 | // SystemVerilog interface for the Apple II bus 21 | // 22 | 23 | interface a2bus_if ( 24 | input logic clk_logic, 25 | input logic clk_pixel, 26 | input logic system_reset_n, 27 | input logic device_reset_n, 28 | input logic phi0, 29 | input logic phi1, 30 | input logic phi1_posedge, 31 | input logic phi1_negedge, 32 | input logic clk_2m_posedge, 33 | input logic clk_7m, 34 | input logic clk_7m_posedge, 35 | input logic clk_7m_negedge, 36 | input logic clk_14m_posedge 37 | ); 38 | 39 | logic sw_gs; 40 | logic rw_n; 41 | logic [15:0] addr; 42 | logic m2sel_n; 43 | logic m2b0; 44 | logic [7:0] data; 45 | logic data_in_strobe; 46 | 47 | modport master ( 48 | input clk_logic, 49 | input clk_pixel, 50 | input system_reset_n, 51 | input device_reset_n, 52 | input phi0, 53 | input phi1, 54 | input phi1_posedge, 55 | input phi1_negedge, 56 | input clk_2m_posedge, 57 | input clk_7m, 58 | input clk_7m_posedge, 59 | input clk_7m_negedge, 60 | input clk_14m_posedge, 61 | 62 | output rw_n, 63 | output addr, 64 | output m2sel_n, 65 | output m2b0, 66 | output data, 67 | output data_in_strobe, 68 | output sw_gs 69 | ); 70 | 71 | modport slave ( 72 | input clk_logic, 73 | input clk_pixel, 74 | input system_reset_n, 75 | input device_reset_n, 76 | input phi0, 77 | input phi1, 78 | input phi1_posedge, 79 | input phi1_negedge, 80 | input clk_2m_posedge, 81 | input clk_7m, 82 | input clk_7m_posedge, 83 | input clk_7m_negedge, 84 | input clk_14m_posedge, 85 | 86 | input rw_n, 87 | input addr, 88 | input m2sel_n, 89 | input m2b0, 90 | input data, 91 | input data_in_strobe, 92 | input sw_gs, 93 | 94 | import io_select_n, 95 | import dev_select_n, 96 | import io_strobe_n 97 | ); 98 | 99 | endinterface: a2bus_if 100 | 101 | -------------------------------------------------------------------------------- /hdl/disk/diskii.hex: -------------------------------------------------------------------------------- 1 | A2 20 A0 00 A2 03 86 3C 8A 0A 24 3C F0 10 05 3C 2 | 49 FF 29 7E B0 08 4A D0 FB 98 9D 56 03 C8 E8 10 3 | E5 20 58 FF BA BD 00 01 0A 0A 0A 0A 85 2B AA BD 4 | 8E C0 BD 8C C0 BD 8A C0 BD 89 C0 A0 50 BD 80 C0 5 | 98 29 03 0A 05 2B AA BD 81 C0 A9 56 20 A8 FC 88 6 | 10 EB 85 26 85 3D 85 41 A9 08 85 27 18 08 BD 8C 7 | C0 10 FB 49 D5 D0 F7 BD 8C C0 10 FB C9 AA D0 F3 8 | EA BD 8C C0 10 FB C9 96 F0 09 28 90 DF 49 AD F0 9 | 25 D0 D9 A0 03 85 40 BD 8C C0 10 FB 2A 85 3C BD 10 | 8C C0 10 FB 25 3C 88 D0 EC 28 C5 3D D0 BE A5 40 11 | C5 41 D0 B8 B0 B7 A0 56 84 3C BC 8C C0 10 FB 59 12 | D6 02 A4 3C 88 99 00 03 D0 EE 84 3C BC 8C C0 10 13 | FB 59 D6 02 A4 3C 91 26 C8 D0 EF BC 8C C0 10 FB 14 | 59 D6 02 D0 87 A0 00 A2 56 CA 30 FB B1 26 5E 00 15 | 03 2A 5E 00 03 2A 91 26 C8 D0 EE E6 27 E6 3D A5 16 | 3D CD 00 08 A6 2B 90 DB 4C 01 08 00 00 00 00 00 17 | -------------------------------------------------------------------------------- /hdl/disk/drive_volume_if.sv: -------------------------------------------------------------------------------- 1 | // 2 | // Apple II drive volume interface 3 | // 4 | // (c) 2023,2024 Ed Anuff 5 | // 6 | // Permission to use, copy, modify, and/or distribute this software for any 7 | // purpose with or without fee is hereby granted, provided that the above 8 | // copyright notice and this permission notice appear in all copies. 9 | // 10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | // 18 | // Description: 19 | // 20 | // SystemVerilog interface for drive volumes to pass to the PicoSOC 21 | // 22 | 23 | interface drive_volume_if(); 24 | 25 | logic ready; 26 | logic active; 27 | logic mounted; 28 | logic readonly; 29 | logic [31:0] size; 30 | 31 | // block level access 32 | logic [31:0] lba; 33 | logic [5:0] blk_cnt; // number of blocks-1; total size ((sd_blk_cnt+1)*(1<<(BLKSZ+7))) must be <= 16384! 34 | logic rd; 35 | logic wr; 36 | logic ack; 37 | 38 | modport drive ( 39 | input ready, 40 | output active, 41 | input mounted, 42 | input readonly, 43 | input size, 44 | 45 | output lba, 46 | output blk_cnt, 47 | output rd, 48 | output wr, 49 | input ack 50 | 51 | ); 52 | 53 | modport volume ( 54 | output ready, 55 | input active, 56 | output mounted, 57 | output readonly, 58 | output size, 59 | 60 | input lba, 61 | input blk_cnt, 62 | input rd, 63 | input wr, 64 | output ack 65 | 66 | ); 67 | 68 | endinterface: drive_volume_if 69 | -------------------------------------------------------------------------------- /hdl/f18a/f18a.sv: -------------------------------------------------------------------------------- 1 | // 2 | // SystemVerilog wrapper for the F18A implementation of the TMS9918A VDP 3 | // 4 | // Description: 5 | // 6 | // This module wraps the Matthew Hagerty F18A implementation of the TMS9918A VDP to 7 | // provide a SystemVerilog interface to the VDP. The purpose of this is to 8 | // abstract out the GPU interface so that alternate co-processors can be 9 | // used with the F18A VDP. 10 | // 11 | // See the accompanying f18a_gpu_if.sv for the interface definition. 12 | // 13 | 14 | 15 | module f18a ( 16 | input wire clk_logic_i, 17 | input wire clk_pixel_i, 18 | 19 | // 9918A to Host System Interface 20 | input wire reset_n_i, // Must be active for at least one 25MHz clock cycle 21 | input wire mode_i, 22 | input wire csw_n_i, 23 | input wire csr_n_i, 24 | output wire int_n_o, 25 | input wire [7:0] cd_i, 26 | output wire [7:0] cd_o, 27 | 28 | input wire [9:0] raster_x_i, 29 | input wire [9:0] raster_y_i, 30 | 31 | // Video Output 32 | output wire blank_o, 33 | output wire hsync_o, 34 | output wire vsync_o, 35 | output wire [3:0] red_o, 36 | output wire [3:0] grn_o, 37 | output wire [3:0] blu_o, 38 | output wire transparent_o, 39 | output wire ext_video_o, 40 | output wire scanlines_o, 41 | 42 | // Feature Selection 43 | input wire sprite_max_i, // Default sprite max, '0' = 32, '1' = 4 44 | input wire scanlines_i, // Simulated scan lines, '0' = no, '1' = yes 45 | output wire unlocked_o, 46 | output wire [3:0] gmode_o, 47 | 48 | f18a_gpu_if.master gpu_if 49 | ); 50 | 51 | f18a_core f18a_core ( 52 | .clk_logic_i(clk_logic_i), 53 | .clk_pixel_i(clk_pixel_i), 54 | .reset_n_i(reset_n_i), 55 | .mode_i(mode_i), 56 | .csw_n_i(csw_n_i), 57 | .csr_n_i(csr_n_i), 58 | .int_n_o(int_n_o), 59 | .cd_i(cd_i), 60 | .cd_o(cd_o), 61 | .raster_x_i(raster_x_i), 62 | .raster_y_i(raster_y_i), 63 | .blank_o(blank_o), 64 | .hsync_o(hsync_o), 65 | .vsync_o(vsync_o), 66 | .red_o(red_o), 67 | .grn_o(grn_o), 68 | .blu_o(blu_o), 69 | .transparent_o(transparent_o), 70 | .ext_video_o(ext_video_o), 71 | .sprite_max_i(sprite_max_i), 72 | .scanlines_i(scanlines_i), 73 | .scanlines_o(scanlines_o), 74 | .unlocked_o(unlocked_o), 75 | .gmode_o(gmode_o), 76 | 77 | .gpu_trigger_o(gpu_if.trigger), 78 | .gpu_running_i(gpu_if.running), 79 | .gpu_pause_o(gpu_if.pause), 80 | .gpu_pause_ack_i(gpu_if.pause_ack), 81 | .gpu_load_pc_o(gpu_if.load_pc), 82 | .gpu_vdin_o(gpu_if.vdin), 83 | .gpu_vwe_i(gpu_if.vwe), 84 | .gpu_vaddr_i(gpu_if.vaddr), 85 | .gpu_vdout_i(gpu_if.vdout), 86 | .gpu_pdin_o(gpu_if.pdin), 87 | .gpu_pwe_i(gpu_if.pwe), 88 | .gpu_paddr_i(gpu_if.paddr), 89 | .gpu_pdout_i(gpu_if.pdout), 90 | .gpu_rdin_o(gpu_if.rdin), 91 | .gpu_raddr_i(gpu_if.raddr), 92 | .gpu_rwe_i(gpu_if.rwe), 93 | .gpu_scanline_o(gpu_if.scanline), 94 | .gpu_blank_o(gpu_if.blank), 95 | .gpu_bmlba_o(gpu_if.bmlba), 96 | .gpu_bml_w_o(gpu_if.bml_w), 97 | .gpu_pgba_o(gpu_if.pgba), 98 | .gpu_gstatus_i(gpu_if.gstatus) 99 | ); 100 | 101 | endmodule 102 | 103 | -------------------------------------------------------------------------------- /hdl/f18a/f18a_gpu_if.sv: -------------------------------------------------------------------------------- 1 | // 2 | // SystemVerilog interface for the F18A GPU 3 | // 4 | // Description: 5 | // 6 | // This SystemVerilog interface is used to connect the F18A GPU to the 7 | // alternate co-processors that can be used with the F18A VDP. 8 | // 9 | // The F18A provides a GPU based on the TMS9900 CPU. The GPU is used to 10 | // run graphics operations on the VDP. For the A2FPGA, we don't use the 11 | // TMS9900 GPU, but instead use a SystemVerilog interface to the F18A 12 | // GPU signals that can be used to connect the F18A to the PicoRV32 CPU 13 | // or other co-processors. 14 | // 15 | 16 | interface f18a_gpu_if; 17 | 18 | // GPU Status Interface 19 | logic trigger; // trigger the GPU 20 | logic running; // '1' if the GPU is running; '0' when idle 21 | logic pause; // pause the GPU; active high 22 | logic pause_ack; // acknowledge pause 23 | logic [15:0] load_pc; 24 | // GPU VRAM Interface 25 | logic [7:0] vdin; 26 | logic vwe; 27 | logic [13:0] vaddr; 28 | logic [7:0] vdout; 29 | // GPU Palette Interface 30 | logic [11:0] pdin; 31 | logic pwe; 32 | logic [5:0] paddr; 33 | logic [11:0] pdout; 34 | // GPU Register Interface 35 | logic [7:0] rdin; 36 | logic [13:0] raddr; 37 | logic rwe; // write enable for VDP registers 38 | // GPU Data inputs 39 | logic [7:0] scanline; 40 | logic blank; // '1' when blanking (horz and vert) 41 | logic [7:0] bmlba; // bitmap layer base address 42 | logic [7:0] bml_w; // bitmap layer width 43 | logic pgba; // pattern generator base address 44 | // GPU Data output; 7-bits of user defined status 45 | logic [6:0] gstatus; 46 | 47 | modport master ( 48 | output trigger, 49 | input running, 50 | output pause, 51 | input pause_ack, 52 | output load_pc, 53 | 54 | output vdin, 55 | input vwe, 56 | input vaddr, 57 | input vdout, 58 | 59 | output pdin, 60 | input pwe, 61 | input paddr, 62 | input pdout, 63 | 64 | output rdin, 65 | input raddr, 66 | input rwe, 67 | 68 | output scanline, 69 | output blank, 70 | output bmlba, 71 | output bml_w, 72 | output pgba, 73 | 74 | input gstatus 75 | ); 76 | 77 | modport slave ( 78 | input trigger, 79 | output running, 80 | input pause, 81 | output pause_ack, 82 | input load_pc, 83 | 84 | input vdin, 85 | output vwe, 86 | output vaddr, 87 | output vdout, 88 | 89 | input pdin, 90 | output pwe, 91 | output paddr, 92 | output pdout, 93 | 94 | input rdin, 95 | output raddr, 96 | output rwe, 97 | 98 | input scanline, 99 | input blank, 100 | input bmlba, 101 | input bml_w, 102 | input pgba, 103 | 104 | output gstatus 105 | ); 106 | 107 | 108 | endinterface: f18a_gpu_if 109 | -------------------------------------------------------------------------------- /hdl/f18a/f18a_single_port_ram.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- F18A 3 | -- A pin-compatible enhanced replacement for the TMS9918A VDP family. 4 | -- https://dnotq.io 5 | -- 6 | 7 | -- Released under the 3-Clause BSD License: 8 | -- 9 | -- Copyright 2011-2018 Matthew Hagerty (matthew dnotq io) 10 | -- 11 | -- Redistribution and use in source and binary forms, with or without 12 | -- modification, are permitted provided that the following conditions are met: 13 | -- 14 | -- 1. Redistributions of source code must retain the above copyright notice, 15 | -- this list of conditions and the following disclaimer. 16 | -- 17 | -- 2. Redistributions in binary form must reproduce the above copyright 18 | -- notice, this list of conditions and the following disclaimer in the 19 | -- documentation and/or other materials provided with the distribution. 20 | -- 21 | -- 3. Neither the name of the copyright holder nor the names of its 22 | -- contributors may be used to endorse or promote products derived from this 23 | -- software without specific prior written permission. 24 | -- 25 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | -- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | -- POSSIBILITY OF SUCH DAMAGE. 36 | 37 | -- Version history. See README.md for details. 38 | -- 39 | -- V1.9 Dec 31, 2018 40 | -- V1.8 Aug 24, 2016 41 | -- V1.7 Jan 1, 2016 42 | -- V1.6 May 3, 2014 .. Apr 26, 2015 43 | -- V1.5 Jul 23, 2013 44 | -- V1.4 Mar 20, 2013 .. Apr 26, 2013 45 | -- V1.3 Jul 26, 2012, Release firmware 46 | 47 | -- The on-board 16K VRAM. Initialized with font pattern and name table data 48 | -- that will display the F18A power-on screen. This allows the F18A to produce 49 | -- a display even when there is no host CPU and helps troubleshooting. 50 | 51 | library ieee; 52 | use ieee.std_logic_1164.all; 53 | use ieee.numeric_std.all; 54 | 55 | entity f18a_single_port_ram is 56 | port ( 57 | clk : in std_logic; 58 | we : in std_logic; 59 | addr : in std_logic_vector(0 to 13); 60 | addr2 : in std_logic_vector(0 to 13); 61 | din : in std_logic_vector(0 to 7); 62 | dout : out std_logic_vector(0 to 7); 63 | dout2 : out std_logic_vector(0 to 7) 64 | ); 65 | end f18a_single_port_ram; 66 | 67 | architecture rtl of f18a_single_port_ram is 68 | 69 | -- Initialize the VRAM with patterns for a font and credits / version information on the screen. 70 | type ram_t is array (0 to 16383) of std_logic_vector(0 to 7); 71 | signal ram : ram_t; 72 | 73 | begin 74 | -- Inferred read_first ram. 75 | process (clk) 76 | begin 77 | if rising_edge(clk) then 78 | dout2 <= ram(to_integer(unsigned(addr2))); 79 | if we = '1' then 80 | ram(to_integer(unsigned(addr))) <= din; 81 | else 82 | dout <= ram(to_integer(unsigned(addr))); 83 | end if; 84 | end if; 85 | end process; 86 | 87 | end rtl; 88 | -------------------------------------------------------------------------------- /hdl/f18a/f18a_vram.vhd: -------------------------------------------------------------------------------- 1 | -- 2 | -- F18A 3 | -- A pin-compatible enhanced replacement for the TMS9918A VDP family. 4 | -- https://dnotq.io 5 | -- 6 | 7 | -- Released under the 3-Clause BSD License: 8 | -- 9 | -- Copyright 2011-2018 Matthew Hagerty (matthew dnotq io) 10 | -- 11 | -- Redistribution and use in source and binary forms, with or without 12 | -- modification, are permitted provided that the following conditions are met: 13 | -- 14 | -- 1. Redistributions of source code must retain the above copyright notice, 15 | -- this list of conditions and the following disclaimer. 16 | -- 17 | -- 2. Redistributions in binary form must reproduce the above copyright 18 | -- notice, this list of conditions and the following disclaimer in the 19 | -- documentation and/or other materials provided with the distribution. 20 | -- 21 | -- 3. Neither the name of the copyright holder nor the names of its 22 | -- contributors may be used to endorse or promote products derived from this 23 | -- software without specific prior written permission. 24 | -- 25 | -- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 26 | -- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 | -- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 | -- ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 29 | -- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 30 | -- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 31 | -- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 32 | -- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 33 | -- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | -- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 35 | -- POSSIBILITY OF SUCH DAMAGE. 36 | 37 | -- Version history. See README.md for details. 38 | -- 39 | -- V1.9 Dec 31, 2018 40 | -- V1.8 Aug 24, 2016 41 | -- V1.7 Jan 1, 2016 42 | -- V1.6 May 3, 2014 .. Apr 26, 2015 43 | -- V1.5 Jul 23, 2013 44 | -- V1.4 Mar 20, 2013 .. Apr 26, 2013 45 | -- V1.3 Jul 26, 2012, Release firmware 46 | 47 | -- Implements the main VRAM multiplexer. The host-CPU interface always has 48 | -- access on one port, the tiles and sprites share the other port since their 49 | -- FSMs are triggered sequentially during each scan line. 50 | 51 | library ieee; 52 | use ieee.std_logic_1164.all; 53 | use ieee.numeric_std.all; 54 | use ieee.std_logic_unsigned.all; 55 | 56 | entity f18a_vram is 57 | port ( 58 | clk : in std_logic; 59 | rst_n : in std_logic; 60 | -- CPU Interface 61 | cpu_din : in std_logic_vector(0 to 7); 62 | cpu_we : in std_logic; 63 | cpu_addr : in std_logic_vector(0 to 13); 64 | cpu_dout : out std_logic_vector(0 to 7); 65 | -- TILE Interface 66 | tile_active : in std_logic; 67 | tile_addr : in std_logic_vector(0 to 13); 68 | tile_dout : out std_logic_vector(0 to 7); 69 | -- SPRITE Interface 70 | sprt_addr : in std_logic_vector(0 to 13) 71 | ); 72 | end f18a_vram; 73 | 74 | architecture rtl of f18a_vram is 75 | 76 | signal addr_mux : std_logic_vector(0 to 13); 77 | 78 | begin 79 | 80 | -- Main RAM 81 | inst_ram : entity work.f18a_single_port_ram 82 | port map ( 83 | clk => clk, 84 | we => cpu_we, 85 | addr => cpu_addr, 86 | addr2 => addr_mux, 87 | din => cpu_din, 88 | dout => cpu_dout, 89 | dout2 => tile_dout 90 | ); 91 | 92 | addr_mux <= tile_addr when tile_active = '1' else sprt_addr; 93 | 94 | end rtl; 95 | -------------------------------------------------------------------------------- /hdl/hdmi/audio_clock_regeneration_packet.sv: -------------------------------------------------------------------------------- 1 | // Implementation of HDMI audio clock regeneration packet 2 | // By Sameer Puri https://github.com/sameer 3 | 4 | // See HDMI 1.4b Section 5.3.3 5 | module audio_clock_regeneration_packet 6 | #( 7 | parameter real VIDEO_RATE = 25.2E6, 8 | parameter int AUDIO_RATE = 48e3 9 | ) 10 | ( 11 | input logic clk_pixel, 12 | input logic clk_audio, 13 | output logic clk_audio_counter_wrap, 14 | output logic [23:0] header, 15 | output logic [55:0] sub [3:0] 16 | ); 17 | 18 | // See Section 7.2.3, values derived from "Other" row in Tables 7-1, 7-2, 7-3. 19 | localparam bit [19:0] N = AUDIO_RATE % 125 == 0 ? 20'(16 * AUDIO_RATE / 125) : AUDIO_RATE % 225 == 0 ? 20'(32 * AUDIO_RATE / 225) : 20'(AUDIO_RATE * 16 / 125); 20 | 21 | localparam int CLK_AUDIO_COUNTER_WIDTH = $clog2(N / 128); 22 | localparam bit [CLK_AUDIO_COUNTER_WIDTH-1:0] CLK_AUDIO_COUNTER_END = CLK_AUDIO_COUNTER_WIDTH'(N / 128 - 1); 23 | logic [CLK_AUDIO_COUNTER_WIDTH-1:0] clk_audio_counter = CLK_AUDIO_COUNTER_WIDTH'(0); 24 | logic internal_clk_audio_counter_wrap = 1'd0; 25 | always_ff @(posedge clk_pixel) 26 | begin 27 | if (clk_audio) begin 28 | if (clk_audio_counter == CLK_AUDIO_COUNTER_END) 29 | begin 30 | clk_audio_counter <= CLK_AUDIO_COUNTER_WIDTH'(0); 31 | internal_clk_audio_counter_wrap <= !internal_clk_audio_counter_wrap; 32 | end 33 | else 34 | clk_audio_counter <= clk_audio_counter + 1'd1; 35 | end 36 | end 37 | 38 | logic [1:0] clk_audio_counter_wrap_synchronizer_chain = 2'd0; 39 | always_ff @(posedge clk_pixel) 40 | clk_audio_counter_wrap_synchronizer_chain <= {internal_clk_audio_counter_wrap, clk_audio_counter_wrap_synchronizer_chain[1]}; 41 | 42 | localparam bit [19:0] CYCLE_TIME_STAMP_COUNTER_IDEAL = 20'(int'(VIDEO_RATE * int'(N) / 128 / AUDIO_RATE)); 43 | localparam int CYCLE_TIME_STAMP_COUNTER_WIDTH = $clog2(20'(int'(real'(CYCLE_TIME_STAMP_COUNTER_IDEAL) * 1.1))); // Account for 10% deviation in audio clock 44 | 45 | logic [19:0] cycle_time_stamp = 20'd0; 46 | logic [CYCLE_TIME_STAMP_COUNTER_WIDTH-1:0] cycle_time_stamp_counter = CYCLE_TIME_STAMP_COUNTER_WIDTH'(0); 47 | always_ff @(posedge clk_pixel) 48 | begin 49 | if (clk_audio_counter_wrap_synchronizer_chain[1] ^ clk_audio_counter_wrap_synchronizer_chain[0]) 50 | begin 51 | cycle_time_stamp_counter <= CYCLE_TIME_STAMP_COUNTER_WIDTH'(0); 52 | cycle_time_stamp <= {(20-CYCLE_TIME_STAMP_COUNTER_WIDTH)'(0), cycle_time_stamp_counter + CYCLE_TIME_STAMP_COUNTER_WIDTH'(1)}; 53 | clk_audio_counter_wrap <= !clk_audio_counter_wrap; 54 | end 55 | else 56 | cycle_time_stamp_counter <= cycle_time_stamp_counter + CYCLE_TIME_STAMP_COUNTER_WIDTH'(1); 57 | end 58 | 59 | // "An HDMI Sink shall ignore bytes HB1 and HB2 of the Audio Clock Regeneration Packet header." 60 | `ifdef MODEL_TECH 61 | assign header = {8'd0, 8'd0, 8'd1}; 62 | `else 63 | assign header = {8'dX, 8'dX, 8'd1}; 64 | `endif 65 | 66 | // "The four Subpackets each contain the same Audio Clock regeneration Subpacket." 67 | genvar i; 68 | generate 69 | for (i = 0; i < 4; i++) 70 | begin: same_packet 71 | assign sub[i] = {N[7:0], N[15:8], {4'd0, N[19:16]}, cycle_time_stamp[7:0], cycle_time_stamp[15:8], {4'd0, cycle_time_stamp[19:16]}, 8'd0}; 72 | end 73 | endgenerate 74 | 75 | endmodule 76 | -------------------------------------------------------------------------------- /hdl/hdmi/audio_info_frame.sv: -------------------------------------------------------------------------------- 1 | // Implementation of HDMI audio info frame 2 | // By Sameer Puri https://github.com/sameer 3 | 4 | // See Section 8.2.2 5 | module audio_info_frame 6 | #( 7 | parameter bit [2:0] AUDIO_CHANNEL_COUNT = 3'd1, // 2 channels. See CEA-861-D table 17 for details. 8 | parameter bit [7:0] CHANNEL_ALLOCATION = 8'h00, // Channel 0 = Front Left, Channel 1 = Front Right (0-indexed) 9 | parameter bit DOWN_MIX_INHIBITED = 1'b0, // Permitted or no information about any assertion of this. The DM_INH field is to be set only for DVD-Audio applications. 10 | parameter bit [3:0] LEVEL_SHIFT_VALUE = 4'd0, // 4-bit unsigned number from 0dB up to 15dB, used for downmixing. 11 | parameter bit [1:0] LOW_FREQUENCY_EFFECTS_PLAYBACK_LEVEL = 2'b00 // No information, LFE = bass-only info < 120Hz, used in Dolby Surround. 12 | ) 13 | ( 14 | output logic [23:0] header, 15 | output logic [55:0] sub [3:0] 16 | ); 17 | 18 | // NOTE—HDMI requires the coding type, sample size and sample frequency fields to be set to 0 ("Refer to Stream Header") as these items are carried in the audio stream 19 | localparam bit [3:0] AUDIO_CODING_TYPE = 4'd0; // Refer to stream header. 20 | localparam bit [2:0] SAMPLING_FREQUENCY = 3'd0; // Refer to stream header. 21 | localparam bit [1:0] SAMPLE_SIZE = 2'd0; // Refer to stream header. 22 | 23 | localparam bit [4:0] LENGTH = 5'd10; 24 | localparam bit [7:0] VERSION = 8'd1; 25 | localparam bit [6:0] TYPE = 7'd4; 26 | 27 | assign header = {{3'b0, LENGTH}, VERSION, {1'b1, TYPE}}; 28 | 29 | // PB0-PB6 = sub0 30 | // PB7-13 = sub1 31 | // PB14-20 = sub2 32 | // PB21-27 = sub3 33 | logic [7:0] packet_bytes [27:0]; 34 | 35 | assign packet_bytes[0] = 8'd1 + ~(header[23:16] + header[15:8] + header[7:0] + packet_bytes[5] + packet_bytes[4] + packet_bytes[3] + packet_bytes[2] + packet_bytes[1]); 36 | assign packet_bytes[1] = {AUDIO_CODING_TYPE, 1'b0, AUDIO_CHANNEL_COUNT}; 37 | assign packet_bytes[2] = {3'd0, SAMPLING_FREQUENCY, SAMPLE_SIZE}; 38 | assign packet_bytes[3] = 8'd0; 39 | assign packet_bytes[4] = CHANNEL_ALLOCATION; 40 | assign packet_bytes[5] = {DOWN_MIX_INHIBITED, LEVEL_SHIFT_VALUE, 1'b0, LOW_FREQUENCY_EFFECTS_PLAYBACK_LEVEL}; 41 | 42 | genvar i; 43 | generate 44 | for (i = 6; i < 28; i++) 45 | begin: pb_reserved 46 | assign packet_bytes[i] = 8'd0; 47 | end 48 | for (i = 0; i < 4; i++) 49 | begin: pb_to_sub 50 | assign sub[i] = {packet_bytes[6 + i*7], packet_bytes[5 + i*7], packet_bytes[4 + i*7], packet_bytes[3 + i*7], packet_bytes[2 + i*7], packet_bytes[1 + i*7], packet_bytes[0 + i*7]}; 51 | end 52 | endgenerate 53 | endmodule 54 | -------------------------------------------------------------------------------- /hdl/hdmi/packet_assembler.sv: -------------------------------------------------------------------------------- 1 | // Implementation of HDMI packet ECC calculation. 2 | // By Sameer Puri https://github.com/sameer 3 | 4 | module packet_assembler ( 5 | input logic clk_pixel, 6 | input logic reset, 7 | input logic data_island_period, 8 | input logic [23:0] header, // See Table 5-8 Packet Types 9 | input logic [55:0] sub [3:0], 10 | output logic [8:0] packet_data, // See Figure 5-4 Data Island Packet and ECC Structure 11 | output logic [4:0] counter 12 | ); 13 | 14 | // 32 pixel wrap-around counter. See Section 5.2.3.4 for further information. 15 | always_ff @(posedge clk_pixel) 16 | begin 17 | if (reset) 18 | counter <= 5'd0; 19 | else if (data_island_period) 20 | counter <= counter + 5'd1; 21 | end 22 | // BCH packets 0 to 3 are transferred two bits at a time, see Section 5.2.3.4 for further information. 23 | wire [5:0] counter_t2 = {counter, 1'b0}; 24 | wire [5:0] counter_t2_p1 = {counter, 1'b1}; 25 | 26 | // Initialize parity bits to 0 27 | logic [7:0] parity [4:0] = '{8'd0, 8'd0, 8'd0, 8'd0, 8'd0}; 28 | 29 | wire [63:0] bch [3:0]; 30 | assign bch[0] = {parity[0], sub[0]}; 31 | assign bch[1] = {parity[1], sub[1]}; 32 | assign bch[2] = {parity[2], sub[2]}; 33 | assign bch[3] = {parity[3], sub[3]}; 34 | wire [31:0] bch4 = {parity[4], header}; 35 | assign packet_data = {bch[3][counter_t2_p1], bch[2][counter_t2_p1], bch[1][counter_t2_p1], bch[0][counter_t2_p1], bch[3][counter_t2], bch[2][counter_t2], bch[1][counter_t2], bch[0][counter_t2], bch4[counter]}; 36 | 37 | // See Figure 5-5 Error Correction Code generator. Generalization of a CRC with binary BCH. 38 | // See https://web.archive.org/web/20190520020602/http://hamsterworks.co.nz/mediawiki/index.php/Minimal_HDMI#Computing_the_ECC for an explanation of the implementation. 39 | // See https://en.wikipedia.org/wiki/BCH_code#Systematic_encoding:_The_message_as_a_prefix for further information. 40 | function automatic [7:0] next_ecc; 41 | input [7:0] ecc, next_bch_bit; 42 | begin 43 | next_ecc = (ecc >> 1) ^ ((ecc[0] ^ next_bch_bit) ? 8'b10000011 : 8'd0); 44 | end 45 | endfunction 46 | 47 | logic [7:0] parity_next [4:0]; 48 | 49 | // The parity needs to be calculated 2 bits at a time for blocks 0 to 3. 50 | // There's 56 bits being sent 2 bits at a time over TMDS channels 1 & 2, so the parity bits wouldn't be ready in time otherwise. 51 | logic [7:0] parity_next_next [3:0]; 52 | 53 | genvar i; 54 | generate 55 | for(i = 0; i < 5; i++) 56 | begin: parity_calc 57 | if (i == 4) 58 | assign parity_next[i] = next_ecc(parity[i], header[counter]); 59 | else 60 | begin 61 | assign parity_next[i] = next_ecc(parity[i], sub[i][counter_t2]); 62 | assign parity_next_next[i] = next_ecc(parity_next[i], sub[i][counter_t2_p1]); 63 | end 64 | end 65 | endgenerate 66 | 67 | always_ff @(posedge clk_pixel) 68 | begin 69 | if (reset) 70 | parity <= '{8'd0, 8'd0, 8'd0, 8'd0, 8'd0}; 71 | else if (data_island_period) 72 | begin 73 | if (counter < 5'd28) // Compute ECC only on subpacket data, not on itself 74 | begin 75 | parity[3:0] <= parity_next_next; 76 | if (counter < 5'd24) // Header only has 24 bits, whereas subpackets have 56 and 56 / 2 = 28. 77 | parity[4] <= parity_next[4]; 78 | end 79 | else if (counter == 5'd31) 80 | parity <= '{8'd0, 8'd0, 8'd0, 8'd0, 8'd0}; // Reset ECC for next packet 81 | end 82 | else 83 | parity <= '{8'd0, 8'd0, 8'd0, 8'd0, 8'd0}; 84 | end 85 | 86 | endmodule 87 | -------------------------------------------------------------------------------- /hdl/hdmi/source_product_description_info_frame.sv: -------------------------------------------------------------------------------- 1 | // Implementation of HDMI SPD InfoFrame packet. 2 | // By Sameer Puri https://github.com/sameer 3 | 4 | // See CEA-861-D Section 6.5 page 72 (84 in PDF) 5 | module source_product_description_info_frame 6 | #( 7 | parameter bit [8*8-1:0] VENDOR_NAME = 0, 8 | parameter bit [8*16-1:0] PRODUCT_DESCRIPTION = 0, 9 | parameter bit [7:0] SOURCE_DEVICE_INFORMATION = 0 10 | ) 11 | ( 12 | output logic [23:0] header, 13 | output logic [55:0] sub [3:0] 14 | ); 15 | 16 | localparam bit [4:0] LENGTH = 5'd25; 17 | localparam bit [7:0] VERSION = 8'd1; 18 | localparam bit [6:0] TYPE = 7'd3; 19 | 20 | assign header = {{3'b0, LENGTH}, VERSION, {1'b1, TYPE}}; 21 | 22 | // PB0-PB6 = sub0 23 | // PB7-13 = sub1 24 | // PB14-20 = sub2 25 | // PB21-27 = sub3 26 | logic [7:0] packet_bytes [27:0]; 27 | 28 | assign packet_bytes[0] = 8'd1 + ~(header[23:16] + header[15:8] + header[7:0] + packet_bytes[25] + packet_bytes[24] + packet_bytes[23] + packet_bytes[22] + packet_bytes[21] + packet_bytes[20] + packet_bytes[19] + packet_bytes[18] + packet_bytes[17] + packet_bytes[16] + packet_bytes[15] + packet_bytes[14] + packet_bytes[13] + packet_bytes[12] + packet_bytes[11] + packet_bytes[10] + packet_bytes[9] + packet_bytes[8] + packet_bytes[7] + packet_bytes[6] + packet_bytes[5] + packet_bytes[4] + packet_bytes[3] + packet_bytes[2] + packet_bytes[1]); 29 | 30 | 31 | byte vendor_name [0:7]; 32 | byte product_description [0:15]; 33 | 34 | genvar i; 35 | generate 36 | for (i = 0; i < 8; i++) 37 | begin: vendor_to_bytes 38 | assign vendor_name[i] = VENDOR_NAME[(7-i+1)*8-1:(7-i)*8]; 39 | end 40 | for (i = 0; i < 16; i++) 41 | begin: product_to_bytes 42 | assign product_description[i] = PRODUCT_DESCRIPTION[(15-i+1)*8-1:(15-i)*8]; 43 | end 44 | 45 | for (i = 1; i < 9; i++) 46 | begin: pb_vendor 47 | assign packet_bytes[i] = vendor_name[i - 1] == 8'h30 ? 8'h00 : vendor_name[i - 1]; 48 | end 49 | for (i = 9; i < LENGTH; i++) 50 | begin: pb_product 51 | assign packet_bytes[i] = product_description[i - 9] == 8'h30 ? 8'h00 : product_description[i - 9]; 52 | end 53 | assign packet_bytes[LENGTH] = SOURCE_DEVICE_INFORMATION; 54 | for (i = 26; i < 28; i++) 55 | begin: pb_reserved 56 | assign packet_bytes[i] = 8'd0; 57 | end 58 | for (i = 0; i < 4; i++) 59 | begin: pb_to_sub 60 | assign sub[i] = {packet_bytes[6 + i*7], packet_bytes[5 + i*7], packet_bytes[4 + i*7], packet_bytes[3 + i*7], packet_bytes[2 + i*7], packet_bytes[1 + i*7], packet_bytes[0 + i*7]}; 61 | end 62 | endgenerate 63 | 64 | endmodule 65 | -------------------------------------------------------------------------------- /hdl/memory/a2mem_if.sv: -------------------------------------------------------------------------------- 1 | // 2 | // Apple II Memory Interface 3 | // 4 | // (c) 2023,2024 Ed Anuff 5 | // 6 | // Permission to use, copy, modify, and/or distribute this software for any 7 | // purpose with or without fee is hereby granted, provided that the above 8 | // copyright notice and this permission notice appear in all copies. 9 | // 10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | // 18 | // Description: 19 | // 20 | // SystemVerilog interface for the Apple II memory soft switches and 21 | // memory configuration 22 | // 23 | 24 | interface a2mem_if; 25 | 26 | // II Soft switches 27 | logic TEXT_MODE; 28 | logic MIXED_MODE; 29 | logic PAGE2; 30 | logic HIRES_MODE; 31 | logic AN0; 32 | logic AN1; 33 | logic AN2; 34 | logic AN3; 35 | 36 | // ][e auxilary switches 37 | logic STORE80; 38 | logic RAMRD; 39 | logic RAMWRT; 40 | logic INTCXROM; 41 | logic ALTZP; 42 | logic SLOTC3ROM; 43 | logic COL80; 44 | logic ALTCHAR; 45 | 46 | logic INTC8ROM; 47 | 48 | logic [2:0] SLOTROM; 49 | 50 | // IIgs configuration 51 | logic [3:0] TEXT_COLOR; 52 | logic [3:0] BACKGROUND_COLOR; 53 | logic [3:0] BORDER_COLOR; 54 | logic MONOCHROME_MODE; 55 | logic MONOCHROME_DHIRES_MODE; 56 | logic SHRG_MODE; 57 | logic LINEARIZE_MODE; 58 | 59 | logic aux_mem; 60 | 61 | logic [7:0] keycode; 62 | logic keypress_strobe; 63 | 64 | modport master ( 65 | output TEXT_MODE, 66 | output MIXED_MODE, 67 | output PAGE2, 68 | output HIRES_MODE, 69 | output AN0, 70 | output AN1, 71 | output AN2, 72 | output AN3, 73 | 74 | output STORE80, 75 | output RAMRD, 76 | output RAMWRT, 77 | output INTCXROM, 78 | output ALTZP, 79 | output SLOTC3ROM, 80 | output COL80, 81 | output ALTCHAR, 82 | 83 | output INTC8ROM, 84 | 85 | output SLOTROM, 86 | 87 | output TEXT_COLOR, 88 | output BACKGROUND_COLOR, 89 | output BORDER_COLOR, 90 | output MONOCHROME_MODE, 91 | output MONOCHROME_DHIRES_MODE, 92 | output SHRG_MODE, 93 | output LINEARIZE_MODE, 94 | 95 | output aux_mem, 96 | 97 | output keycode, 98 | output keypress_strobe 99 | ); 100 | 101 | modport slave ( 102 | input TEXT_MODE, 103 | input MIXED_MODE, 104 | input PAGE2, 105 | input HIRES_MODE, 106 | input AN0, 107 | input AN1, 108 | input AN2, 109 | input AN3, 110 | 111 | input STORE80, 112 | input RAMRD, 113 | input RAMWRT, 114 | input INTCXROM, 115 | input ALTZP, 116 | input SLOTC3ROM, 117 | input COL80, 118 | input ALTCHAR, 119 | 120 | input INTC8ROM, 121 | 122 | input SLOTROM, 123 | 124 | input TEXT_COLOR, 125 | input BACKGROUND_COLOR, 126 | input BORDER_COLOR, 127 | input MONOCHROME_MODE, 128 | input MONOCHROME_DHIRES_MODE, 129 | input SHRG_MODE, 130 | input LINEARIZE_MODE, 131 | 132 | input aux_mem, 133 | 134 | input keycode, 135 | input keypress_strobe 136 | ); 137 | 138 | endinterface: a2mem_if 139 | 140 | 141 | 142 | -------------------------------------------------------------------------------- /hdl/picosoc/peripherals/a2disk/picosoc_a2disk.sv: -------------------------------------------------------------------------------- 1 | // 2 | // PicoSoC peripheral to interface the PicoSoC to the A2FPGA core 3 | // 4 | // (c) 2023,2024 Ed Anuff 5 | // 6 | // Permission to use, copy, modify, and/or distribute this software for any 7 | // purpose with or without fee is hereby granted, provided that the above 8 | // copyright notice and this permission notice appear in all copies. 9 | // 10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | // 18 | // Description: 19 | // 20 | // Exposes the A2FPGA core to the PicoSoC as memory-mapped I/O 21 | // 22 | 23 | 24 | module picosoc_a2disk ( 25 | input clk, 26 | input resetn, 27 | 28 | input iomem_valid, 29 | input [3:0] iomem_wstrb, 30 | input [31:0] iomem_addr, 31 | output reg [31:0] iomem_rdata, 32 | output reg iomem_ready, 33 | input [31:0] iomem_wdata, 34 | 35 | a2bus_if.slave a2bus_if, 36 | drive_volume_if.volume volumes[2] 37 | ); 38 | 39 | localparam ADDR_VOL_READY = 8'h00; // V0 ready 40 | localparam ADDR_VOL_ACTIVE = 8'h04; // V0 active 41 | localparam ADDR_VOL_MOUNTED = 8'h08; // V0 mounted 42 | localparam ADDR_VOL_READONLY = 8'h0C; // V0 readonly 43 | localparam ADDR_VOL_SIZE = 8'h10; // V0 size 44 | localparam ADDR_VOL_LBA = 8'h14; // V0 lba, 45 | localparam ADDR_VOL_BLK_CNT = 8'h18; // V0 blk_cnt, 46 | localparam ADDR_VOL_RD = 8'h1C; // V0 rd, 47 | localparam ADDR_VOL_WR = 8'h20; // V0 wr, 48 | localparam ADDR_VOL_ACK = 8'h24; // V0 ack 49 | 50 | reg volume_ready_r[2]; 51 | reg volume_mounted_r[2]; 52 | reg volume_readonly_r[2]; 53 | reg [31:0] volume_size_r[2]; 54 | reg volume_ack_r[2]; 55 | 56 | assign volumes[0].ready = volume_ready_r[0]; 57 | assign volumes[0].mounted = volume_mounted_r[0]; 58 | assign volumes[0].readonly = volume_readonly_r[0]; 59 | assign volumes[0].size = volume_size_r[0]; 60 | assign volumes[0].ack = volume_ack_r[0]; 61 | 62 | assign volumes[1].ready = volume_ready_r[1]; 63 | assign volumes[1].mounted = volume_mounted_r[1]; 64 | assign volumes[1].readonly = volume_readonly_r[1]; 65 | assign volumes[1].size = volume_size_r[1]; 66 | assign volumes[1].ack = volume_ack_r[1]; 67 | 68 | wire volume_active_w[2]; 69 | wire [31:0] volume_lba_w[2]; 70 | wire [5:0] volume_blk_cnt_w[2]; 71 | wire volume_rd_w[2]; 72 | wire volume_wr_w[2]; 73 | 74 | assign volume_active_w[0] = volumes[0].active; 75 | assign volume_lba_w[0] = volumes[0].lba; 76 | assign volume_blk_cnt_w[0] = volumes[0].blk_cnt; 77 | assign volume_rd_w[0] = volumes[0].rd; 78 | assign volume_wr_w[0] = volumes[0].wr; 79 | 80 | assign volume_active_w[1] = volumes[1].active; 81 | assign volume_lba_w[1] = volumes[1].lba; 82 | assign volume_blk_cnt_w[1] = volumes[1].blk_cnt; 83 | assign volume_rd_w[1] = volumes[1].rd; 84 | assign volume_wr_w[1] = volumes[1].wr; 85 | 86 | always @(posedge clk) begin 87 | 88 | iomem_ready <= 0; 89 | iomem_rdata <= 32'b0; 90 | 91 | if (iomem_valid) begin 92 | if (|iomem_wstrb) begin 93 | case (iomem_addr[5:2]) 94 | ADDR_VOL_READY[5:2]: volume_ready_r[iomem_addr[7]] <= iomem_wdata[0]; 95 | ADDR_VOL_MOUNTED[5:2]: volume_mounted_r[iomem_addr[7]] <= iomem_wdata[0]; 96 | ADDR_VOL_READONLY[5:2]: volume_readonly_r[iomem_addr[7]] <= iomem_wdata[0]; 97 | ADDR_VOL_SIZE[5:2]: volume_size_r[iomem_addr[7]] <= iomem_wdata; 98 | ADDR_VOL_ACK[5:2]: volume_ack_r[iomem_addr[7]] <= iomem_wdata[0]; 99 | default: ; 100 | endcase 101 | end else begin 102 | case (iomem_addr[5:2]) 103 | ADDR_VOL_ACTIVE[5:2]: iomem_rdata <= {31'b0, volume_active_w[iomem_addr[7]]}; 104 | ADDR_VOL_LBA[5:2]: iomem_rdata <= volume_lba_w[iomem_addr[7]]; 105 | ADDR_VOL_BLK_CNT[5:2]: iomem_rdata <= {26'b0, volume_blk_cnt_w[iomem_addr[7]]}; 106 | ADDR_VOL_RD[5:2]: iomem_rdata <= {31'b0, volume_rd_w[iomem_addr[7]]}; 107 | ADDR_VOL_WR[5:2]: iomem_rdata <= {31'b0, volume_wr_w[iomem_addr[7]]}; 108 | default: ; 109 | endcase 110 | end 111 | 112 | iomem_ready <= 1; 113 | end 114 | end 115 | 116 | endmodule 117 | -------------------------------------------------------------------------------- /hdl/picosoc/peripherals/a2slots/picosoc_a2slots.sv: -------------------------------------------------------------------------------- 1 | // 2 | // PicoSoC peripheral to interface the PicoSoC to the A2FPGA core 3 | // 4 | // (c) 2023,2024 Ed Anuff 5 | // 6 | // Permission to use, copy, modify, and/or distribute this software for any 7 | // purpose with or without fee is hereby granted, provided that the above 8 | // copyright notice and this permission notice appear in all copies. 9 | // 10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | // 18 | // Description: 19 | // 20 | // Exposes the A2FPGA core to the PicoSoC as memory-mapped I/O 21 | // 22 | 23 | 24 | module picosoc_a2slots ( 25 | input clk, 26 | input resetn, 27 | 28 | input iomem_valid, 29 | input [3:0] iomem_wstrb, 30 | input [31:0] iomem_addr, 31 | output reg [31:0] iomem_rdata, 32 | output iomem_ready, 33 | input [31:0] iomem_wdata, 34 | 35 | a2bus_if.slave a2bus_if, 36 | slotmaker_config_if.controller slotmaker_config_if 37 | ); 38 | 39 | reg ready_queue[2:0]; 40 | always @(posedge clk) 41 | ready_queue <= {ready_queue[1:0], iomem_valid}; 42 | assign iomem_ready = ready_queue[2] & iomem_valid; 43 | 44 | wire [2:0] slot = iomem_addr[4:2]; 45 | wire [7:0] card = iomem_wdata[7:0]; 46 | wire wr = iomem_valid && |iomem_wstrb; 47 | assign slotmaker_config_if.slot = slot; 48 | assign slotmaker_config_if.card_i = card; 49 | assign slotmaker_config_if.wr = wr; 50 | 51 | // trigger the slotmaker to reconfigure on write 52 | // 53 | // reconfiguration takes 16 clock cycles but can 54 | // be restarted at any time so it's safe to do this 55 | // 56 | // PicoRV32 takes 4 cycles per instruction so a 57 | // very tight loop might restart the reconfiguration 58 | // before it completes, although it's unlikely 59 | // and should be harmless if it does 60 | // 61 | assign slotmaker_config_if.reconfig = wr; 62 | 63 | always @(posedge clk) 64 | iomem_rdata <= {24'b0, slotmaker_config_if.card_o}; 65 | 66 | endmodule 67 | -------------------------------------------------------------------------------- /hdl/picosoc/peripherals/gpio/picosoc_gpio.sv: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * 4 | */ 5 | module picosoc_gpio #( 6 | parameter int CLOCK_SPEED_HZ = 50_000_000 7 | ) ( 8 | input resetn, 9 | input clk, 10 | input iomem_valid, 11 | input [3:0] iomem_wstrb, 12 | input [31:0] iomem_addr, 13 | output reg [31:0] iomem_rdata, 14 | output reg iomem_ready, 15 | input [31:0] iomem_wdata, 16 | input button, 17 | output reg led, 18 | output ws2812); 19 | 20 | localparam ADDR_LED = 8'h00; 21 | localparam ADDR_RGB = 8'h04; 22 | localparam ADDR_BUTTON = 8'h08; 23 | 24 | reg [23:0] rgb; 25 | 26 | always @(posedge clk) begin 27 | iomem_ready <= 0; 28 | iomem_rdata <= 32'b0; 29 | if (iomem_valid) begin 30 | if (|iomem_wstrb) begin 31 | case (iomem_addr[7:2]) 32 | ADDR_LED[7:2]: led <= iomem_wdata[0]; 33 | ADDR_RGB[7:2]: rgb <= iomem_wdata[23:0]; 34 | default: ; 35 | endcase 36 | end else begin 37 | case (iomem_addr[7:2]) 38 | ADDR_BUTTON[7:2]: iomem_rdata <= {31'b0, button}; 39 | default: ; 40 | endcase 41 | end 42 | iomem_ready <= 1; 43 | end 44 | end 45 | 46 | ws2812 #(.CLK_FRE(CLOCK_SPEED_HZ)) ws2812_inst ( 47 | .clk(clk), 48 | .rgb(rgb), 49 | .WS2812(ws2812) 50 | ); 51 | 52 | endmodule 53 | -------------------------------------------------------------------------------- /hdl/picosoc/peripherals/sdcard/picosoc_sdcard.sv: -------------------------------------------------------------------------------- 1 | 2 | module picosoc_sdcard #(parameter int CLOCK_SPEED_HZ = 0) 3 | ( 4 | input resetn, 5 | input clk, 6 | input iomem_valid, 7 | output reg iomem_ready, 8 | input [3:0] iomem_wstrb, 9 | input [31:0] iomem_addr, 10 | input [31:0] iomem_wdata, 11 | output reg [31:0] iomem_rdata, 12 | output SD_MOSI, 13 | input SD_MISO, 14 | output SD_SCK, 15 | output SD_CS); 16 | 17 | reg spi_wr, spi_rd; 18 | reg [31:0] spi_rdata; 19 | reg spi_ready; 20 | spi_master #(.CLOCK_FREQ_HZ(CLOCK_SPEED_HZ), .CS_LENGTH(1)) sd ( 21 | .clk(clk), 22 | .resetn(resetn), 23 | .ctrl_wr(spi_wr), 24 | .ctrl_rd(spi_rd), 25 | .ctrl_addr(iomem_addr[7:0]), 26 | .ctrl_wdat(iomem_wdata), 27 | .ctrl_rdat(spi_rdata), 28 | .ctrl_done(spi_ready), 29 | .mosi(SD_MOSI), 30 | .miso(SD_MISO), 31 | .sclk(SD_SCK), 32 | .CS(SD_CS)); 33 | 34 | 35 | always @(posedge clk) begin 36 | spi_wr <= 0; 37 | spi_rd <= 0; 38 | iomem_ready <= 0; 39 | if (iomem_valid && !iomem_ready) begin 40 | iomem_ready <= spi_ready; 41 | iomem_rdata <= spi_rdata; 42 | spi_wr <= spi_ready ? 0 : iomem_wstrb[0]; 43 | spi_rd <= !iomem_wstrb && !spi_ready; 44 | end 45 | end 46 | 47 | endmodule 48 | -------------------------------------------------------------------------------- /hdl/picosoc/peripherals/sdcard/spi_master.v: -------------------------------------------------------------------------------- 1 | module spi_master #( 2 | parameter integer CLOCK_FREQ_HZ = 0, 3 | parameter integer CS_LENGTH = 32 4 | ) ( 5 | input clk, 6 | input resetn, 7 | 8 | input ctrl_wr, 9 | input ctrl_rd, 10 | input [ 7:0] ctrl_addr, 11 | input [31:0] ctrl_wdat, 12 | output reg [31:0] ctrl_rdat, 13 | output reg ctrl_done, 14 | 15 | output [CS_LENGTH-1:0] CS, 16 | output mosi, 17 | input miso, 18 | output sclk 19 | ); 20 | wire spi_miso; 21 | reg spi_mosi, spi_sclk; 22 | reg [CS_LENGTH-1:0] spi_cs; 23 | 24 | reg mode_cpol; 25 | reg mode_cpha; 26 | 27 | reg [7:0] prescale_cnt; 28 | reg [7:0] prescale_cfg; 29 | reg [7:0] spi_data; 30 | reg [4:0] spi_state; 31 | 32 | assign spi_miso = miso; 33 | assign mosi = spi_mosi; 34 | assign sclk = spi_sclk ^ ~mode_cpol; 35 | assign CS = spi_cs; 36 | 37 | always @(posedge clk) begin 38 | ctrl_rdat <= 'bx; 39 | ctrl_done <= 0; 40 | if (!resetn) begin 41 | spi_mosi <= 0; 42 | spi_sclk <= 1; 43 | spi_cs <= ~0; 44 | 45 | mode_cpol <= 1; 46 | mode_cpha <= 1; 47 | prescale_cnt <= 0; 48 | prescale_cfg <= 0; 49 | spi_state <= 0; 50 | end else 51 | if (!ctrl_done) begin 52 | if (ctrl_wr) begin 53 | ctrl_done <= 1; 54 | if (ctrl_addr == 'h00) prescale_cfg <= ctrl_wdat[7:0]; 55 | if (ctrl_addr == 'h04) begin 56 | spi_cs <= ctrl_wdat[0]; 57 | ctrl_done <= prescale_cnt == prescale_cfg; 58 | prescale_cnt <= prescale_cnt == prescale_cfg ? 0 : 8'(prescale_cnt + 1'd1); 59 | end 60 | if (ctrl_addr == 'h08) begin 61 | if (!prescale_cnt) begin 62 | if (spi_state == 0) begin 63 | spi_data <= ctrl_wdat[7:0]; 64 | spi_mosi <= ctrl_wdat[7]; 65 | end else begin 66 | if (spi_state[0]) 67 | spi_data <= {spi_data[6:0], spi_miso}; 68 | else if (spi_state < 16) 69 | spi_mosi <= spi_data[7]; 70 | end 71 | end 72 | spi_sclk <= spi_state[0] ^ ~mode_cpha; 73 | ctrl_done <= spi_state == (mode_cpha ? 15 : 16) && prescale_cnt == prescale_cfg; 74 | spi_state <= prescale_cnt == prescale_cfg ? (spi_state[4] ? 0 : 5'(spi_state + 1'd1)) : spi_state; 75 | if (mode_cpha) spi_state[4] <= 0; 76 | prescale_cnt <= prescale_cnt == prescale_cfg ? 0 : 8'(prescale_cnt + 1'd1); 77 | end 78 | if (ctrl_addr == 'h0c) begin 79 | {mode_cpol, mode_cpha} <= ctrl_wdat[1:0]; 80 | ctrl_done <= prescale_cnt == prescale_cfg; 81 | prescale_cnt <= prescale_cnt == prescale_cfg ? 0 : 8'(prescale_cnt + 1'd1); 82 | end 83 | end 84 | if (ctrl_rd) begin 85 | ctrl_done <= 1; 86 | if (ctrl_addr == 'h00) ctrl_rdat <= prescale_cfg; 87 | if (ctrl_addr == 'h04) ctrl_rdat <= spi_cs; 88 | if (ctrl_addr == 'h08) ctrl_rdat <= spi_data; 89 | if (ctrl_addr == 'h0c) ctrl_rdat <= {mode_cpol, mode_cpha}; 90 | end 91 | end 92 | end 93 | endmodule 94 | 95 | -------------------------------------------------------------------------------- /hdl/picosoc/peripherals/sdram/fast_cache.sv: -------------------------------------------------------------------------------- 1 | module fast_cache #( 2 | parameter DATA_WIDTH = 32, 3 | parameter ADDR_WIDTH = 24, 4 | parameter OFFSET_BITS = 2, 5 | parameter INDEX_BITS = 10, // 2^10 = 1024 lines 6 | parameter TAG_BITS = ADDR_WIDTH - OFFSET_BITS - INDEX_BITS, 7 | parameter CACHE_DEPTH = 1 << INDEX_BITS // 1024 lines 8 | ) ( 9 | input clk, 10 | input we, 11 | input [ADDR_WIDTH-1:0] addr_i, 12 | output [DATA_WIDTH-1:0] data_o, 13 | input [DATA_WIDTH-1:0] data_i, 14 | output hit 15 | ); 16 | 17 | // Cache storage 18 | reg [DATA_WIDTH+TAG_BITS:0] cache_data[CACHE_DEPTH-1:0]; 19 | reg [DATA_WIDTH+TAG_BITS:0] current_line; 20 | 21 | // Address decomposition 22 | wire [TAG_BITS-1:0] tag = addr_i[ADDR_WIDTH-1:OFFSET_BITS+INDEX_BITS]; 23 | wire [INDEX_BITS-1:0] index = addr_i[OFFSET_BITS+INDEX_BITS-1:OFFSET_BITS]; 24 | // Offset not used in this simple example 25 | 26 | // Read operation 27 | always @(posedge clk) begin 28 | if (we) begin 29 | cache_data[index] <= {1'b1, tag, data_i}; 30 | current_line <= {1'b1, tag, data_i}; 31 | end else begin 32 | current_line <= cache_data[index]; 33 | end 34 | end 35 | 36 | assign hit = current_line[DATA_WIDTH+TAG_BITS:DATA_WIDTH] == {1'b1, tag}; 37 | assign data_o = current_line[DATA_WIDTH-1:0]; 38 | 39 | endmodule 40 | -------------------------------------------------------------------------------- /hdl/picosoc/peripherals/sdram/picosoc_sdram.sv: -------------------------------------------------------------------------------- 1 | // 2 | // PicoSoC SDRAM Interface 3 | // 4 | // (c) 2023,2024 Ed Anuff 5 | // 6 | // Permission to use, copy, modify, and/or distribute this software for any 7 | // purpose with or without fee is hereby granted, provided that the above 8 | // copyright notice and this permission notice appear in all copies. 9 | // 10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | // 18 | // Description: 19 | // 20 | // Exposes the SDRAM to the PicoSoC as a memory-mapped device 21 | // 22 | 23 | module picosoc_sdram 24 | ( 25 | a2bus_if.slave a2bus_if, 26 | input iomem_valid, 27 | input [3:0] iomem_wstrb, 28 | input [31:0] iomem_addr, 29 | output wire [31:0] iomem_rdata, 30 | output wire iomem_ready, 31 | input [31:0] iomem_wdata, 32 | input iomem_instr, 33 | input [31:0] iomem_la_addr, 34 | sdram_port_if.client mem_if 35 | ); 36 | 37 | wire cache_hit; 38 | wire [31:0] cache_data; 39 | 40 | wire mem_wr = iomem_valid & (iomem_wstrb != 4'h0); 41 | wire mem_rd = iomem_valid & (iomem_wstrb == 4'h0) & ~(iomem_instr & cache_hit); 42 | assign mem_if.addr = iomem_addr[22:2]; 43 | assign mem_if.data = iomem_wdata; 44 | assign mem_if.wr = mem_wr; 45 | assign mem_if.rd = mem_rd; 46 | assign mem_if.byte_en = iomem_wstrb; 47 | assign iomem_rdata = iomem_instr ? cache_data : mem_if.q; 48 | assign iomem_ready = iomem_instr ? iomem_valid & cache_hit : mem_if.ready; 49 | 50 | fast_cache #( 51 | .DATA_WIDTH(32), 52 | .ADDR_WIDTH(21), 53 | .OFFSET_BITS(0), 54 | .INDEX_BITS(6) 55 | ) instr_cache ( 56 | .clk(a2bus_if.clk_logic), 57 | .we(iomem_instr & mem_if.ready), 58 | .addr_i(iomem_la_addr[22:2]), 59 | .data_o(cache_data), 60 | .data_i(mem_if.q), 61 | .hit(cache_hit) 62 | ); 63 | 64 | endmodule 65 | -------------------------------------------------------------------------------- /hdl/picosoc/peripherals/sram/picosoc_sram.sv: -------------------------------------------------------------------------------- 1 | module picosoc_sram #( 2 | parameter integer MEM_WORDS = 256 3 | ) 4 | ( 5 | input resetn, 6 | input clk, 7 | input iomem_valid, 8 | input [3:0] iomem_wstrb, 9 | input [31:0] iomem_addr, 10 | output reg [31:0] iomem_rdata, 11 | output reg iomem_ready, 12 | input [31:0] iomem_wdata 13 | ); 14 | 15 | wire ram_ready = iomem_valid && !iomem_ready && (iomem_addr < 4 * MEM_WORDS); 16 | 17 | always @(posedge clk) 18 | iomem_ready <= ram_ready; 19 | 20 | wire [3:0] wen = ram_ready ? iomem_wstrb : 4'b0; 21 | wire [21:0] addr = iomem_addr[23:2]; 22 | 23 | reg [31:0] mem [0:MEM_WORDS-1]; 24 | 25 | initial $readmemh("firmware.hex", mem); 26 | always @(posedge clk) begin 27 | iomem_rdata <= mem[addr]; 28 | if (wen[0]) mem[addr][ 7: 0] <= iomem_wdata[ 7: 0]; 29 | if (wen[1]) mem[addr][15: 8] <= iomem_wdata[15: 8]; 30 | if (wen[2]) mem[addr][23:16] <= iomem_wdata[23:16]; 31 | if (wen[3]) mem[addr][31:24] <= iomem_wdata[31:24]; 32 | end 33 | 34 | 35 | endmodule 36 | -------------------------------------------------------------------------------- /hdl/picosoc/peripherals/uart/picosoc_uart.sv: -------------------------------------------------------------------------------- 1 | module picosoc_uart #( 2 | parameter int CLOCK_SPEED_HZ = 50_000_000, 3 | parameter int BAUD_RATE = 115200 4 | ) 5 | ( 6 | input resetn, 7 | input clk, 8 | input iomem_valid, 9 | input [3:0] iomem_wstrb, 10 | input [31:0] iomem_addr, 11 | output [31:0] iomem_rdata, 12 | output iomem_ready, 13 | input [31:0] iomem_wdata, 14 | input uart_rx_i, 15 | output uart_tx_o 16 | ); 17 | 18 | wire simpleuart_reg_div_sel = iomem_valid && (iomem_addr == 32'h 0200_0004); 19 | wire [31:0] simpleuart_reg_div_do; 20 | 21 | wire simpleuart_reg_dat_sel = iomem_valid && (iomem_addr == 32'h 0200_0008); 22 | wire [31:0] simpleuart_reg_dat_do; 23 | wire simpleuart_reg_dat_wait; 24 | 25 | assign iomem_ready = simpleuart_reg_div_sel || (simpleuart_reg_dat_sel && !simpleuart_reg_dat_wait); 26 | 27 | assign iomem_rdata = simpleuart_reg_div_sel ? simpleuart_reg_div_do : 28 | simpleuart_reg_dat_sel ? simpleuart_reg_dat_do : 29 | 32'h 0000_0000; 30 | 31 | simpleuart #( 32 | .DEFAULT_DIV(CLOCK_SPEED_HZ / BAUD_RATE) 33 | ) simpleuart ( 34 | .clk(clk), 35 | .resetn(resetn), 36 | 37 | .ser_tx(uart_tx_o), 38 | .ser_rx(uart_rx_i), 39 | 40 | .reg_div_we(simpleuart_reg_div_sel ? iomem_wstrb : 4'b 0000), 41 | .reg_div_di(iomem_wdata), 42 | .reg_div_do(simpleuart_reg_div_do), 43 | 44 | .reg_dat_we(simpleuart_reg_dat_sel ? iomem_wstrb[0] : 1'b 0), 45 | .reg_dat_re(simpleuart_reg_dat_sel && !iomem_wstrb), 46 | .reg_dat_di(iomem_wdata), 47 | .reg_dat_do(simpleuart_reg_dat_do), 48 | .reg_dat_wait(simpleuart_reg_dat_wait) 49 | ); 50 | 51 | endmodule 52 | -------------------------------------------------------------------------------- /hdl/picosoc/peripherals/uart/simpleuart.v: -------------------------------------------------------------------------------- 1 | /* 2 | * PicoSoC - A simple example SoC using PicoRV32 3 | * 4 | * Copyright (C) 2017 Claire Xenia Wolf 5 | * 6 | * Permission to use, copy, modify, and/or distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | * 18 | */ 19 | 20 | module simpleuart #(parameter integer DEFAULT_DIV = 468) ( 21 | input clk, 22 | input resetn, 23 | 24 | output ser_tx, 25 | input ser_rx, 26 | 27 | input [3:0] reg_div_we, 28 | input [31:0] reg_div_di, 29 | output [31:0] reg_div_do, 30 | 31 | input reg_dat_we, 32 | input reg_dat_re, 33 | input [31:0] reg_dat_di, 34 | output [31:0] reg_dat_do, 35 | output reg_dat_wait 36 | ); 37 | reg [31:0] cfg_divider; 38 | 39 | reg [3:0] recv_state; 40 | reg [31:0] recv_divcnt; 41 | reg [7:0] recv_pattern; 42 | reg [7:0] recv_buf_data; 43 | reg recv_buf_valid; 44 | 45 | reg [9:0] send_pattern; 46 | reg [3:0] send_bitcnt; 47 | reg [31:0] send_divcnt; 48 | reg send_dummy; 49 | 50 | assign reg_div_do = cfg_divider; 51 | 52 | assign reg_dat_wait = reg_dat_we && (send_bitcnt || send_dummy); 53 | assign reg_dat_do = recv_buf_valid ? recv_buf_data : ~0; 54 | 55 | always @(posedge clk) begin 56 | if (!resetn) begin 57 | cfg_divider <= DEFAULT_DIV; 58 | end else begin 59 | if (reg_div_we[0]) cfg_divider[ 7: 0] <= reg_div_di[ 7: 0]; 60 | if (reg_div_we[1]) cfg_divider[15: 8] <= reg_div_di[15: 8]; 61 | if (reg_div_we[2]) cfg_divider[23:16] <= reg_div_di[23:16]; 62 | if (reg_div_we[3]) cfg_divider[31:24] <= reg_div_di[31:24]; 63 | end 64 | end 65 | 66 | always @(posedge clk) begin 67 | if (!resetn) begin 68 | recv_state <= 0; 69 | recv_divcnt <= 0; 70 | recv_pattern <= 0; 71 | recv_buf_data <= 0; 72 | recv_buf_valid <= 0; 73 | end else begin 74 | recv_divcnt <= recv_divcnt + 1; 75 | if (reg_dat_re) 76 | recv_buf_valid <= 0; 77 | case (recv_state) 78 | 0: begin 79 | if (!ser_rx) 80 | recv_state <= 1; 81 | recv_divcnt <= 0; 82 | end 83 | 1: begin 84 | if (2*recv_divcnt > cfg_divider) begin 85 | recv_state <= 2; 86 | recv_divcnt <= 0; 87 | end 88 | end 89 | 10: begin 90 | if (recv_divcnt > cfg_divider) begin 91 | recv_buf_data <= recv_pattern; 92 | recv_buf_valid <= 1; 93 | recv_state <= 0; 94 | end 95 | end 96 | default: begin 97 | if (recv_divcnt > cfg_divider) begin 98 | recv_pattern <= {ser_rx, recv_pattern[7:1]}; 99 | recv_state <= recv_state + 1'd1; 100 | recv_divcnt <= 0; 101 | end 102 | end 103 | endcase 104 | end 105 | end 106 | 107 | assign ser_tx = send_pattern[0]; 108 | 109 | always @(posedge clk) begin 110 | if (reg_div_we) 111 | send_dummy <= 1; 112 | send_divcnt <= send_divcnt + 1; 113 | if (!resetn) begin 114 | send_pattern <= ~0; 115 | send_bitcnt <= 0; 116 | send_divcnt <= 0; 117 | send_dummy <= 1; 118 | end else begin 119 | if (send_dummy && !send_bitcnt) begin 120 | send_pattern <= ~0; 121 | send_bitcnt <= 15; 122 | send_divcnt <= 0; 123 | send_dummy <= 0; 124 | end else 125 | if (reg_dat_we && !send_bitcnt) begin 126 | send_pattern <= {1'b1, reg_dat_di[7:0], 1'b0}; 127 | send_bitcnt <= 10; 128 | send_divcnt <= 0; 129 | end else 130 | if (send_divcnt > cfg_divider && send_bitcnt) begin 131 | send_pattern <= {1'b1, send_pattern[9:1]}; 132 | send_bitcnt <= send_bitcnt - 1'd1; 133 | send_divcnt <= 0; 134 | end 135 | end 136 | end 137 | endmodule 138 | -------------------------------------------------------------------------------- /hdl/sdram/sdram_if_cdc.sv: -------------------------------------------------------------------------------- 1 | module sdram_if_cdc #( 2 | parameter N = 3 // Stretch factor, default value set to 3 (2X clock diff + 1) 3 | ) 4 | ( 5 | input clk_controller, 6 | input clk_client, 7 | sdram_port_if.client controller, 8 | sdram_port_if.controller client 9 | ); 10 | 11 | pulse_crossing #(.N(N)) mem_ready_pulse ( 12 | .clk_src(clk_controller), 13 | .clk_dst(clk_client), 14 | .pulse_src(controller.ready), 15 | .pulse_dst(client.ready) 16 | ); 17 | 18 | assign controller.addr = client.addr; 19 | assign controller.data = client.data; 20 | assign controller.byte_en = client.byte_en; 21 | assign client.q = controller.q; 22 | assign controller.wr = client.wr; 23 | assign controller.rd = client.rd; 24 | assign client.available = controller.available; 25 | 26 | endmodule -------------------------------------------------------------------------------- /hdl/sdram/sdram_if_mux.sv: -------------------------------------------------------------------------------- 1 | // 2 | // SDRAM port mux 3 | // 4 | // (c) 2023,2024 Ed Anuff 5 | // 6 | // Permission to use, copy, modify, and/or distribute this software for any 7 | // purpose with or without fee is hereby granted, provided that the above 8 | // copyright notice and this permission notice appear in all copies. 9 | // 10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | // 18 | // Description: 19 | // 20 | // Multiplexes two SDRAM ports to a single controller port 21 | // 22 | 23 | module sdram_if_mux ( 24 | input switch, 25 | sdram_port_if.client controller, 26 | sdram_port_if.controller client_0, 27 | sdram_port_if.controller client_1 28 | ); 29 | 30 | always @* begin : mux 31 | if (!switch) begin 32 | controller.addr = client_0.addr; 33 | controller.data = client_0.data; 34 | controller.byte_en = client_0.byte_en; 35 | client_0.q = controller.q; 36 | controller.wr = client_0.wr; 37 | controller.rd = client_0.rd; 38 | client_0.available = controller.available; 39 | client_0.ready = controller.ready; 40 | 41 | client_1.q = '0; 42 | client_1.available = 1'b0; 43 | client_1.ready = 1'b0; 44 | end else begin 45 | controller.addr = client_1.addr; 46 | controller.data = client_1.data; 47 | controller.byte_en = client_1.byte_en; 48 | client_1.q = controller.q; 49 | controller.wr = client_1.wr; 50 | controller.rd = client_1.rd; 51 | client_1.available = controller.available; 52 | client_1.ready = controller.ready; 53 | 54 | client_0.q = '0; 55 | client_0.available = 1'b0; 56 | client_0.ready = 1'b0; 57 | end 58 | end 59 | 60 | endmodule -------------------------------------------------------------------------------- /hdl/sdram/sdram_port_if.sv: -------------------------------------------------------------------------------- 1 | // 2 | // SystemVerilog interface for a SDRAM port 3 | // 4 | // (c) 2023,2024 Ed Anuff 5 | // 6 | // Permission to use, copy, modify, and/or distribute this software for any 7 | // purpose with or without fee is hereby granted, provided that the above 8 | // copyright notice and this permission notice appear in all copies. 9 | // 10 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | // 18 | // Description: 19 | // 20 | // SystemVerilog interface for a SDRAM port 21 | // 22 | 23 | interface sdram_port_if #( 24 | parameter PORT_ADDR_WIDTH = 12, 25 | parameter DATA_WIDTH = 16, 26 | parameter DQM_WIDTH = 2, 27 | parameter PORT_OUTPUT_WIDTH = DATA_WIDTH * 2 28 | ); 29 | 30 | logic [PORT_ADDR_WIDTH-1:0] addr; 31 | logic [DATA_WIDTH-1:0] data; 32 | logic [DQM_WIDTH-1:0] byte_en; // Byte enable for writes 33 | logic [PORT_OUTPUT_WIDTH-1:0] q; 34 | 35 | logic wr; 36 | logic rd; 37 | 38 | logic available; // The port is able to be used 39 | logic ready; // The port has finished its task. Will rise for a single cycle 40 | 41 | modport controller ( 42 | input addr, 43 | input data, 44 | input byte_en, 45 | output q, 46 | 47 | input wr, 48 | input rd, 49 | 50 | output available, 51 | output ready 52 | ); 53 | 54 | modport client ( 55 | output addr, 56 | output data, 57 | output byte_en, 58 | input q, 59 | 60 | output wr, 61 | output rd, 62 | 63 | input available, 64 | input ready 65 | ); 66 | 67 | endinterface: sdram_port_if 68 | -------------------------------------------------------------------------------- /hdl/slots/slot_if.sv: -------------------------------------------------------------------------------- 1 | 2 | interface slot_if (); 3 | 4 | logic [2:0] slot; 5 | logic [7:0] card_id; 6 | logic io_select_n; 7 | logic dev_select_n; 8 | logic io_strobe_n; 9 | 10 | logic config_select_n; 11 | logic [31:0] card_config; 12 | logic card_enable; 13 | 14 | modport slotmaker ( 15 | output slot, 16 | output card_id, 17 | output io_select_n, 18 | output dev_select_n, 19 | output io_strobe_n, 20 | 21 | output config_select_n, 22 | output card_config, 23 | output card_enable 24 | ); 25 | 26 | modport card ( 27 | input slot, 28 | input card_id, 29 | input io_select_n, 30 | input dev_select_n, 31 | input io_strobe_n, 32 | 33 | input config_select_n, 34 | input card_config, 35 | input card_enable 36 | ); 37 | 38 | endinterface 39 | 40 | -------------------------------------------------------------------------------- /hdl/slots/slotmaker_config_if.sv: -------------------------------------------------------------------------------- 1 | interface slotmaker_config_if(); 2 | logic [2:0] slot; 3 | logic wr; 4 | logic [7:0] card_i; 5 | logic [7:0] card_o; 6 | logic reconfig; 7 | 8 | modport slotmaker ( 9 | input slot, 10 | input wr, 11 | input card_i, 12 | output card_o, 13 | input reconfig 14 | ); 15 | 16 | modport controller ( 17 | output slot, 18 | output wr, 19 | output card_i, 20 | input card_o, 21 | output reconfig 22 | ); 23 | 24 | endinterface -------------------------------------------------------------------------------- /hdl/slots/slots.hex: -------------------------------------------------------------------------------- 1 | 00 00 03 00 02 04 00 01 -------------------------------------------------------------------------------- /hdl/sound/apple_speaker.sv: -------------------------------------------------------------------------------- 1 | module apple_speaker ( 2 | a2bus_if.slave a2bus_if, 3 | input enable, 4 | output reg speaker_o 5 | ); 6 | 7 | reg speaker_bit; 8 | 9 | always @(posedge a2bus_if.clk_logic or negedge a2bus_if.system_reset_n) begin 10 | if (!a2bus_if.system_reset_n) begin 11 | speaker_bit <= 1'b0; 12 | end else if (a2bus_if.phi1_posedge && (a2bus_if.addr[15:0] == 16'hC030) && !a2bus_if.m2sel_n) 13 | speaker_bit <= !speaker_bit; 14 | end 15 | 16 | localparam COUNTDOWN_WIDTH = 20; 17 | reg [COUNTDOWN_WIDTH - 1:0] countdown; 18 | reg prev_speaker_bit; 19 | 20 | always_ff @(posedge a2bus_if.clk_logic) begin 21 | if (speaker_bit != prev_speaker_bit) begin 22 | countdown <= '1; 23 | end else begin 24 | countdown <= countdown != 0 ? COUNTDOWN_WIDTH'(countdown - 1) : '0; 25 | end 26 | prev_speaker_bit <= speaker_bit; 27 | 28 | if ((countdown != 0) && enable) begin 29 | if (speaker_bit) begin 30 | speaker_o <= 1; 31 | end else begin 32 | speaker_o <= 0; 33 | end 34 | end else begin 35 | speaker_o <= 0; 36 | end 37 | end 38 | 39 | endmodule -------------------------------------------------------------------------------- /hdl/sound/audio_out.v: -------------------------------------------------------------------------------- 1 | 2 | module audio_out 3 | #( 4 | parameter CLK_RATE = 24576000, 5 | parameter AUDIO_RATE = 48000 6 | ) 7 | ( 8 | input reset, 9 | input clk, 10 | 11 | input [31:0] flt_rate, 12 | input [39:0] cx, 13 | input [7:0] cx0, 14 | input [7:0] cx1, 15 | input [7:0] cx2, 16 | input [23:0] cy0, 17 | input [23:0] cy1, 18 | input [23:0] cy2, 19 | 20 | input is_signed, 21 | input [15:0] core_l, 22 | input [15:0] core_r, 23 | 24 | output audio_clk, 25 | output [15:0] audio_l, 26 | output [15:0] audio_r 27 | ); 28 | localparam AUDIO_CLK_COUNT = CLK_RATE / AUDIO_RATE; 29 | logic [$clog2(AUDIO_CLK_COUNT)-1:0] audio_counter_r; 30 | reg sample_ce; 31 | always_ff @(posedge clk) 32 | begin 33 | audio_counter_r <= (audio_counter_r == AUDIO_CLK_COUNT) ? 1'd0 : audio_counter_r + 1'd1; 34 | sample_ce <= audio_counter_r == AUDIO_CLK_COUNT; 35 | end 36 | assign audio_clk = sample_ce; 37 | 38 | reg flt_ce; 39 | reg [31:0] cnt = 0; 40 | always @(posedge clk, posedge reset) begin 41 | if(reset) begin 42 | cnt <= 0; 43 | flt_ce <= 0; 44 | end 45 | else begin 46 | flt_ce <= 0; 47 | cnt <= cnt + {flt_rate[30:0],1'b0}; 48 | if(cnt >= CLK_RATE) begin 49 | cnt <= cnt - CLK_RATE; 50 | flt_ce <= 1; 51 | end 52 | end 53 | end 54 | 55 | reg [15:0] cl,cr; 56 | reg [15:0] cl1,cl2; 57 | reg [15:0] cr1,cr2; 58 | always @(posedge clk) begin 59 | cl1 <= core_l; cl2 <= cl1; 60 | if(cl2 == cl1) cl <= cl2; 61 | 62 | cr1 <= core_r; cr2 <= cr1; 63 | if(cr2 == cr1) cr <= cr2; 64 | end 65 | 66 | reg a_en1 = 0, a_en2 = 0; 67 | reg [1:0] dly1 = 0; 68 | reg [14:0] dly2 = 0; 69 | always @(posedge clk, posedge reset) begin 70 | 71 | if(reset) begin 72 | dly1 <= 0; 73 | dly2 <= 0; 74 | a_en1 <= 0; 75 | a_en2 <= 0; 76 | end 77 | else begin 78 | if(flt_ce) begin 79 | if(~&dly1) dly1 <= dly1 + 1'd1; 80 | else a_en1 <= 1; 81 | end 82 | 83 | if(sample_ce) begin 84 | if(!dly2[13]) dly2 <= dly2 + 1'd1; 85 | else a_en2 <= 1; 86 | end 87 | end 88 | end 89 | 90 | wire [15:0] acl, acr; 91 | IIR_filter #(.use_params(0)) IIR_filter 92 | ( 93 | .clk(clk), 94 | .reset(reset), 95 | 96 | .ce(flt_ce & a_en1), 97 | .sample_ce(sample_ce), 98 | 99 | .cx(cx), 100 | .cx0(cx0), 101 | .cx1(cx1), 102 | .cx2(cx2), 103 | .cy0(cy0), 104 | .cy1(cy1), 105 | .cy2(cy2), 106 | 107 | .input_l({~is_signed ^ cl[15], cl[14:0]}), 108 | .input_r({~is_signed ^ cr[15], cr[14:0]}), 109 | .output_l(acl), 110 | .output_r(acr) 111 | ); 112 | 113 | wire [15:0] adl; 114 | DC_blocker dcb_l 115 | ( 116 | .clk(clk), 117 | .ce(sample_ce), 118 | .mute(~a_en2), 119 | .din(acl), 120 | .dout(adl) 121 | ); 122 | 123 | wire [15:0] adr; 124 | DC_blocker dcb_r 125 | ( 126 | .clk(clk), 127 | .ce(sample_ce), 128 | .mute(~a_en2), 129 | .din(acr), 130 | .dout(adr) 131 | ); 132 | 133 | assign audio_l = adl; 134 | assign audio_r = adr; 135 | 136 | 137 | endmodule 138 | -------------------------------------------------------------------------------- /hdl/support/bell.sv: -------------------------------------------------------------------------------- 1 | module bell ( 2 | input clk_50_i, 3 | input reset_n_i, 4 | input trigger_i, 5 | output reg speaker_o, 6 | output wire done_o 7 | ); 8 | 9 | localparam CYCLE_COUNT = 192; 10 | logic [7:0] cycle_counter; 11 | localparam CYCLE_WAIT = 26791; 12 | logic [14:0] wait_counter; 13 | reg prev_trigger_r; 14 | reg playing_r; 15 | assign done_o = !playing_r; 16 | 17 | always @(posedge clk_50_i) begin 18 | prev_trigger_r <= trigger_i; 19 | end 20 | 21 | always @(posedge clk_50_i) begin 22 | if (reset_n_i == 1'b0) begin 23 | playing_r <= 1'b0; 24 | cycle_counter <= 0; 25 | wait_counter <= 0; 26 | speaker_o <= 1'b0; 27 | end else begin 28 | if (!playing_r && !prev_trigger_r && trigger_i) begin 29 | cycle_counter <= CYCLE_COUNT; 30 | wait_counter <= CYCLE_WAIT; 31 | playing_r <= 1'b1; 32 | end else if (playing_r) begin 33 | if (wait_counter > 0) begin 34 | wait_counter <= wait_counter - 15'd1; 35 | end else begin 36 | speaker_o <= !speaker_o; 37 | wait_counter <= CYCLE_WAIT; 38 | if (cycle_counter > 0) begin 39 | cycle_counter <= cycle_counter - 8'd1; 40 | end else begin 41 | playing_r <= 1'b0; 42 | cycle_counter <= 0; 43 | wait_counter <= 0; 44 | end 45 | end 46 | end else begin 47 | speaker_o <= 1'b0; 48 | end 49 | end 50 | end 51 | 52 | 53 | endmodule 54 | 55 | 56 | -------------------------------------------------------------------------------- /hdl/support/cdc.sv: -------------------------------------------------------------------------------- 1 | module cdc ( 2 | input clk, 3 | input i, 4 | output o, 5 | output o_n, 6 | output o_posedge, // o_posedge is asserted on the first posedge of i, o is still 0 7 | output o_negedge // o_negedge is asserted on the first negedge of i, o is still 1 8 | ); 9 | 10 | reg i_sync1, i_sync2; 11 | reg [2:0] i_debounce; 12 | reg i_stable; 13 | 14 | always @(posedge clk) begin 15 | // Step 1: Synchronize slow clock to fast clock domain 16 | i_sync1 <= i; 17 | i_sync2 <= i_sync1; 18 | 19 | // Step 2: Debounce slow clock 20 | i_debounce <= {i_debounce[1:0], i_sync2}; 21 | if (i_debounce == 3'b111) 22 | i_stable <= 1'b1; 23 | else if (i_debounce == 3'b000) 24 | i_stable <= 1'b0; 25 | end 26 | 27 | reg [1:0] fifo = 2'b0 /*synthesis syn_keep=1*/; 28 | 29 | always @(posedge clk) fifo <= {fifo[0], i_stable}; 30 | 31 | assign o = fifo[1]; 32 | assign o_n = !fifo[1]; 33 | assign o_posedge = (fifo == 2'b01); 34 | assign o_negedge = (fifo == 2'b10); 35 | 36 | endmodule 37 | -------------------------------------------------------------------------------- /hdl/support/cdc_fifo.sv: -------------------------------------------------------------------------------- 1 | module cdc_fifo 2 | #( 3 | parameter WIDTH = 8 4 | ) 5 | ( 6 | input clk, 7 | input [WIDTH-1:0] i, 8 | output [WIDTH-1:0] o 9 | ); 10 | 11 | reg [WIDTH-1:0] fifo[3] /*synthesis syn_keep=1*/; 12 | 13 | always @(posedge clk) begin 14 | fifo[0] <= i; 15 | fifo[1] <= fifo[0]; 16 | fifo[2] <= fifo[1]; 17 | end 18 | 19 | assign o = fifo[2]; 20 | 21 | endmodule 22 | -------------------------------------------------------------------------------- /hdl/support/clock_enable_counter.sv: -------------------------------------------------------------------------------- 1 | module clock_enable_counter #( 2 | parameter SIZE = 8 3 | ) ( 4 | input clk, 5 | input ce, 6 | output reg [SIZE-1:0] q 7 | ); 8 | 9 | always @(posedge clk) begin 10 | if (ce) begin 11 | q <= q + 1'b1; 12 | end 13 | end 14 | 15 | endmodule 16 | -------------------------------------------------------------------------------- /hdl/support/countdown.sv: -------------------------------------------------------------------------------- 1 | module countdown #( 2 | parameter CLOCK_FREQ = 54_000_000, // Default clock frequency 3 | parameter CLOCK_DIVIDER = 1_000_000 // Default to microseconds 4 | ) ( 5 | input clk, // Clock input 6 | input reset, // Asynchronous reset 7 | input we, // Write enable 8 | input [31:0] start, // Number to count down from 9 | output reg [31:0] counter, // 32-bit counter 10 | output done // Done flag 11 | ); 12 | 13 | // Calculate the number of cycles to count based on the clock frequency 14 | localparam CYCLES_PER_COUNT = CLOCK_FREQ / CLOCK_DIVIDER; 15 | 16 | // Determine the number of bits required to store CYCLES_PER_COUNT 17 | localparam BITS_FOR_CYCLES = $clog2(CYCLES_PER_COUNT); 18 | 19 | // Counter for cycles 20 | reg [BITS_FOR_CYCLES-1:0] cycles = 0; 21 | 22 | always @(posedge clk or posedge reset) begin 23 | if (reset) begin 24 | // Reset cycles and counter 25 | cycles <= 0; 26 | counter <= 0; 27 | end else begin 28 | if (we) begin 29 | // Reset cycles and counter 30 | cycles <= 0; 31 | counter <= start; 32 | end else begin 33 | if (cycles < CYCLES_PER_COUNT - 1) begin 34 | // Increment cycles 35 | cycles <= cycles + 1'b1; 36 | end else begin 37 | // Reset cycles and decrement counter if not zero 38 | cycles <= 0; 39 | counter <= counter != 0 ? counter - 1'b1 : '0; 40 | end 41 | end 42 | end 43 | end 44 | 45 | assign done = counter == 0; 46 | 47 | endmodule 48 | -------------------------------------------------------------------------------- /hdl/support/dual_set_reg.sv: -------------------------------------------------------------------------------- 1 | module dual_set_reg #( 2 | parameter SIZE = 8 3 | ) ( 4 | input clk, 5 | input a_set, 6 | input [SIZE-1:0] a, 7 | input b_set, 8 | input [SIZE-1:0] b, 9 | output reg [SIZE-1:0] q 10 | ); 11 | 12 | reg a_set_prev, b_set_prev; 13 | 14 | always @(posedge clk) begin 15 | a_set_prev <= a_set; 16 | b_set_prev <= b_set; 17 | 18 | if (!a_set_prev && a_set) begin 19 | q <= a; 20 | end 21 | 22 | if (!b_set_prev && b_set) begin 23 | q <= b; 24 | end 25 | end 26 | 27 | endmodule 28 | -------------------------------------------------------------------------------- /hdl/support/pulse_arbiter.v: -------------------------------------------------------------------------------- 1 | module PulseArbiter ( 2 | input wire clk, 3 | input wire rst_n, 4 | input wire pulseA, 5 | input wire pulseB, 6 | output reg pulseA_out, 7 | output reg pulseB_out 8 | ); 9 | 10 | reg prev_pulseA; 11 | reg prev_pulseB; 12 | 13 | always @(posedge clk) begin 14 | prev_pulseA <= pulseA; 15 | prev_pulseB <= pulseB; 16 | end 17 | wire pulseA_posedge = pulseA & ~prev_pulseA; 18 | wire pulseB_posedge = pulseB & ~prev_pulseB; 19 | 20 | reg [2:0] fifoA = 3'b00; 21 | reg [1:0] fifoB = 2'b00; 22 | 23 | always @(posedge clk or negedge rst_n) begin 24 | if (!rst_n) begin 25 | fifoA <= 3'b00; 26 | fifoB <= 2'b00; 27 | pulseA_out <= 0; 28 | pulseB_out <= 0; 29 | end else begin 30 | // Default output states 31 | pulseA_out <= 0; 32 | pulseB_out <= 0; 33 | 34 | fifoA = {fifoA[1], fifoA[0], 1'b0}; 35 | fifoB = {fifoB[0], 1'b0}; 36 | 37 | if (pulseA_posedge & (pulseB_out | pulseB_posedge) ) begin 38 | if (pulseB_out) fifoA <= 3'b010; 39 | else fifoA <= 3'b001; 40 | if (pulseB_posedge) pulseB_out <= 1; 41 | end else if (pulseA_posedge) begin 42 | pulseA_out <= 1; 43 | end else if (pulseB_posedge & pulseA_out) begin 44 | fifoB <= 2'b01; 45 | end else if (pulseB_posedge) begin 46 | pulseB_out <= 1; 47 | end else if (fifoA[2]) begin 48 | pulseA_out <= 1; 49 | end else if (fifoB[1]) begin 50 | pulseB_out <= 1; 51 | end 52 | 53 | end 54 | end 55 | endmodule 56 | -------------------------------------------------------------------------------- /hdl/support/pulse_crossing.v: -------------------------------------------------------------------------------- 1 | module pulse_crossing 2 | #( 3 | parameter N = 3 // Stretch factor, default value set to 3 (2X clock diff + 1) 4 | ) 5 | ( 6 | input reset, 7 | input wire clk_src, // Source clock 8 | input wire clk_dst, // Destination clock 9 | input wire pulse_src, // Pulse in source domain 10 | output reg pulse_dst // Pulse in destination domain 11 | ); 12 | 13 | reg pulse_stretched; 14 | reg [N-1:0] pulse_fifo = 0; 15 | always @(posedge clk_src) begin 16 | if (reset) 17 | pulse_fifo <= 0; 18 | else begin 19 | pulse_fifo <= {pulse_fifo[N-2:0], pulse_src}; // Load the LSB 20 | pulse_stretched <= pulse_src | |pulse_fifo; // register the stretched pulse 21 | end 22 | end 23 | 24 | // Stage 2: Synchronize the stretched pulse into the destination domain 25 | reg [2:0] sync_fifo = 3'b0; 26 | 27 | always @(posedge clk_dst) begin 28 | if (reset) 29 | sync_fifo <= 3'b0; 30 | else begin 31 | sync_fifo <= {sync_fifo[1:0], pulse_stretched}; 32 | pulse_dst <= sync_fifo[2:1] == 2'b01; 33 | end 34 | end 35 | 36 | // Stage 3: Edge detection in the destination domain 37 | //assign pulse_dst = (sync_fifo[2:1] == 2'b01); 38 | 39 | endmodule 40 | -------------------------------------------------------------------------------- /hdl/support/pulse_generator.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | module pulse_generator #( 4 | parameter COUNT = 10, // Default value of COUNT is 10 5 | parameter WIDTH = $clog2((COUNT > 0 ? COUNT : 1) + 1), // Width of cnt is calculated based on COUNT 6 | parameter ONE = WIDTH'(1) 7 | ) ( 8 | input wire clk, 9 | input wire reset_n, 10 | input wire trigger, 11 | output reg pulse 12 | ); 13 | 14 | reg [WIDTH-1:0] cnt; 15 | reg trigger_d; // delayed version of trigger 16 | 17 | always @(posedge clk or negedge reset_n) begin 18 | if (!reset_n) begin 19 | pulse <= 1'b0; 20 | cnt <= 'b0; 21 | trigger_d <= 1'b0; 22 | end else begin 23 | trigger_d <= trigger; 24 | if (cnt > 0) begin 25 | cnt <= cnt - ONE; 26 | pulse <= 1'b1; 27 | end else if (!trigger_d && trigger) begin // low to high transition 28 | cnt <= COUNT; 29 | pulse <= 1'b1; 30 | end else begin 31 | pulse <= 1'b0; 32 | end 33 | end 34 | end 35 | 36 | endmodule 37 | -------------------------------------------------------------------------------- /hdl/support/rising_edge.sv: -------------------------------------------------------------------------------- 1 | module rising_edge ( 2 | input clk, 3 | input i, 4 | output reg o 5 | ); 6 | 7 | reg prev; 8 | 9 | always @(posedge clk) begin 10 | prev <= i; 11 | 12 | if (!prev && i) begin 13 | o <= 1'b1; 14 | end else begin 15 | o <= 1'b0; 16 | end 17 | end 18 | 19 | endmodule 20 | -------------------------------------------------------------------------------- /hdl/support/rom.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //------------------------------------------------------------------------------------------------- 4 | module rom 5 | //------------------------------------------------------------------------------------------------- 6 | # 7 | ( 8 | parameter DW = 8, 9 | parameter AW = 14, 10 | parameter FN = "rom8x16K.hex" 11 | ) 12 | ( 13 | input wire clock, 14 | input wire ce, 15 | output reg [DW-1:0] data_out, 16 | input wire[AW-1:0] a 17 | ); 18 | //------------------------------------------------------------------------------------------------- 19 | 20 | reg[DW-1:0] d[(2**AW)-1:0]; 21 | initial $readmemh(FN, d, 0); 22 | 23 | always @(posedge clock) if(ce) data_out<= d[a]; 24 | 25 | //------------------------------------------------------------------------------------------------- 26 | endmodule 27 | //------------------------------------------------------------------------------------------------- 28 | -------------------------------------------------------------------------------- /hdl/support/sdpram32.sv: -------------------------------------------------------------------------------- 1 | 2 | module sdpram32 #( 3 | parameter ADDR_WIDTH = 10 4 | ) ( 5 | input clk, 6 | input [ADDR_WIDTH-1:0] write_addr, 7 | input [31:0] write_data, 8 | input write_enable, 9 | input [3:0] byte_enable, 10 | input [ADDR_WIDTH-1:0] read_addr, 11 | input read_enable, 12 | output reg [31:0] read_data 13 | ); 14 | 15 | reg [31:0] mem [2**ADDR_WIDTH-1:0]; 16 | 17 | // force pipeline read mode, per GowinSynthesis Coding Templates 18 | // Necessary to avoid potential glitches in read data if 19 | // write address and read address are the same 20 | reg [31:0] read_data_r; 21 | 22 | always_ff @(posedge clk) begin 23 | if (write_enable) begin 24 | if (byte_enable[0]) 25 | mem[write_addr][7:0] <= write_data[7:0]; 26 | if (byte_enable[1]) 27 | mem[write_addr][15:8] <= write_data[15:8]; 28 | if (byte_enable[2]) 29 | mem[write_addr][23:16] <= write_data[23:16]; 30 | if (byte_enable[3]) 31 | mem[write_addr][31:24] <= write_data[31:24]; 32 | end else if (read_enable) begin 33 | read_data_r <= mem[read_addr]; 34 | end 35 | read_data <= read_data_r; 36 | end 37 | 38 | endmodule 39 | -------------------------------------------------------------------------------- /hdl/support/srff.v: -------------------------------------------------------------------------------- 1 | module srff ( 2 | input wire clk, 3 | input wire s, 4 | input wire r, 5 | output wire q 6 | ); 7 | 8 | reg prev_s_r; 9 | reg prev_r_r; 10 | reg q_r; 11 | wire edge_s_w = s & ~prev_s_r; 12 | wire edge_r_w = r & ~prev_r_r; 13 | 14 | assign q = (edge_s_w & !edge_r_w) | q_r; 15 | 16 | always @(posedge clk) begin 17 | prev_s_r <= s; 18 | prev_r_r <= r; 19 | if (edge_r_w) 20 | q_r <= 0; 21 | else if (edge_s_w) 22 | q_r <= 1; 23 | end 24 | 25 | endmodule -------------------------------------------------------------------------------- /hdl/support/timer.sv: -------------------------------------------------------------------------------- 1 | module timer #( 2 | parameter CLOCK_FREQ = 54_000_000, // Default clock frequency 3 | parameter CLOCK_DIVIDER = 1000 // Default to milliseconds 4 | ) ( 5 | input clk, // Clock input 6 | input reset, // Asynchronous reset 7 | output reg [31:0] counter // 32-bit counter 8 | ); 9 | 10 | // Calculate the number of cycles based on the clock frequency 11 | localparam CYCLES_PER_COUNT = CLOCK_FREQ / CLOCK_DIVIDER; 12 | 13 | // Determine the number of bits required to store CYCLES_PER_COUNT 14 | localparam BITS_FOR_CYCLES = $clog2(CYCLES_PER_COUNT); 15 | 16 | // Counter for cycles 17 | reg [BITS_FOR_CYCLES-1:0] cycles = 0; 18 | 19 | always @(posedge clk or posedge reset) begin 20 | if (reset) begin 21 | // Reset cycles and counter 22 | cycles <= 0; 23 | counter <= 0; 24 | end else begin 25 | if (cycles < CYCLES_PER_COUNT - 1) begin 26 | // Increment cycles 27 | cycles <= cycles + 1'b1; 28 | end else begin 29 | // Reset cycles and increment counter 30 | cycles <= 0; 31 | counter <= counter + 1; 32 | end 33 | end 34 | end 35 | 36 | endmodule 37 | -------------------------------------------------------------------------------- /hdl/support/uart_rx.v: -------------------------------------------------------------------------------- 1 | module uart_rx 2 | ( 3 | input clk, //clock input 4 | input[20:0] cycle, //baud counter 5 | input rst_n, //asynchronous reset input, low active 6 | output reg[7:0] rx_data, //received serial data 7 | output reg rx_data_valid, //received serial data is valid 8 | input rx_data_ready, //data receiver module ready 9 | input rx_pin //serial data input 10 | ); 11 | 12 | //state machine code 13 | localparam S_IDLE = 1; 14 | localparam S_START = 2; //start bit 15 | localparam S_REC_BYTE = 3; //data bits 16 | localparam S_STOP = 4; //stop bit 17 | localparam S_DATA = 5; 18 | 19 | reg[2:0] state; 20 | reg[2:0] next_state; 21 | reg rx_d0; //delay 1 clock for rx_pin 22 | reg rx_d1; //delay 1 clock for rx_d0 23 | wire rx_negedge; //negedge of rx_pin 24 | reg[7:0] rx_bits; //temporary storage of received data 25 | reg[20:0] cycle_cnt; //baud counter 26 | reg[2:0] bit_cnt; //bit counter 27 | 28 | assign rx_negedge = rx_d1 && ~rx_d0; 29 | 30 | always@(posedge clk or negedge rst_n) 31 | begin 32 | if(rst_n == 1'b0) 33 | begin 34 | rx_d0 <= 1'b0; 35 | rx_d1 <= 1'b0; 36 | end 37 | else 38 | begin 39 | rx_d0 <= rx_pin; 40 | rx_d1 <= rx_d0; 41 | end 42 | end 43 | 44 | 45 | always@(posedge clk or negedge rst_n) 46 | begin 47 | if(rst_n == 1'b0) 48 | state <= S_IDLE; 49 | else 50 | state <= next_state; 51 | end 52 | 53 | always@(*) 54 | begin 55 | case(state) 56 | S_IDLE: 57 | if(rx_negedge) 58 | next_state <= S_START; 59 | else 60 | next_state <= S_IDLE; 61 | S_START: 62 | if(cycle_cnt == 21'd0)//one data cycle 63 | next_state <= S_REC_BYTE; 64 | else 65 | next_state <= S_START; 66 | S_REC_BYTE: 67 | if(cycle_cnt == 21'd0 && bit_cnt == 3'd7) //receive 8bit data 68 | next_state <= S_STOP; 69 | else 70 | next_state <= S_REC_BYTE; 71 | S_STOP: 72 | if(cycle_cnt == {1'b0, cycle[20:1]})//half bit cycle,to avoid missing the next byte receiver 73 | next_state <= S_DATA; 74 | else 75 | next_state <= S_STOP; 76 | S_DATA: 77 | if(rx_data_ready) //data receive complete 78 | next_state <= S_IDLE; 79 | else 80 | next_state <= S_DATA; 81 | default: 82 | next_state <= S_IDLE; 83 | endcase 84 | end 85 | 86 | always@(posedge clk or negedge rst_n) 87 | begin 88 | if(rst_n == 1'b0) 89 | rx_data_valid <= 1'b0; 90 | else if(state == S_STOP && next_state != state) 91 | rx_data_valid <= 1'b1; 92 | else if(state == S_DATA && rx_data_ready) 93 | rx_data_valid <= 1'b0; 94 | end 95 | 96 | always@(posedge clk or negedge rst_n) 97 | begin 98 | if(rst_n == 1'b0) 99 | rx_data <= 8'd0; 100 | else if(state == S_STOP && next_state != state) 101 | rx_data <= rx_bits;//latch received data 102 | end 103 | 104 | always@(posedge clk or negedge rst_n) 105 | begin 106 | if(rst_n == 1'b0) 107 | begin 108 | bit_cnt <= 3'd0; 109 | end 110 | else if(state == S_REC_BYTE) 111 | if(cycle_cnt == 21'd0) 112 | bit_cnt <= bit_cnt + 3'd1; 113 | else 114 | bit_cnt <= bit_cnt; 115 | else 116 | bit_cnt <= 3'd0; 117 | end 118 | 119 | 120 | always@(posedge clk) 121 | begin 122 | if(rst_n == 1'b0) 123 | cycle_cnt <= cycle; 124 | else if((state == S_REC_BYTE && cycle_cnt == 21'd0) || next_state != state) 125 | cycle_cnt <= cycle; 126 | else 127 | cycle_cnt <= cycle_cnt - 21'd1; 128 | end 129 | 130 | //receive serial data bit data 131 | always@(posedge clk or negedge rst_n) 132 | begin 133 | if(rst_n == 1'b0) 134 | rx_bits <= 8'd0; 135 | else if(state == S_REC_BYTE && cycle_cnt == {1'b0, cycle[20:1]}) 136 | rx_bits[bit_cnt] <= rx_pin; 137 | else 138 | rx_bits <= rx_bits; 139 | end 140 | endmodule -------------------------------------------------------------------------------- /hdl/support/uart_tx.v: -------------------------------------------------------------------------------- 1 | module uart_tx 2 | ( 3 | input clk, //clock input 4 | input[20:0] cycle, //baud counter 5 | input rst_n, //asynchronous reset input, low active 6 | input[7:0] tx_data, //data to send 7 | input tx_data_valid, //data to be sent is valid 8 | output reg tx_data_ready, //send ready 9 | output tx_pin, //serial data output 10 | output loopback //looped back input data 11 | ); 12 | 13 | //state machine code 14 | localparam S_IDLE = 1; 15 | localparam S_START = 2;//start bit 16 | localparam S_SEND_BYTE = 3;//data bits 17 | localparam S_STOP = 4;//stop bit 18 | reg[2:0] state; 19 | reg[2:0] next_state; 20 | reg[20:0] cycle_cnt; //baud counter 21 | reg[2:0] bit_cnt;//bit counter 22 | reg[7:0] tx_data_latch; //latch data to send 23 | reg tx_reg; //serial data output 24 | reg[7:0] loopback_reg; 25 | 26 | assign tx_pin = tx_reg; 27 | assign loopback = loopback_reg[7]; 28 | 29 | always@(posedge clk or negedge rst_n) 30 | begin 31 | if(rst_n == 1'b0) 32 | state <= S_IDLE; 33 | else 34 | state <= next_state; 35 | end 36 | 37 | always@(*) 38 | begin 39 | case(state) 40 | S_IDLE: 41 | if(tx_data_valid == 1'b1) 42 | next_state <= S_START; 43 | else 44 | next_state <= S_IDLE; 45 | S_START: 46 | if(cycle_cnt == 20'd0) 47 | next_state <= S_SEND_BYTE; 48 | else 49 | next_state <= S_START; 50 | S_SEND_BYTE: 51 | if(cycle_cnt == 20'd0 && bit_cnt == 3'd7) 52 | next_state <= S_STOP; 53 | else 54 | next_state <= S_SEND_BYTE; 55 | S_STOP: 56 | if(cycle_cnt == 20'd0) 57 | next_state <= S_IDLE; 58 | else 59 | next_state <= S_STOP; 60 | default: 61 | next_state <= S_IDLE; 62 | endcase 63 | end 64 | always@(posedge clk or negedge rst_n) 65 | begin 66 | if(rst_n == 1'b0) 67 | begin 68 | tx_data_ready <= 1'b0; 69 | end 70 | else if(state == S_IDLE) 71 | if(tx_data_valid == 1'b1) 72 | tx_data_ready <= 1'b0; 73 | else 74 | tx_data_ready <= 1'b1; 75 | else if(state == S_STOP && cycle_cnt == 20'd0) 76 | tx_data_ready <= 1'b1; 77 | end 78 | 79 | 80 | always@(posedge clk or negedge rst_n) 81 | begin 82 | if(rst_n == 1'b0) 83 | begin 84 | tx_data_latch <= 8'd0; 85 | end 86 | else if(state == S_IDLE && tx_data_valid == 1'b1) 87 | tx_data_latch <= tx_data; 88 | 89 | end 90 | 91 | always@(posedge clk or negedge rst_n) 92 | begin 93 | if(rst_n == 1'b0) 94 | begin 95 | bit_cnt <= 3'd0; 96 | end 97 | else if(state == S_SEND_BYTE) 98 | if(cycle_cnt == 20'd0) 99 | bit_cnt <= bit_cnt + 3'd1; 100 | else 101 | bit_cnt <= bit_cnt; 102 | else 103 | bit_cnt <= 3'd0; 104 | end 105 | 106 | 107 | always@(posedge clk) 108 | begin 109 | if(rst_n == 1'b0) 110 | cycle_cnt <= cycle; 111 | else if((state == S_SEND_BYTE && cycle_cnt == 20'd0) || next_state != state) 112 | cycle_cnt <= cycle; 113 | else 114 | cycle_cnt <= cycle_cnt - 20'd1; 115 | end 116 | 117 | always@(posedge clk or negedge rst_n) 118 | begin 119 | if(rst_n == 1'b0) 120 | begin 121 | tx_reg <= 1'b1; 122 | loopback_reg <= 8'b11111111; 123 | end 124 | else 125 | case(state) 126 | S_IDLE,S_STOP: 127 | begin 128 | tx_reg <= 1'b1; 129 | loopback_reg <= {loopback_reg[6:0], 1'b1}; 130 | end 131 | S_START: 132 | begin 133 | tx_reg <= 1'b0; 134 | loopback_reg <= {loopback_reg[6:0], 1'b0}; 135 | end 136 | S_SEND_BYTE: 137 | begin 138 | tx_reg <= tx_data_latch[bit_cnt]; 139 | loopback_reg <= {loopback_reg[6:0], tx_data_latch[bit_cnt]}; 140 | end 141 | default: 142 | begin 143 | tx_reg <= 1'b1; 144 | loopback_reg <= {loopback_reg[6:0], 1'b1}; 145 | end 146 | endcase 147 | end 148 | 149 | endmodule -------------------------------------------------------------------------------- /hdl/support/ws2812.sv: -------------------------------------------------------------------------------- 1 | module ws2812 ( 2 | input clk, // input clock source 3 | 4 | input [23:0] rgb, 5 | 6 | output reg WS2812 // output to the interface of WS2812 7 | ); 8 | 9 | parameter WS2812_NUM = 0 ; // LED number of WS2812 (starts from 0) 10 | parameter WS2812_WIDTH = 24 ; // WS2812 data bit width 11 | parameter CLK_FRE = 27_000_000 ; // CLK frequency (mHZ) 12 | 13 | parameter DELAY_1_HIGH = (CLK_FRE / 1_000_000 * 0.85 ) - 1; //≈850ns±150ns 1 high level time 14 | parameter DELAY_1_LOW = (CLK_FRE / 1_000_000 * 0.40 ) - 1; //≈400ns±150ns 1 low level time 15 | parameter DELAY_0_HIGH = (CLK_FRE / 1_000_000 * 0.40 ) - 1; //≈400ns±150ns 0 high level time 16 | parameter DELAY_0_LOW = (CLK_FRE / 1_000_000 * 0.85 ) - 1; //≈850ns±150ns 0 low level time 17 | parameter DELAY_RESET = (CLK_FRE / 10 ) - 1; //0.1s reset time >50us 18 | 19 | parameter RESET = 0; //state machine statement 20 | parameter DATA_SEND = 1; 21 | parameter BIT_SEND_HIGH = 2; 22 | parameter BIT_SEND_LOW = 3; 23 | 24 | parameter INIT_DATA = 24'b1111; // initial pattern 25 | 26 | reg [ 1:0] state = 0; // synthesis preserve - main state machine control 27 | reg [ 8:0] bit_send = 0; // number of bits sent - increase for larger led strips/matrix 28 | reg [ 8:0] data_send = 0; // number of data sent - increase for larger led strips/matrix 29 | reg [31:0] clk_count = 0; // delay control 30 | reg [23:0] WS2812_data = 0; // WS2812 color data 31 | 32 | always@(posedge clk) 33 | case (state) 34 | RESET:begin 35 | WS2812 <= 0; 36 | if (clk_count < DELAY_RESET) begin 37 | clk_count <= clk_count + 1; 38 | end 39 | else begin 40 | clk_count <= 0; 41 | WS2812_data <= {<<{rgb[15:8],rgb[23:16],rgb[7:0]}}; //color data 42 | state <= DATA_SEND; 43 | end 44 | end 45 | 46 | DATA_SEND: 47 | if (data_send > WS2812_NUM && bit_send == WS2812_WIDTH)begin 48 | clk_count <= 0; 49 | data_send <= 0; 50 | bit_send <= 0; 51 | state <= RESET; 52 | end 53 | else if (bit_send < WS2812_WIDTH) begin 54 | state <= BIT_SEND_HIGH; 55 | end 56 | else begin 57 | data_send <= data_send + 1; 58 | bit_send <= 0; 59 | state <= BIT_SEND_HIGH; 60 | end 61 | 62 | BIT_SEND_HIGH:begin 63 | WS2812 <= 1; 64 | 65 | if (WS2812_data[bit_send]) 66 | if (clk_count < DELAY_1_HIGH) 67 | clk_count <= clk_count + 1; 68 | else begin 69 | clk_count <= 0; 70 | state <= BIT_SEND_LOW; 71 | end 72 | else 73 | if (clk_count < DELAY_0_HIGH) 74 | clk_count <= clk_count + 1; 75 | else begin 76 | clk_count <= 0; 77 | state <= BIT_SEND_LOW; 78 | end 79 | end 80 | 81 | BIT_SEND_LOW:begin 82 | WS2812 <= 0; 83 | 84 | if (WS2812_data[bit_send]) 85 | if (clk_count < DELAY_1_LOW) 86 | clk_count <= clk_count + 1; 87 | else begin 88 | clk_count <= 0; 89 | 90 | bit_send <= bit_send + 1; 91 | state <= DATA_SEND; 92 | end 93 | else 94 | if (clk_count < DELAY_0_LOW) 95 | clk_count <= clk_count + 1; 96 | else begin 97 | clk_count <= 0; 98 | 99 | bit_send <= bit_send + 1; 100 | state <= DATA_SEND; 101 | end 102 | end 103 | endcase 104 | endmodule -------------------------------------------------------------------------------- /releases/README.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/a2fpga/a2fpga_core/20291afa7f7f9e438615e2cbe1d8e29de5e1f835/releases/README.pdf -------------------------------------------------------------------------------- /src/picosoc/README.md: -------------------------------------------------------------------------------- 1 | # A2N20 RISC-V/32 SOC 2 | 3 | The A2N20 uses the [PicoRV32](https://github.com/YosysHQ/picorv32) core as a coprocessor for on-screen display and FAT32 SDCard support. 4 | 5 | The `firmware` subdirectory contains the code for generating the .hex file that is used to initialize blockram in the FPGA core during synthesis. This is what 6 | is executed when the FPGA finishes configuration at power up. The firmware uses the [Petite Fat File System](http://elm-chan.org/fsw/ff/00index_p.html) to 7 | load `boot.bin` from the root directory of an SDCard. Use `make` to build the firmware. The `firmware.hex` file will be copied into the appropriate 8 | directory in the rtl source, assuming files are all in the correct directory. 9 | 10 | The `boot` subdirectory contains the actual runtime kernel for generating the on-screen display for mounting disk volume images as well as configuring 11 | options for the A2N20. Use `make` to build the boot kernel and place the resultant `boot.bin` file in the root directory of an SDCard. 12 | 13 | For Mac, use the [RISC-V Toolchain installed via Homebrew](https://github.com/riscv-software-src/homebrew-riscv). Use the standard `brew install riscv-tools` option. This will install the version that supports both 64-bit and 32-bit targets. Contrary to many sources online, the riscv64-unknown-elf-* tools will build for 32-bit targets such as PicoRV32 as long as the command line options `-march` and `-mabi` are set properly. You do not need to build or install the riscv32-unknown-elf-* toolset. 14 | 15 | For Windows under WSL2 or Linux, use the [Prebuilt RISC-V GCC Toolchains for Linux](https://github.com/stnolting/riscv-gcc-prebuilt) and choose the rv32i download and follow the installation instructions. 16 | 17 | Note: This firmware and PicoSoc implementation is derived from Lawrie Griffiths' [pico_ram_soc](https://github.com/lawrie/pico_ram_soc) project which adapts PicoRV32 to use FPGA BlockRam as program memory as well as Claire Wolf's [icotools](https://github.com/cliffordwolf/icotools) project. 18 | -------------------------------------------------------------------------------- /src/picosoc/boot/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(wildcard /opt/homebrew/opt/riscv-gnu-toolchain/bin/riscv64-unknown-elf-gcc),) 2 | $(info Using Mac Homebrew 64-bit RISC-V GCC Toolchain (riscv64-unknown-elf)) 3 | TOOLCHAIN_BIN_DIR = /opt/homebrew/opt/riscv-gnu-toolchain/bin 4 | RISCVBUILD = 64 5 | else 6 | $(info Using 32-bit RISC-V GCC Toolchain installed in /opt/riscv/bin (riscv32-unknown-elf)) 7 | TOOLCHAIN_BIN_DIR = /opt/riscv/bin 8 | RISCVBUILD = 32 9 | endif 10 | 11 | GCC = $(TOOLCHAIN_BIN_DIR)/riscv$(RISCVBUILD)-unknown-elf-gcc 12 | OBJCOPY = $(TOOLCHAIN_BIN_DIR)/riscv$(RISCVBUILD)-unknown-elf-objcopy 13 | FIRMWARE_DIR = . 14 | INCLUDE_DIR = ../libraries 15 | 16 | LDS_FILE = $(FIRMWARE_DIR)/boot.lds 17 | START_FILE = $(FIRMWARE_DIR)/boot.S 18 | C_FILES = \ 19 | main.c \ 20 | $(INCLUDE_DIR)/a2fpga/a2fpga.c \ 21 | $(INCLUDE_DIR)/a2slots/a2slots.c \ 22 | $(INCLUDE_DIR)/soc/soc.c \ 23 | $(INCLUDE_DIR)/uart/uart.c \ 24 | $(INCLUDE_DIR)/xprintf/xprintf.c \ 25 | $(INCLUDE_DIR)/a2mem/a2mem.c \ 26 | $(INCLUDE_DIR)/ff/ffunicode.c \ 27 | $(INCLUDE_DIR)/ff/sdmm.c \ 28 | $(INCLUDE_DIR)/ff/ff.c \ 29 | 30 | all: boot.bin 31 | 32 | boot.elf: $(C_FILES) 33 | $(GCC) -march=rv32im -mabi=ilp32 -nostartfiles \ 34 | -Wl,-Bstatic,-T,$(LDS_FILE),--strip-debug,-Map=boot.map,--cref \ 35 | -fno-zero-initialized-in-bss -ffreestanding -Os \ 36 | -o boot.elf \ 37 | -I$(INCLUDE_DIR) $(START_FILE) $(C_FILES) 38 | 39 | boot.bin: boot.elf 40 | $(OBJCOPY) -O binary boot.elf boot.bin 41 | 42 | clean: 43 | rm -f boot.elf boot.bin boot.o boot.map 44 | 45 | -------------------------------------------------------------------------------- /src/picosoc/boot/boot.S: -------------------------------------------------------------------------------- 1 | .section .init 2 | .global main 3 | 4 | j main 5 | 6 | .balign 4 7 | 8 | -------------------------------------------------------------------------------- /src/picosoc/boot/boot.lds: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | . = 0x04400000; 3 | .memory : { 4 | *(.init); 5 | *(.text); 6 | *(*); 7 | . = ALIGN(4); 8 | _end = .; PROVIDE (end = .); 9 | } 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/picosoc/boot/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | // 12 | // A2FPGA Kernel 13 | // 14 | // (c) 2023,2024 Ed Anuff 15 | // 16 | // Permission to use, copy, modify, and/or distribute this software for any 17 | // purpose with or without fee is hereby granted, provided that the above 18 | // copyright notice and this permission notice appear in all copies. 19 | // 20 | // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 21 | // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 22 | // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 23 | // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 24 | // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 25 | // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 26 | // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 27 | // 28 | // Description: 29 | // 30 | // This is the kernel for the A2FPGA. It is responsible for presenting 31 | // a simple OSD UX for selecting and mounting Apple II disk images as 32 | // well as other system configuration options. 33 | // 34 | 35 | #define reg_uart_clkdiv (*(volatile uint32_t*)0x02000004) 36 | #define reg_uart_data (*(volatile uint32_t*)0x02000008) 37 | #define gpio (*(volatile uint32_t*)0x03000000) 38 | 39 | static void put_rc (FRESULT rc) 40 | { 41 | reg_a2fpga_video_enable = 1; 42 | const char *str = 43 | "OK\0" "DISK_ERR\0" "INT_ERR\0" "NOT_READY\0" "NO_FILE\0" "NO_PATH\0" 44 | "INVALID_NAME\0" "DENIED\0" "EXIST\0" "INVALID_OBJECT\0" "WRITE_PROTECTED\0" 45 | "INVALID_DRIVE\0" "NOT_ENABLED\0" "NO_FILE_SYSTEM\0" "MKFS_ABORTED\0" "TIMEOUT\0" 46 | "LOCKED\0" "NOT_ENOUGH_CORE\0" "TOO_MANY_OPEN_FILES\0" "INVALID_PARAMETER\0"; 47 | FRESULT i; 48 | 49 | for (i = 0; i != rc && *str; i++) { 50 | while (*str++) ; 51 | } 52 | xprintf("rc=%u FR_%s\n", (UINT)rc, str); 53 | } 54 | 55 | FATFS FatFs; /* File system object for each logical drive */ 56 | FILINFO Finfo; 57 | DIR Dir; /* Directory object */ 58 | 59 | void main(soc_firmware_jump_table_t* firmware_jump_table) { 60 | soc_irq(0); 61 | 62 | reg_uart_clkdiv = 468; // 54000000 / 115200 63 | 64 | xdev_out(screen_putchar); 65 | reg_a2fpga_video_enable = 1; 66 | 67 | screen_clear(); 68 | xputs("A2FPGA OS Loaded\n\n"); 69 | 70 | FRESULT res; 71 | UINT acc_files, acc_dirs; 72 | QWORD acc_size; 73 | 74 | res = f_mount(&FatFs, "", 0); 75 | if (res) { put_rc(res); return; } 76 | 77 | res = f_opendir(&Dir, ""); 78 | if (res) { put_rc(res); return; } 79 | 80 | acc_size = acc_dirs = acc_files = 0; 81 | for(;;) { 82 | res = f_readdir(&Dir, &Finfo); 83 | if ((res != FR_OK) || !Finfo.fname[0]) break; 84 | if (Finfo.fattrib & AM_DIR) { 85 | acc_dirs++; 86 | } else { 87 | acc_files++; 88 | acc_size += Finfo.fsize; 89 | } 90 | xprintf("%c %7lu %s\n", 91 | (Finfo.fattrib & AM_DIR) ? 'D' : '-', 92 | Finfo.fsize, Finfo.fname); 93 | } 94 | xprintf("\n%4u File(s)\n", acc_files); 95 | xprintf("%9llu bytes total\n", acc_size); 96 | xprintf("%4u Dir(s)\n", acc_dirs); 97 | 98 | uint32_t *buff=(uint32_t *)0x04080000; 99 | UINT br; 100 | 101 | FIL fil; 102 | xputs("\nOpening DOS 3.3...\n"); 103 | res = f_open(&fil, "dos33.nib", FA_READ); 104 | if (res) { put_rc(res); return; } 105 | 106 | xputs("\nLoading DOS 3.3...\n"); 107 | res = f_read(&fil, buff, 0x40000, &br); 108 | //if (res) { put_rc(res); return; } 109 | 110 | f_close(&fil); 111 | 112 | xprintf("\n%4u bytes read\n", br); 113 | 114 | xputs("\nDOS 3.3 loaded!\n"); 115 | 116 | reg_a2fpga_volume_0_ready = 1; 117 | reg_a2fpga_volume_0_mounted = 1; 118 | reg_a2fpga_volume_0_readonly = 1; 119 | reg_a2fpga_volume_0_size = 0x40000; 120 | reg_a2fpga_volume_0_blk_cnt = 0x80; 121 | reg_a2fpga_volume_0_ack = 1; 122 | 123 | soc_wait(5000); 124 | 125 | reg_a2fpga_video_enable = 0; 126 | 127 | while (1) { 128 | 129 | firmware_jump_table->wait_for_cmd(); 130 | reg_a2fpga_a2_cmd = 0; 131 | 132 | reg_a2fpga_video_enable = 1; 133 | xputs("\nEntering co-processor...\n"); 134 | 135 | uint8_t c; 136 | //while (c = firmware_jump_table->wait_for_char() != 'Q') { 137 | while ((c = wait_for_char()) != 'Q') { 138 | screen_putchar(c); 139 | } 140 | xputs("\nExiting co-processor...\n"); 141 | 142 | reg_a2fpga_video_enable = 0; 143 | } 144 | 145 | //printf("\nDone!\n"); 146 | } 147 | -------------------------------------------------------------------------------- /src/picosoc/firmware/Makefile: -------------------------------------------------------------------------------- 1 | ifneq ($(wildcard /opt/homebrew/opt/riscv-gnu-toolchain/bin/riscv64-unknown-elf-gcc),) 2 | $(info Using Mac Homebrew 64-bit RISC-V GCC Toolchain (riscv64-unknown-elf)) 3 | TOOLCHAIN_BIN_DIR = /opt/homebrew/opt/riscv-gnu-toolchain/bin 4 | RISCVBUILD = 64 5 | else 6 | $(info Using 32-bit RISC-V GCC Toolchain installed in /opt/riscv/bin (riscv32-unknown-elf)) 7 | TOOLCHAIN_BIN_DIR = /opt/riscv/bin 8 | RISCVBUILD = 32 9 | endif 10 | 11 | GCC = $(TOOLCHAIN_BIN_DIR)/riscv$(RISCVBUILD)-unknown-elf-gcc 12 | OBJCOPY = $(TOOLCHAIN_BIN_DIR)/riscv$(RISCVBUILD)-unknown-elf-objcopy 13 | FIRMWARE_DIR = . 14 | INCLUDE_DIR = ../libraries 15 | 16 | LDS_FILE = $(FIRMWARE_DIR)/firmware.lds 17 | START_FILE = $(FIRMWARE_DIR)/firmware.S 18 | C_FILES = \ 19 | main.c \ 20 | $(INCLUDE_DIR)/a2fpga/a2fpga.c \ 21 | $(INCLUDE_DIR)/a2slots/a2slots.c \ 22 | $(INCLUDE_DIR)/soc/soc.c \ 23 | $(INCLUDE_DIR)/uart/uart.c \ 24 | $(INCLUDE_DIR)/xprintf/xprintf.c \ 25 | $(INCLUDE_DIR)/a2mem/a2mem.c \ 26 | $(INCLUDE_DIR)/pff/mmcbbp.c \ 27 | $(INCLUDE_DIR)/pff/pff.c \ 28 | 29 | all: firmware.hex 30 | 31 | firmware.elf: $(C_FILES) 32 | $(GCC) -march=rv32im -mabi=ilp32 -mno-div \ 33 | -nostartfiles \ 34 | -Wl,-Bstatic,-T,$(LDS_FILE),--strip-debug,-Map=firmware.map,--cref \ 35 | -fno-zero-initialized-in-bss -ffreestanding -Os \ 36 | -o firmware.elf \ 37 | -I$(INCLUDE_DIR) $(START_FILE) $(C_FILES) 38 | 39 | firmware.asm: $(C_FILES) 40 | $(GCC) -march=rv32im -mabi=ilp32 -mno-div \ 41 | -nostartfiles \ 42 | -Wl,-Bstatic,-T,$(LDS_FILE),--strip-debug,-Map=firmware.map,--cref \ 43 | -fno-zero-initialized-in-bss -ffreestanding -Os \ 44 | -I$(INCLUDE_DIR) $(START_FILE) -c -S $(C_FILES) 45 | mkdir asm 46 | mv *.s asm/ 47 | 48 | firmware.bin: firmware.elf 49 | $(OBJCOPY) -O binary firmware.elf firmware.bin 50 | 51 | firmware.hex: $(FIRMWARE_DIR)/makehex.py firmware.bin 52 | python3 $(FIRMWARE_DIR)/makehex.py firmware.bin 3584 > firmware.hex 53 | @echo "Firmware size: $$(grep .. firmware.hex | wc -l) / $$(wc -l < firmware.hex)" 54 | cp firmware.hex ../../../hdl/picosoc/ 55 | 56 | clean: 57 | rm -f firmware.elf firmware.hex firmware.bin firmware.o firmware.map asm/*.s 58 | rmdir asm 59 | 60 | -------------------------------------------------------------------------------- /src/picosoc/firmware/firmware.lds: -------------------------------------------------------------------------------- 1 | SECTIONS { 2 | .memory : { 3 | . = 0x000000; 4 | *(.init); 5 | *(.text); 6 | *(*); 7 | . = ALIGN(4); 8 | _end = .; PROVIDE (end = .); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/picosoc/firmware/makehex.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # This is free and unencumbered software released into the public domain. 4 | # 5 | # Anyone is free to copy, modify, publish, use, compile, sell, or 6 | # distribute this software, either in source code form or as a compiled 7 | # binary, for any purpose, commercial or non-commercial, and by any 8 | # means. 9 | 10 | from sys import argv 11 | 12 | binfile = argv[1] 13 | nwords = int(argv[2]) 14 | 15 | with open(binfile, "rb") as f: 16 | bindata = f.read() 17 | 18 | assert len(bindata) < 4*nwords 19 | assert len(bindata) % 4 == 0 20 | 21 | for i in range(nwords): 22 | if i < len(bindata) // 4: 23 | w = bindata[4*i : 4*i+4] 24 | print("%02x%02x%02x%02x" % (w[3], w[2], w[1], w[0])) 25 | else: 26 | print("0") 27 | 28 | -------------------------------------------------------------------------------- /src/picosoc/libraries/a2disk/a2disk.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | #ifndef __A2DISK_H__ 5 | #define __A2DISK_H__ 6 | 7 | #define reg_a2disk_volume_0_ready (*(volatile uint8_t*)0x07000000) 8 | #define reg_a2disk_volume_0_active (*(volatile uint8_t*)0x07000004) 9 | #define reg_a2disk_volume_0_mounted (*(volatile uint8_t*)0x07000008) 10 | #define reg_a2disk_volume_0_readonly (*(volatile uint8_t*)0x0700000C) 11 | #define reg_a2disk_volume_0_size (*(volatile uint32_t*)0x07000010) 12 | #define reg_a2disk_volume_0_lba (*(volatile uint32_t*)0x07000014) 13 | #define reg_a2disk_volume_0_blk_cnt (*(volatile uint8_t*)0x07000018) 14 | #define reg_a2disk_volume_0_rd (*(volatile uint8_t*)0x0700001C) 15 | #define reg_a2disk_volume_0_wr (*(volatile uint8_t*)0x07000020) 16 | #define reg_a2disk_volume_0_ack (*(volatile uint32_t*)0x07000024) 17 | 18 | #define reg_a2disk_volume_1_ready (*(volatile uint8_t*)0x07000080) 19 | #define reg_a2disk_volume_1_active (*(volatile uint8_t*)0x07000084) 20 | #define reg_a2disk_volume_1_mounted (*(volatile uint8_t*)0x07000088) 21 | #define reg_a2disk_volume_1_readonly (*(volatile uint8_t*)0x0700008C) 22 | #define reg_a2disk_volume_1_size (*(volatile uint32_t*)0x07000090) 23 | #define reg_a2disk_volume_1_lba (*(volatile uint32_t*)0x07000094) 24 | #define reg_a2disk_volume_1_blk_cnt (*(volatile uint8_t*)0x07000098) 25 | #define reg_a2disk_volume_1_rd (*(volatile uint8_t*)0x0700009C) 26 | #define reg_a2disk_volume_1_wr (*(volatile uint8_t*)0x070000A0) 27 | #define reg_a2disk_volume_1_ack (*(volatile uint32_t*)0x070000A4) 28 | 29 | #endif 30 | 31 | -------------------------------------------------------------------------------- /src/picosoc/libraries/a2fpga/a2fpga.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "a2fpga.h" 3 | 4 | uint8_t wait_for_cmd() 5 | { 6 | register uint8_t c; 7 | while ((c = reg_a2fpga_a2_cmd) == 0) ; 8 | reg_a2fpga_a2_cmd = 0; 9 | return c; 10 | } 11 | 12 | uint8_t wait_for_char() 13 | { 14 | register uint8_t c; 15 | while ((c = reg_a2fpga_keycode) == 0) ; 16 | reg_a2fpga_keycode = 0; 17 | return c; 18 | } 19 | 20 | void wait_for_countdown(uint32_t us) 21 | { 22 | while (reg_a2fpga_countdown != 0) ; 23 | } 24 | -------------------------------------------------------------------------------- /src/picosoc/libraries/a2fpga/a2fpga.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | #ifndef __A2FPGA_H__ 5 | #define __A2FPGA_H__ 6 | 7 | #define reg_a2fpga_system_time (*(volatile uint32_t*)0x05000000) 8 | #define reg_a2fpga_keycode (*(volatile uint8_t*)0x05000004) 9 | #define reg_a2fpga_video_enable (*(volatile uint8_t*)0x05000008) 10 | #define reg_a2fpga_text_mode (*(volatile uint8_t*)0x0500000C) 11 | #define reg_a2fpga_mixed_mode (*(volatile uint8_t*)0x05000010) 12 | #define reg_a2fpga_page2 (*(volatile uint8_t*)0x05000014) 13 | #define reg_a2fpga_hires_mode (*(volatile uint8_t*)0x05000018) 14 | #define reg_a2fpga_an3 (*(volatile uint8_t*)0x0500001C) 15 | #define reg_a2fpga_store80 (*(volatile uint8_t*)0x05000020) 16 | #define reg_a2fpga_col80 (*(volatile uint8_t*)0x05000024) 17 | #define reg_a2fpga_altchar (*(volatile uint8_t*)0x05000028) 18 | #define reg_a2fpga_text_color (*(volatile uint8_t*)0x0500002C) 19 | #define reg_a2fpga_background_color (*(volatile uint8_t*)0x05000030) 20 | #define reg_a2fpga_border_color (*(volatile uint8_t*)0x05000034) 21 | #define reg_a2fpga_monochrome_mode (*(volatile uint8_t*)0x05000038) 22 | #define reg_a2fpga_monochrome_dhires_mode (*(volatile uint8_t*)0x0500003C) 23 | #define reg_a2fpga_shrg_mode (*(volatile uint8_t*)0x05000040) 24 | #define reg_a2fpga_a2_cmd (*(volatile uint8_t*)0x05000044) 25 | #define reg_a2fpga_a2_data (*(volatile uint8_t*)0x05000048) 26 | #define reg_a2fpga_countdown (*(volatile uint32_t*)0x0500004C) 27 | #define reg_a2fpga_a2bus_ready (*(volatile uint8_t*)0x05000050) 28 | 29 | uint8_t wait_for_cmd(); 30 | uint8_t wait_for_char(); 31 | void wait_for_countdown(uint32_t us); 32 | 33 | #endif 34 | 35 | -------------------------------------------------------------------------------- /src/picosoc/libraries/a2mem/a2mem.c: -------------------------------------------------------------------------------- 1 | #include "a2mem.h" 2 | 3 | #define a2_mem_bytes ((volatile uint8_t*)0x04000000) 4 | #define a2_mem_words ((volatile uint32_t*)0x04000000) 5 | 6 | #define mmio8(x) (*(volatile uint8_t*)(x)) 7 | #define mmio32(x) (*(volatile uint32_t*)(x)) 8 | 9 | uint32_t peek32(uint32_t addr) { 10 | return mmio32(0x04000000 + addr); 11 | } 12 | 13 | uint8_t peek8(uint32_t addr) { 14 | return mmio8(0x04000000 + addr); 15 | } 16 | 17 | void poke32(uint32_t addr, uint32_t val) { 18 | mmio32(0x04000000 + addr) = val; 19 | } 20 | 21 | void poke8(uint32_t addr, uint8_t val) { 22 | mmio8(0x04000000 + addr) = val; 23 | } 24 | 25 | void shadow_ram_init() 26 | { 27 | // clear text page 0 28 | for (int i = 0; i < 2048; i += 4) { 29 | mmio32(0x04000800 + i) = 0x00000000; 30 | } 31 | } 32 | 33 | int h = 0; 34 | int v = 0; 35 | 36 | void screen_home() 37 | { 38 | h = 0; 39 | v = 0; 40 | } 41 | 42 | void screen_clear() 43 | { 44 | for (int i = 0; i < 2048; i += 4) { 45 | mmio32(0x04020800 + i) = 0xA0A0A0A0; 46 | } 47 | h = 0; 48 | v = 0; 49 | } 50 | 51 | uint32_t screen_addr(int x, int y) 52 | { 53 | return 0x04020800 + (0x50 * (y >> 3)) + ((y & 0x07) << 8) + (x << 1); 54 | } 55 | 56 | void screen_scroll() 57 | { 58 | uint32_t dst_addr = 0; 59 | uint32_t src_addr = 0; 60 | for (int y = 1; y < 24; y++) { 61 | dst_addr = screen_addr(0, y - 1); 62 | src_addr = screen_addr(0, y); 63 | for (int x = 0; x < 80; x += 4) { 64 | mmio32(dst_addr + x) = mmio32(src_addr + x); 65 | } 66 | } 67 | dst_addr = screen_addr(0, 23); 68 | for (int x = 0; x < 80; x += 4) { 69 | mmio32(dst_addr + x) = 0xA0A0A0A0; 70 | } 71 | h = 0; 72 | v = 23; 73 | } 74 | 75 | void newline() 76 | { 77 | h = 0; 78 | v++; 79 | if (v > 23) { 80 | v = 0; 81 | screen_scroll(); 82 | } 83 | } 84 | 85 | void screen_putchar(uint8_t c) 86 | { 87 | if (c == '\n') { 88 | newline(); 89 | return; 90 | } 91 | if (c < 32) return; 92 | 93 | mmio8(screen_addr(h, v)) = c + 128; 94 | 95 | h++; 96 | if (h > 39) { 97 | newline(); 98 | } 99 | } 100 | 101 | -------------------------------------------------------------------------------- /src/picosoc/libraries/a2mem/a2mem.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | #ifndef __A2MEM_H__ 5 | #define __A2MEM_H__ 6 | 7 | // Memory-map of the A2FPGA SDRAM 8 | // SDRAM mapped to 0x04xx_xxxx 9 | // 0x0400_0000 - 0x0401_FFFF: 128KB Apple II shadow RAM (interleaved) 10 | // 0x0402_0000 - 0x0403_FFFF: 128KB SOC RAM for OSD (interleaved) 11 | // 0x0404_0000 - 0x0407_FFFF: 256KB DOC AUDIO RAM 12 | // 0x0408_0000 - 0x040B_FFFF: 256KB Disk 1 RAM Buffer 13 | // 0x040C_0000 - 0x040F_FFFF: 256KB Disk 2 RAM Buffer 14 | // 0x0410_0000 - 0x043F_FFFF: 3MB unused (reserved for future expansion) 15 | // 0x0440_0000 - 0x047F_FFFF: 4MB SOC RAM for firmware OS 16 | 17 | void shadow_ram_init(); 18 | 19 | void screen_clear(); 20 | void screen_home(); 21 | void screen_putchar(uint8_t c); 22 | 23 | uint32_t peek32(uint32_t addr); 24 | uint8_t peek8(uint32_t addr); 25 | void poke32(uint32_t addr, uint32_t val); 26 | void poke8(uint32_t addr, uint8_t val); 27 | 28 | 29 | #endif 30 | 31 | -------------------------------------------------------------------------------- /src/picosoc/libraries/a2slots/a2slots.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "a2slots.h" 3 | 4 | #define mmio8(x) (*(volatile uint8_t*)(x)) 5 | #define mmio32(x) (*(volatile uint32_t*)(x)) 6 | 7 | void slots_set_card(uint8_t slot, uint8_t card) 8 | { 9 | mmio8(0x08000000 + (slot << 2)) = card; 10 | } 11 | 12 | uint8_t slots_get_card(uint8_t slot) 13 | { 14 | return mmio8(0x08000000 + (slot << 2)); 15 | } 16 | -------------------------------------------------------------------------------- /src/picosoc/libraries/a2slots/a2slots.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef __A2SLOTS_H__ 4 | #define __A2SLOTS_H__ 5 | 6 | void slots_set_card(uint8_t slot, uint8_t card); 7 | 8 | uint8_t slots_get_card(uint8_t slot); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/picosoc/libraries/ff/diskio.h: -------------------------------------------------------------------------------- 1 | /*-----------------------------------------------------------------------/ 2 | / Low level disk interface modlue include file (C)ChaN, 2019 / 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | /* Status of Disk Functions */ 13 | typedef BYTE DSTATUS; 14 | 15 | /* Results of Disk Functions */ 16 | typedef enum { 17 | RES_OK = 0, /* 0: Successful */ 18 | RES_ERROR, /* 1: R/W Error */ 19 | RES_WRPRT, /* 2: Write Protected */ 20 | RES_NOTRDY, /* 3: Not Ready */ 21 | RES_PARERR /* 4: Invalid Parameter */ 22 | } DRESULT; 23 | 24 | 25 | /*---------------------------------------*/ 26 | /* Prototypes for disk control functions */ 27 | 28 | 29 | DSTATUS disk_initialize (BYTE pdrv); 30 | DSTATUS disk_status (BYTE pdrv); 31 | DRESULT disk_read (BYTE pdrv, BYTE* buff, LBA_t sector, UINT count); 32 | DRESULT disk_write (BYTE pdrv, const BYTE* buff, LBA_t sector, UINT count); 33 | DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff); 34 | 35 | 36 | /* Disk Status Bits (DSTATUS) */ 37 | 38 | #define STA_NOINIT 0x01 /* Drive not initialized */ 39 | #define STA_NODISK 0x02 /* No medium in the drive */ 40 | #define STA_PROTECT 0x04 /* Write protected */ 41 | 42 | 43 | /* Command code for disk_ioctrl fucntion */ 44 | 45 | /* Generic command (Used by FatFs) */ 46 | #define CTRL_SYNC 0 /* Complete pending write process (needed at FF_FS_READONLY == 0) */ 47 | #define GET_SECTOR_COUNT 1 /* Get media size (needed at FF_USE_MKFS == 1) */ 48 | #define GET_SECTOR_SIZE 2 /* Get sector size (needed at FF_MAX_SS != FF_MIN_SS) */ 49 | #define GET_BLOCK_SIZE 3 /* Get erase block size (needed at FF_USE_MKFS == 1) */ 50 | #define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at FF_USE_TRIM == 1) */ 51 | 52 | /* Generic command (Not used by FatFs) */ 53 | #define CTRL_POWER 5 /* Get/Set power status */ 54 | #define CTRL_LOCK 6 /* Lock/Unlock media removal */ 55 | #define CTRL_EJECT 7 /* Eject media */ 56 | #define CTRL_FORMAT 8 /* Create physical format on the media */ 57 | 58 | /* MMC/SDC specific ioctl command */ 59 | #define MMC_GET_TYPE 10 /* Get card type */ 60 | #define MMC_GET_CSD 11 /* Get CSD */ 61 | #define MMC_GET_CID 12 /* Get CID */ 62 | #define MMC_GET_OCR 13 /* Get OCR */ 63 | #define MMC_GET_SDSTAT 14 /* Get SD status */ 64 | #define ISDIO_READ 55 /* Read data form SD iSDIO register */ 65 | #define ISDIO_WRITE 56 /* Write data to SD iSDIO register */ 66 | #define ISDIO_MRITE 57 /* Masked write data to SD iSDIO register */ 67 | 68 | /* ATA/CF specific ioctl command */ 69 | #define ATA_GET_REV 20 /* Get F/W revision */ 70 | #define ATA_GET_MODEL 21 /* Get model name */ 71 | #define ATA_GET_SN 22 /* Get serial number */ 72 | 73 | /* MMC card type flags (MMC_GET_TYPE) */ 74 | #define CT_MMC3 0x01 /* MMC ver 3 */ 75 | #define CT_MMC4 0x02 /* MMC ver 4+ */ 76 | #define CT_MMC 0x03 /* MMC */ 77 | #define CT_SDC1 0x04 /* SD ver 1 */ 78 | #define CT_SDC2 0x08 /* SD ver 2+ */ 79 | #define CT_SDC 0x0C /* SD */ 80 | #define CT_BLOCK 0x10 /* Block addressing */ 81 | 82 | #ifdef __cplusplus 83 | } 84 | #endif 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /src/picosoc/libraries/gpio/gpio.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifndef __GPIO_H__ 4 | #define __GPIO_H__ 5 | 6 | #define reg_led (*(volatile uint8_t*)0x03000000) 7 | #define reg_ws2812 (*(volatile uint32_t*)0x03000004) 8 | #define reg_button (*(volatile uint8_t*)0x03000008) 9 | 10 | #endif 11 | 12 | -------------------------------------------------------------------------------- /src/picosoc/libraries/pff/diskio.h: -------------------------------------------------------------------------------- 1 | /*----------------------------------------------------------------------- 2 | / PFF - Low level disk interface modlue include file (C)ChaN, 2010 3 | /-----------------------------------------------------------------------*/ 4 | 5 | #ifndef _DISKIO_DEFINED 6 | #define _DISKIO_DEFINED 7 | 8 | #ifdef __cplusplus 9 | extern "C" { 10 | #endif 11 | 12 | #include "pff.h" 13 | 14 | /* Status of Disk Functions */ 15 | typedef BYTE DSTATUS; 16 | 17 | #define STA_NOINIT 0x01 /* Drive not initialized */ 18 | #define STA_NODISK 0x02 /* No medium in the drive */ 19 | 20 | 21 | /* Results of Disk Functions */ 22 | typedef enum { 23 | RES_OK = 0, /* 0: Function succeeded */ 24 | RES_ERROR, /* 1: Disk error */ 25 | RES_NOTRDY, /* 2: Not ready */ 26 | RES_PARERR /* 3: Invalid parameter */ 27 | } DRESULT; 28 | 29 | 30 | /*---------------------------------------*/ 31 | /* Prototypes for disk control functions */ 32 | 33 | DSTATUS disk_initialize (void); 34 | DRESULT disk_readp (BYTE*, DWORD, UINT, UINT); 35 | DRESULT disk_writep (const BYTE*, DWORD); 36 | 37 | 38 | #ifdef __cplusplus 39 | } 40 | #endif 41 | 42 | #endif /* _DISKIO_DEFINED */ 43 | -------------------------------------------------------------------------------- /src/picosoc/libraries/pff/pffconf.h: -------------------------------------------------------------------------------- 1 | /*---------------------------------------------------------------------------/ 2 | / Petit FatFs - Configuration file 3 | /---------------------------------------------------------------------------*/ 4 | 5 | #ifndef PFCONF_DEF 6 | #define PFCONF_DEF 8088 /* Revision ID */ 7 | 8 | /*---------------------------------------------------------------------------/ 9 | / Function Configurations (0:Disable, 1:Enable) 10 | /---------------------------------------------------------------------------*/ 11 | 12 | #define PF_USE_READ 1 /* pf_read() function */ 13 | #define PF_USE_DIR 0 /* pf_opendir() and pf_readdir() function */ 14 | #define PF_USE_LSEEK 0 /* pf_lseek() function */ 15 | #define PF_USE_WRITE 0 /* pf_write() function */ 16 | 17 | #define PF_FS_FAT12 0 /* FAT12 */ 18 | #define PF_FS_FAT16 0 /* FAT16 */ 19 | #define PF_FS_FAT32 1 /* FAT32 */ 20 | 21 | 22 | /*---------------------------------------------------------------------------/ 23 | / Locale and Namespace Configurations 24 | /---------------------------------------------------------------------------*/ 25 | 26 | #define PF_USE_LCC 0 /* Allow lower case ASCII and non-ASCII chars */ 27 | 28 | #define PF_CODE_PAGE 437 29 | /* The PF_CODE_PAGE specifies the code page to be used on the target system. 30 | / SBCS code pages with PF_USE_LCC == 1 requiers a 128 byte of case conversion 31 | / table. It might occupy RAM on some platforms, e.g. avr-gcc. 32 | / When PF_USE_LCC == 0, PF_CODE_PAGE has no effect. 33 | / 34 | / 437 - U.S. 35 | / 720 - Arabic 36 | / 737 - Greek 37 | / 771 - KBL 38 | / 775 - Baltic 39 | / 850 - Latin 1 40 | / 852 - Latin 2 41 | / 855 - Cyrillic 42 | / 857 - Turkish 43 | / 860 - Portuguese 44 | / 861 - Icelandic 45 | / 862 - Hebrew 46 | / 863 - Canadian French 47 | / 864 - Arabic 48 | / 865 - Nordic 49 | / 866 - Russian 50 | / 869 - Greek 2 51 | / 932 - Japanese (DBCS) 52 | / 936 - Simplified Chinese (DBCS) 53 | / 949 - Korean (DBCS) 54 | / 950 - Traditional Chinese (DBCS) 55 | */ 56 | 57 | 58 | #endif /* PF_CONF */ 59 | -------------------------------------------------------------------------------- /src/picosoc/libraries/soc/soc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "soc.h" 4 | 5 | asm ( 6 | ".global soc_maskirq\n" 7 | "soc_maskirq:\n" 8 | ".word 0x0605650b\n" // picorv32_maskirq_insn(a0, a0) 9 | "ret\n" 10 | ); 11 | 12 | asm ( 13 | ".global soc_timer\n" 14 | "soc_timer:\n" 15 | ".word 0x0a05650b\n" // picorv32_timer_insn(a0, a0) 16 | "ret\n" 17 | ); 18 | 19 | asm ( 20 | ".global soc_waitirq\n" 21 | "soc_waitirq:\n" 22 | ".word 0x0800450B\n" // picorv32_waitirq_insn(a0) 23 | "ret\n" 24 | ); 25 | 26 | void *_sbrk(ptrdiff_t incr) 27 | { 28 | extern unsigned char _end[]; // Defined by linker 29 | static unsigned long heap_end; 30 | 31 | if (heap_end == 0) 32 | heap_end = (long)_end; 33 | 34 | heap_end += incr; 35 | return (void *)(heap_end - incr); 36 | } 37 | 38 | void soc_wait(uint32_t ms) 39 | { 40 | uint32_t current_time = reg_a2fpga_system_time; 41 | while ((reg_a2fpga_system_time - current_time) < ms) ; 42 | } -------------------------------------------------------------------------------- /src/picosoc/libraries/soc/soc.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifndef __SOC_H__ 5 | #define __SOC_H__ 6 | 7 | 8 | static inline void soc_irq(void(*irq_handler)(uint32_t,uint32_t*)) { 9 | *((uint32_t*)8) = (uint32_t)irq_handler; 10 | } 11 | 12 | extern uint32_t soc_maskirq(uint32_t mask); 13 | 14 | extern uint32_t soc_waitirq(); 15 | 16 | extern uint32_t soc_timer(uint32_t ticks); 17 | 18 | static inline void soc_sbreak() { 19 | asm volatile ("sbreak" : : : "memory"); 20 | } 21 | 22 | void soc_wait(uint32_t ms); 23 | 24 | typedef struct soc_firmware_jump_table_t { 25 | uint8_t (*wait_for_cmd)(); 26 | uint8_t (*wait_for_char)(); 27 | } soc_firmware_jump_table_t; 28 | 29 | 30 | #endif -------------------------------------------------------------------------------- /src/picosoc/libraries/uart/uart.c: -------------------------------------------------------------------------------- 1 | #include "uart.h" 2 | 3 | #define reg_uart_data (*(volatile uint32_t*)0x02000008) 4 | 5 | void uart_putchar(char c) 6 | { 7 | if (c == '\n') 8 | uart_putchar('\r'); 9 | reg_uart_data = c; 10 | } 11 | 12 | -------------------------------------------------------------------------------- /src/picosoc/libraries/uart/uart.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | #ifndef __UART_H__ 5 | #define __UART_H__ 6 | 7 | #define reg_uart_clkdiv (*(volatile uint32_t*)0x02000004) 8 | #define reg_uart_data (*(volatile uint32_t*)0x02000008) 9 | 10 | void uart_putchar(char c); 11 | 12 | #endif 13 | 14 | -------------------------------------------------------------------------------- /src/picosoc/libraries/xprintf/xprintf.h: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------*/ 2 | /* Universal string handler for user console interface (C)ChaN, 2021 */ 3 | /*------------------------------------------------------------------------*/ 4 | 5 | #ifndef XPRINTF_DEF 6 | #define XPRINTF_DEF 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | #define XF_USE_OUTPUT 1 /* 1: Enable output functions */ 14 | #define XF_CRLF 0 /* 1: Convert \n ==> \r\n in the output char */ 15 | #define XF_USE_DUMP 0 /* 1: Enable put_dump function */ 16 | #define XF_USE_LLI 1 /* 1: Enable long long integer in size prefix ll */ 17 | #define XF_USE_FP 0 /* 1: Enable support for floating point in type e and f */ 18 | #define XF_DPC '.' /* Decimal separator for floating point */ 19 | #define XF_USE_INPUT 0 /* 1: Enable input functions */ 20 | #define XF_INPUT_ECHO 0 /* 1: Echo back input chars in xgets function */ 21 | 22 | #if defined(__GNUC__) && __GNUC__ >= 10 23 | #pragma GCC diagnostic ignored "-Wcast-function-type" 24 | #endif 25 | 26 | #if XF_USE_OUTPUT 27 | #define xdev_out(func) xfunc_output = (void(*)(int))(func) 28 | extern void (*xfunc_output)(int); 29 | void xputc (int chr); 30 | void xfputc (void (*func)(int), int chr); 31 | void xputs (const char* str); 32 | void xfputs (void (*func)(int), const char* str); 33 | void xprintf (const char* fmt, ...); 34 | void xsprintf (char* buff, const char* fmt, ...); 35 | void xfprintf (void (*func)(int), const char* fmt, ...); 36 | void put_dump (const void* buff, unsigned long addr, int len, size_t width); 37 | #endif 38 | 39 | #if XF_USE_INPUT 40 | #define xdev_in(func) xfunc_input = (int(*)(void))(func) 41 | extern int (*xfunc_input)(void); 42 | int xgets (char* buff, int len); 43 | int xatoi (char** str, long* res); 44 | int xatof (char** str, double* res); 45 | #endif 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | 51 | #endif 52 | --------------------------------------------------------------------------------