├── .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 |
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 |
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 |
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 | FPGA
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 |
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 |
--------------------------------------------------------------------------------