From 6e3d81d4113b7b005e40a7a17f015205d152b11e Mon Sep 17 00:00:00 2001 From: harbaum Date: Wed, 4 Oct 2023 08:08:43 +0200 Subject: [PATCH] Support for monochrome video and external config pins --- .gitignore | 1 + sim/README.md | 7 +- sim/video_tb/Makefile | 3 + sim/video_tb/mono32k.bin | Bin 0 -> 32000 bytes sim/video_tb/sdram.gtkw | 34 ++-- sim/video_tb/ste_tb.cpp | 25 ++- sim/video_tb/ste_tb.v | 164 +++++++++--------- sim/video_tb/video_test.sv | 14 +- src/atarist/atarist.v | 78 ++++----- .../auxiliary_video_information_info_frame.sv | 4 +- src/hdmi/hdmi.sv | 20 +-- src/hdmi/packet_picker.sv | 4 +- src/misc/scandoubler.v | 8 +- src/misc/video_analyzer.v | 33 ++-- src/tangnano20k/top.sv | 33 ++-- src/tangnano20k/video.v | 11 +- 16 files changed, 245 insertions(+), 194 deletions(-) create mode 100644 sim/video_tb/mono32k.bin diff --git a/.gitignore b/.gitignore index 85e62cf..e7d86f4 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ impl/gwsynthesis/ impl/temp/ impl/pnr/ *.gprj.user +*.vcd diff --git a/sim/README.md b/sim/README.md index 99f1c10..10514b1 100644 --- a/sim/README.md +++ b/sim/README.md @@ -56,11 +56,14 @@ the testbench. It can be viewed by ```make video```. [Video_tb](video_tb) is a test for the video generation. It displays a static image and runs it through the ```scandoubler.v``` and ```video_analyzer.v```. This demo will also write an image file -for visial inspection. +for visual inspection. The demo can also be run on real hardware. In that case the image has to be copied to flash memory first: ``` -$ openFPGALoader --external-flash -o 1048576 vmem32k.bin +$ openFPGALoader --external-flash -o 2097152 vmem32k.bin ``` + +If you want to test a monochrome video use ```mono32k.bin``` for +a monochrome test image. \ No newline at end of file diff --git a/sim/video_tb/Makefile b/sim/video_tb/Makefile index 9c9e52b..2e44602 100644 --- a/sim/video_tb/Makefile +++ b/sim/video_tb/Makefile @@ -41,6 +41,9 @@ video.png: video.rgb elif [ $$(du -b $< | cut -f 1) = 941824 ]; then\ echo "scandoubled ST PAL";\ ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb444 -s 832x566 -i video.rgb -f image2 -vcodec png video.png;\ + elif [ $$(du -b $< | cut -f 1) = 512000 ]; then\ + echo "Monochrome ST";\ + ffmpeg -vcodec rawvideo -f rawvideo -pix_fmt rgb444 -s 640x400 -i video.rgb -f image2 -vcodec png video.png;\ else \ echo "Unknown format";\ fi; diff --git a/sim/video_tb/mono32k.bin b/sim/video_tb/mono32k.bin new file mode 100644 index 0000000000000000000000000000000000000000..6426368dff3621fbe1b006863d1818d955a047b5 GIT binary patch literal 32000 zcmeI3O=whS7=^#673m^oq=AcwO0;5w1r-9Zq$!BfZc4jwOpszPl-`AlRBDw$hO5O* z(T$X5<4OuGHWn;JiVIua)PjV%5~M4si&8iJ0nvqY`rUEn&6~k-4s)Mf%qAz9GtYVa zX2#^k7{Zc!tL2mPA=HvQ&qK(wTAmf}@<+*Je@9Wz^T?}Dw0QLv@9{*$_wzQBrguV^ z$&)k*A<1Ua=$B^6e4h403n6Rrvg`@(Se8yi-b6B=^~+VFq*7@aGag1q_Jj&Pg%NumOnfCeJ$p`!8t&Go?_Tyo^ z`D|r>yqUD%&9olhh38AZy!d>+5g&mpzCel>M(g>U+{pTTKG*VkizwB zm(;x)@LLsrn}gq)dJRsp(7SkwlZ<9l4+m~zg3;{TBpkv7qgZWq<0$EOJ`5Zn{TkPP z93%ZsravDC{iYh%Ke$^n1V2xHk;?T?k>zYoOosc-V&NRp;g|>o2yo*L)e7r z6|ax@`bGV=r>~-ZC$4jUy*xR;G1M=FQS|&mK>aQ?8uvLr`{o%s!u8|-zEl6>*Ih%9 zVx_X|Y^Abd?^(#NGIVdS^3RIB?^1q4Yd$UfwnKjFcl~~_QW?a~kA8fO2b~{uY=(if z3}av@7#IqWmSG?*!x$I}28IHpWtgVce~?_nG{L6~UphqOrN+R0OfU+)mxR(<28d!; zRyU55erXsmeCZIy;`J)`4NMe@*Q-ZMd$j@aryKEl^*8YR_Q&hh**3oP`{L=>xVIMc zi{C$Q87uA82E^~5Yhl{~(l1`G&bINT-#7hskk7yAJz=D@mI0c6o6nKw7q3@`jbAoI zzj(cho?pCP{jjW--9P%p>(!g&`NiwiS>u-t(Jx-Fj*@=y^;_0z;r`KYd%6wNE3Pk3 zT;H|8FPoa@w-faX;pMVc3-@pOaSv}izxeaX2MheNiN5}@>(#Pit^3>cD)bQB^(y7p zzFvj=?0OaQqaR=6L4MG&83xiajDewGU?@OZhJmyUV_+y47z&VR(Dkd|Q}EyEZX3I>J(q-7XL%PtWzWo*Y`nde&^T)UE1C5XD^Vdh; zr`P=YvDD6Q|8DM|&x^0WSF%C$@0Ww&^%4(g$6ce@MdkN*Pm6zq4t&=S)h~he?`1vq zzwdE-`{w1pOdR=Z&5>KZenm|EC-!AqzZ_Zh#p$gl+XG$RU+wbw&QCADb#>FNcIzMZ? zZiB7QPrlHj(7L&k-|gccy4}$6d2O{?RsRb{2fpivXGXi;wCD!aPyH3VMet{Q@Xa%B z^Eat}`-ZiqXA@al)mwyicv;p7?mvexu$B5SL9 zi*WJ`eOYUIHj%Yey+t^AhQ6#dJ)6kds@@`;JVRgBnx0K$ZB=g(PM)DJYfaB4vbL(X z2q(|bm$jy66Iol;TZEHm=*wEuvx%&&>Mg>_GxTMx>DffqR`nL)wyL)X zC(qEAwWeniSzFaxgp+6J%UaX3iL9;aEyBq&^kuE-*+kY>^%mje8Tzu;^lTz)t9pxY z@(g`hYkD@3wN<@EIC+M?tTjEG$l9vjBAh%!U)GwQO=N9VZxK$Op)YGq&nB|As<#Ly z&(N2(re_mbTh&{HlV|A5TGO+MtgY%T!pSrAWv%JiMAlaI7UAR>`m)yaY$9u`dW&%K z41HN^dNz@@RlP+xd4|5MH9eci+N$0noIFEc)|#G8WNlS%5l)_=FKbQDCbG7ww+JWC z(3iEQXA@al)mwyicv;p7?mvexu$B5SL9i*WJ` zeOYUIHj%Yey+t^AhQ6#dJ)6kds@@`;JVRgBnx0K$ZB=g(PM)DJYfaB4vbL(X2q(|b zm$jy66Iol;TZEHm=*wEuvx%&&>Mg>_GxTMx>DffqR`nL)wyL)XC(qEA NwWeniSzFax{{tEheF*>n literal 0 HcmV?d00001 diff --git a/sim/video_tb/sdram.gtkw b/sim/video_tb/sdram.gtkw index 0e9d249..c292f9b 100644 --- a/sim/video_tb/sdram.gtkw +++ b/sim/video_tb/sdram.gtkw @@ -1,24 +1,24 @@ [*] [*] GTKWave Analyzer v3.3.114 (w)1999-2023 BSI -[*] Sat Sep 30 17:48:54 2023 +[*] Mon Oct 2 07:01:46 2023 [*] -[dumpfile] "gstmcu.vcd" -[dumpfile_mtime] "Sat Sep 30 17:48:28 2023" -[dumpfile_size] 724313343 -[savefile] "sdram.gtkw" -[timestart] 3724000 -[size] 1280 947 +[dumpfile] "/home/tharbaum/tmp/private_stuff/mistlite/atarist/sim/video_tb/gstmcu.vcd" +[dumpfile_mtime] "Mon Oct 2 06:57:21 2023" +[dumpfile_size] 844299337 +[savefile] "/home/tharbaum/tmp/private_stuff/mistlite/atarist/sim/video_tb/sdram.gtkw" +[timestart] 3637570 +[size] 1920 1122 [pos] 0 0 -*-19.000002 4399026 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 +*-11.400000 3653600 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 [treeopen] TOP. [treeopen] TOP.ste_tb. [treeopen] TOP.ste_tb.gstshifter. [treeopen] TOP.ste_tb.gstshifter.shifter_video. [treeopen] TOP.ste_tb.sdram. -[sst_width] 209 +[sst_width] 279 [signals_width] 236 [sst_expanded] 1 -[sst_vpaned_height] 515 +[sst_vpaned_height] 629 @28 TOP.porb TOP.resb @@ -34,8 +34,16 @@ TOP.HSYNC_N @22 TOP.B[5:0] TOP.R[5:0] -TOP.B[5:0] +TOP.ste_tb.G[5:0] +@24 +TOP.ste_tb.video_analyzer.hcnt[12:0] +@25 +TOP.ste_tb.video_analyzer.vcnt[9:0] +@22 +TOP.ste_tb.gstshifter.R[3:0] @28 +TOP.ste_tb.gstshifter.shifter_video.notlow +TOP.ste_tb.gstshifter.shmode[1:0] [color] 2 TOP.ste_tb.sdram.cs @24 @@ -56,8 +64,8 @@ TOP.ste_tb.video_analyzer.vs TOP.ste_tb.video_analyzer.hcntL[12:0] TOP.ste_tb.video_analyzer.vcntL[9:0] @28 -TOP.ste_tb.video_analyzer.pal -@29 TOP.ste_tb.video_analyzer.changed +TOP.ste_tb.video_analyzer.mode[1:0] +TOP.ste_tb.gstshifter.DE [pattern_trace] 1 [pattern_trace] 0 diff --git a/sim/video_tb/ste_tb.cpp b/sim/video_tb/ste_tb.cpp index 6ebd3df..7956bac 100644 --- a/sim/video_tb/ste_tb.cpp +++ b/sim/video_tb/ste_tb.cpp @@ -6,6 +6,7 @@ #include "verilated.h" #include "verilated_vcd_c.h" +#define MONO // #define NTSC // undef for PAL static Vste_tb *tb; @@ -18,10 +19,14 @@ static unsigned char rom[8*1024*1024]; // 8 MB spi flash void initrom() { for(int i=0;iVSYNC_N; @@ -174,11 +186,18 @@ int main(int argc, char **argv) { tb->trace(trace, 99); trace->open("gstmcu.vcd"); +#ifdef MONO + tb->mono_detect = 0; // 1 - color, 0 - mono +#else + tb->mono_detect = 1; + #ifdef NTSC tb->ntsc = 1; #else tb->ntsc = 0; #endif +#endif + tb->resb = 0; tb->porb = 0; // 0=cold, 1=warm boot tick(1); diff --git a/sim/video_tb/ste_tb.v b/sim/video_tb/ste_tb.v index 9bf4b18..b8d5b44 100644 --- a/sim/video_tb/ste_tb.v +++ b/sim/video_tb/ste_tb.v @@ -5,83 +5,83 @@ //============================================================================ module ste_tb ( - input clk32, - input flash_clk, - input resb, - input porb, - input BR_N, - input FC0, - input FC1, - input FC2, - output AS_N, - output RW, - output UDS_N, - output LDS_N, - input VMA_N, - input MFPINT_N, + input clk32, + input flash_clk, + input resb, + input porb, + input BR_N, + input FC0, + input FC1, + input FC2, + output AS_N, + output RW, + output UDS_N, + output LDS_N, + input VMA_N, + input MFPINT_N, output [23:0] A, // from CPU output [15:0] DIN, output [15:0] DOUT, - output MHZ8, - output MHZ8_EN1, - output MHZ8_EN2, - output MHZ4, - output MHZ4_EN, - output BERR_N, - output IPL0_N, - output IPL1_N, - output IPL2_N, - output DTACK_N, - output IACK_N, - output ROM0_N, - output ROM1_N, - output ROM2_N, - output ROM3_N, - output ROM4_N, - output ROM5_N, - output ROM6_N, - output ROMP_N, - output RAM_N, - output RAS0_N, - output RAS1_N, - output CAS0L_N, - output CAS0H_N, - output CAS1L_N, - output CAS1H_N, - output RAM_LDS, - output RAM_UDS, - output REF, - output VPA_N, - output MFPCS_N, - output SNDIR, - output SNDCS, - output N6850, - output FCS_N, - output RTCCS_N, - output RTCRD_N, - output RTCWR_N, - output HSYNC_N, - output VSYNC_N, - output BLANK_N, - output SINT, - - output vreset, - output vpal, - - input ntsc, - output MONO, + output MHZ8, + output MHZ8_EN1, + output MHZ8_EN2, + output MHZ4, + output MHZ4_EN, + output BERR_N, + output IPL0_N, + output IPL1_N, + output IPL2_N, + output DTACK_N, + output IACK_N, + output ROM0_N, + output ROM1_N, + output ROM2_N, + output ROM3_N, + output ROM4_N, + output ROM5_N, + output ROM6_N, + output ROMP_N, + output RAM_N, + output RAS0_N, + output RAS1_N, + output CAS0L_N, + output CAS0H_N, + output CAS1L_N, + output CAS1H_N, + output RAM_LDS, + output RAM_UDS, + output REF, + output VPA_N, + output MFPCS_N, + output SNDIR, + output SNDCS, + output N6850, + output FCS_N, + output RTCCS_N, + output RTCRD_N, + output RTCWR_N, + output HSYNC_N, + output VSYNC_N, + output BLANK_N, + output SINT, + + output vreset, + output [1:0] vmode, + + input ntsc, + input mono_detect, output [5:0] R, output [5:0] G, output [5:0] B, output [23:1] ram_a, - output we_n, + output we_n, output [15:0] mdout, input [15:0] mdin, // sdram interface - output sd_clk, - output sd_cke, + output sd_clk, + output sd_cke, inout [31:0] sd_data, `ifdef VERILATOR input [31:0] sd_data_in, @@ -89,25 +89,25 @@ module ste_tb ( output [10:0] sd_addr, output [3:0] sd_dqm, output [1:0] sd_ba, - output sd_cs, - output sd_we, - output sd_ras, - output sd_cas, + output sd_cs, + output sd_we, + output sd_ras, + output sd_cas, // SPI flash interface - output mspi_cs, - inout mspi_di, - inout mspi_hold, - inout mspi_wp, - inout mspi_do, + output mspi_cs, + inout mspi_di, + inout mspi_hold, + inout mspi_wp, + inout mspi_do, `ifdef VERILATOR - input [1:0] mspi_din, + input [1:0] mspi_din, `endif output [5:0] led, - output bus_free + output bus_free ); assign led = { !flash_ready, 2'b11, mspi_cs, !flash_cs, !flash_busy }; @@ -155,7 +155,7 @@ assign led = { !flash_ready, 2'b11, mspi_cs, !flash_cs, !flash_busy }; // start copy state machine once flash and sdram are ready always @(posedge clk32 or negedge mem_ready) begin if(!mem_ready) begin - flash_addr <= 22'h80000; // start reading at 1MB + flash_addr <= 22'h100000; // start reading at 2MB ram_addr <= 22'hfc000; // only write video ram area word_count <= 22'd16000; // only read 32k image data @@ -234,7 +234,7 @@ assign led = { !flash_ready, 2'b11, mspi_cs, !flash_cs, !flash_busy }; 1: wrdata = { 24'hff8200, 16'h001f }; // video base hi \ 2: wrdata = { 24'hff8202, 16'h0080 }; // video base mid / below 2MB top - 3: wrdata = { 24'hff8260, 16'h0000 }; // 320x200 + 3: wrdata = { 24'hff8260, mono_detect?16'h0000:16'h0202 }; // 320x200 4: wrdata = { 24'hff820a, ntsc?16'h0000:16'h0200 }; // NTSC/PAL 5: wrdata = { 24'hff8240, 16'h0777 }; // default palette 6: wrdata = { 24'hff8242, 16'h0700 }; // for 4bpp @@ -261,7 +261,7 @@ assign led = { !flash_ready, 2'b11, mspi_cs, !flash_cs, !flash_busy }; assign AS_N = !wract; assign UDS_N = !wract; assign LDS_N = !wract; - assign RW = !wract; + assign RW = 1'b0; // !wract; reg [31:0] setup_wait; @@ -464,7 +464,7 @@ gstshifter gstshifter ( .MDOUT(mdout), // VIDEO - .MONO_OUT(MONO), + .MONO_OUT(), .LOAD_N(dcyc_n), .DE(st_de), .BLANK_N(BLANK_N), @@ -485,14 +485,14 @@ video_analyzer video_analyzer ( .hs(st_hs_n), .de(st_de), - .pal(vpal), // pal video detected + .mode(vmode), // report video mode detected .vreset(vreset) // reset signal ); scandoubler scandoubler ( // system interface .clk_sys(clk32), - .bypass(1'b0), + .bypass(!mono_detect), // mono .ce_divider(1'b0), // /4 .pixel_ena(), diff --git a/sim/video_tb/video_test.sv b/sim/video_tb/video_test.sv index 40b93a0..0fb07cf 100644 --- a/sim/video_tb/video_test.sv +++ b/sim/video_tb/video_test.sv @@ -1,5 +1,8 @@ /* top.sv - atarist on tang nano toplevel */ +// load image into board: +// openFPGALoader --external-flash -o 2097152 mono32k.bin + // the to 0 for pal `define VIDEO_NTSC 1'b1 @@ -36,6 +39,7 @@ module top( output [3:0] O_sdram_dqm, // 32/4 input [7:0] io, + input [3:0] cfg, // hdmi/tdms output tmds_clk_n, @@ -103,7 +107,8 @@ ELVDS_OBUF tmds_bufds [3:0] ( ); logic vsync_n, hsync_n; -logic vreset, vpal; +logic vreset; +logic [1:0] vmode; wire [5:0] r; // from scan doubler with dim'd lines wire [5:0] g; @@ -122,7 +127,7 @@ hdmi #( .tmds_clock(tmds_clock), // video input - .pal(vpal), // pal video detected + .stmode(vmode), // st video mode detected .reset(vreset), // signal to synchronize HDMI // Atari STE outputs 4 bits per color. Scandoubler outputs 6 bits (to be @@ -145,8 +150,9 @@ ste_tb ste_tb ( .VSYNC_N(vsync_n), .BLANK_N(), - .ntsc(user), // request ntsc/pal signal - .vpal(vpal), + .mono_detect(1'b0), // 0 for monochrome + .ntsc(user), // request ntsc/pal signal + .vmode(vmode), .vreset(vreset), .R(r), diff --git a/src/atarist/atarist.v b/src/atarist/atarist.v index 1e7fd32..e5b3ea7 100644 --- a/src/atarist/atarist.v +++ b/src/atarist/atarist.v @@ -4,58 +4,62 @@ module atarist ( // System clocks / reset / settings - input wire clk_32, - input wire porb, - input wire resb, + input wire clk_32, + input wire porb, + input wire resb, // Video output + input wire mono_detect, // low for monochrome output wire [3:0] r, output wire [3:0] g, output wire [3:0] b, - output wire hsync_n, - output wire vsync_n, - output wire de, - output reg monomode, - output wire blank_n, + output wire hsync_n, + output wire vsync_n, + output wire de, + output wire blank_n, // keyboard, mouse and joystick(s) - output wire [14:0] keyboard_matrix_out, - input wire [7:0] keyboard_matrix_in, - input wire [5:0] joy0, - input wire [4:0] joy1, + output wire [14:0] keyboard_matrix_out, + input wire [7:0] keyboard_matrix_in, + input wire [5:0] joy0, + input wire [4:0] joy1, // Sound output output wire [14:0] audio_mix_l, output wire [14:0] audio_mix_r, // floopy disk/sd card interface - output [31:0] sd_lba, - output [1:0] sd_rd, - output [1:0] sd_wr, - input sd_ack, - input [8:0] sd_buff_addr, - input [7:0] sd_dout, - output [7:0] sd_din, - input sd_dout_strobe, - input [1:0] sd_img_mounted, - input [31:0] sd_img_size, + output [31:0] sd_lba, + output [1:0] sd_rd, + output [1:0] sd_wr, + input sd_ack, + input [8:0] sd_buff_addr, + input [7:0] sd_dout, + output [7:0] sd_din, + input sd_dout_strobe, + input [1:0] sd_img_mounted, + input [31:0] sd_img_size, // MIDI UART - input wire midi_rx, - output wire midi_tx, + input wire midi_rx, + output wire midi_tx, + + // enable STE and extra 8MB ram + input wire ste, + input wire enable_extra_ram, // DRAM interface - output wire ram_ras_n, - output wire ram_cash_n, - output wire ram_casl_n, - output wire ram_we_n, - output wire ram_ref, + output wire ram_ras_n, + output wire ram_cash_n, + output wire ram_casl_n, + output wire ram_we_n, + output wire ram_ref, output wire [23:1] ram_addr, output wire [15:0] ram_data_in, input wire [15:0] ram_data_out, // TOS ROM interface - output wire rom_n, + output wire rom_n, output wire [23:1] rom_addr, input wire [15:0] rom_data_out, @@ -63,13 +67,9 @@ module atarist ( output wire [1:0] leds ); -// enable additional ste/megaste features -wire ste = 1'b0; - // STe always has a blitter wire blitter_en = 1'b1; // ste; wire [7:0] acsi_enable = 8'b00000000; -wire mono_monitor = 1'b1; // registered reset signals reg reset; @@ -309,7 +309,7 @@ gstmcu gstmcu ( .JOYRH_N ( joyrh_n ), .st ( ~ste ), - .extra_ram ( 1'b0 ), // Tang Nano might offer 8MB + .extra_ram ( enable_extra_ram ), // Tang Nano might offer 8MB .tos192k ( rom192k ), .turbo ( 1'b0 ), // no turbo .viking_at_c0 ( 1'b0 ), @@ -352,12 +352,6 @@ gstshifter gstshifter ( .audio_right( dma_snd_r ) ); -// assume mono mode only if it's set during VSYNC -// demos like to switch it on/off during active display to get rid of borders -always @(posedge clk_32) begin - if (!vsync_n) monomode <= mono; -end - /* ------------------------------------------------------------------------------ */ /* ------------------------------------ CPU ------------------------------------- */ /* ------------------------------------------------------------------------------ */ @@ -420,7 +414,7 @@ end wire xsint_delayed = xsint_delay[7]; // mfp io7 is mono_detect which in ste is xor'd with the dma sound irq -wire mfp_io7 = mono_monitor ^ (ste?xsint:1'b0); +wire mfp_io7 = mono_detect ^ (ste?xsint:1'b0); // fake fixed printer signals. TODO: export wire parallel_in_strobe = 1'b0; // TODO: check polarity diff --git a/src/hdmi/auxiliary_video_information_info_frame.sv b/src/hdmi/auxiliary_video_information_info_frame.sv index 074ab79..34fd181 100644 --- a/src/hdmi/auxiliary_video_information_info_frame.sv +++ b/src/hdmi/auxiliary_video_information_info_frame.sv @@ -20,7 +20,7 @@ module auxiliary_video_information_info_frame parameter bit [3:0] PIXEL_REPETITION = 4'b0000 // None ) ( - input logic pal, + input logic [1:0] stmode, output logic [23:0] header, output logic [55:0] sub [3:0] ); @@ -42,7 +42,7 @@ assign packet_bytes[0] = 8'd1 + ~(header[23:16] + header[15:8] + header[7:0] + p assign packet_bytes[1] = {1'b0, VIDEO_FORMAT, ACTIVE_FORMAT_INFO_PRESENT, BAR_INFO, SCAN_INFO}; assign packet_bytes[2] = {COLORIMETRY, PICTURE_ASPECT_RATIO, ACTIVE_FORMAT_ASPECT_RATIO}; assign packet_bytes[3] = {IT_CONTENT, EXTENDED_COLORIMETRY, RGB_QUANTIZATION_RANGE, NON_UNIFORM_PICTURE_SCALING}; -assign packet_bytes[4] = {1'b0, pal?7'd17:7'd2 }; +assign packet_bytes[4] = (stmode==2'd1)?8'd17:8'd2; assign packet_bytes[5] = {YCC_QUANTIZATION_RANGE, CONTENT_TYPE, PIXEL_REPETITION}; genvar i; diff --git a/src/hdmi/hdmi.sv b/src/hdmi/hdmi.sv index 3c1da9c..69e2d51 100644 --- a/src/hdmi/hdmi.sv +++ b/src/hdmi/hdmi.sv @@ -64,7 +64,7 @@ module hdmi input logic clk_audio, // synchronous reset back to 0,0 input logic reset, - input logic pal, // input signal is scan doubled pal + input logic [1:0] stmode, // atari st video mode, 0=60hz ntsc, 1=50hz pal, 2=mono input logic [23:0] rgb, input logic [AUDIO_BIT_WIDTH-1:0] audio_sample_word [1:0], @@ -98,18 +98,18 @@ logic [BIT_WIDTH-1:0] hsync_pulse_start, hsync_pulse_size; logic [BIT_HEIGHT-1:0] vsync_pulse_start, vsync_pulse_size; logic [1:0] invert; -assign frame_width = pal?1024:1016; +assign frame_width = (stmode==2'd0)?1016:(stmode==2'd1)?1024:896; // is usually 800, but Atari ST in PAL outputs 840 pixels per line // and (our) HDMI implementation expects the width to be a multiple of 16 // Also demos openeing the screen can only address 832 pixels properly -assign screen_width = pal?832:848; -assign hsync_pulse_start = pal?24:16; -assign hsync_pulse_size = pal?72:62; +assign screen_width = (stmode==2'd0)?848:(stmode==2'd1)?832:640; +assign hsync_pulse_start = (stmode==2'd0)?16:24; +assign hsync_pulse_size = (stmode==2'd0)?62:72; // should be 625/525, has to be 626/526 for Atari ST in PAL/NTSC mode -assign frame_height = pal?626:526; -assign screen_height = pal?576:484; -assign vsync_pulse_start = pal?5:9; -assign vsync_pulse_size = pal?5:6; +assign frame_height = (stmode==2'd0)?526:(stmode==2'd1)?626:501; +assign screen_height = (stmode==2'd0)?484:(stmode==2'd1)?576:400; +assign vsync_pulse_start = (stmode==2'd0)?9:5; +assign vsync_pulse_size = (stmode==2'd0)?6:5; assign invert = 2'b11; always_comb begin @@ -225,7 +225,7 @@ generate .VENDOR_NAME(VENDOR_NAME), .PRODUCT_DESCRIPTION(PRODUCT_DESCRIPTION), .SOURCE_DEVICE_INFORMATION(SOURCE_DEVICE_INFORMATION) - ) packet_picker (.clk_pixel(clk_pixel), .clk_audio(clk_audio), .reset(reset), .pal(pal), .video_field_end(video_field_end), .packet_enable(packet_enable), .packet_pixel_counter(packet_pixel_counter), .audio_sample_word(audio_sample_word), .header(header), .sub(sub)); + ) packet_picker (.clk_pixel(clk_pixel), .clk_audio(clk_audio), .reset(reset), .stmode(stmode), .video_field_end(video_field_end), .packet_enable(packet_enable), .packet_pixel_counter(packet_pixel_counter), .audio_sample_word(audio_sample_word), .header(header), .sub(sub)); logic [8:0] packet_data; packet_assembler packet_assembler (.clk_pixel(clk_pixel), .reset(reset), .data_island_period(data_island_period), .header(header), .sub(sub), .packet_data(packet_data), .counter(packet_pixel_counter)); diff --git a/src/hdmi/packet_picker.sv b/src/hdmi/packet_picker.sv index d7dd9e8..ea6f1bb 100644 --- a/src/hdmi/packet_picker.sv +++ b/src/hdmi/packet_picker.sv @@ -15,7 +15,7 @@ module packet_picker input logic clk_pixel, input logic clk_audio, input logic reset, - input logic pal, + input logic [1:0] stmode, input logic video_field_end, input logic packet_enable, input logic [4:0] packet_pixel_counter, @@ -133,7 +133,7 @@ audio_sample_packet #(.SAMPLING_FREQUENCY(SAMPLING_FREQUENCY), .WORD_LENGTH({{WO auxiliary_video_information_info_frame #( .IT_CONTENT(IT_CONTENT) -) auxiliary_video_information_info_frame(.pal(pal), .header(headers[130]), .sub(subs[130])); +) auxiliary_video_information_info_frame(.stmode(stmode), .header(headers[130]), .sub(subs[130])); source_product_description_info_frame #(.VENDOR_NAME(VENDOR_NAME), .PRODUCT_DESCRIPTION(PRODUCT_DESCRIPTION), .SOURCE_DEVICE_INFORMATION(SOURCE_DEVICE_INFORMATION)) source_product_description_info_frame(.header(headers[131]), .sub(subs[131])); diff --git a/src/misc/scandoubler.v b/src/misc/scandoubler.v index fcbdc22..209b5e0 100644 --- a/src/misc/scandoubler.v +++ b/src/misc/scandoubler.v @@ -87,9 +87,9 @@ end always @(posedge clk_sys) begin if(bypass) begin - r_out <= r; - g_out <= g; - b_out <= b; + r_out <= { r, 2'b00 }; + g_out <= { g, 2'b00 }; + b_out <= { b, 2'b00 }; hs_out <= hs_sd; vs_out <= vs_sd; end else if(ce_x2) begin @@ -205,7 +205,7 @@ always @(posedge clk_sys) begin vs_sd <= vs_in; end if(bypass) begin - sd_bypass_out <= {r_in, g_in, b_in}; + sd_bypass_out <= {r_in, g_in, b_in }; hs_sd <= hs_in; vs_sd <= vs_in; end diff --git a/src/misc/video_analyzer.v b/src/misc/video_analyzer.v index 03189a7..676d87b 100644 --- a/src/misc/video_analyzer.v +++ b/src/misc/video_analyzer.v @@ -7,13 +7,13 @@ module video_analyzer ( // system interface - input clk, - input hs, - input vs, - input de, + input clk, + input hs, + input vs, + input de, - output reg pal, - output reg vreset + output reg [1:0] mode, // 0=ntsc, 1=pal, 2=mono + output reg vreset ); @@ -54,17 +54,26 @@ always @(posedge clk) begin vcnt <= 0; // check for PAL/NTSC values - if(vcnt == 10'd312 && hcntL == 13'd2047) pal <= 1'b1; - if(vcnt == 10'd262 && hcntL == 13'd2031) pal <= 1'b0; + if(vcnt == 10'd312 && hcntL == 13'd2047) mode <= 2'd1; // PAL + if(vcnt == 10'd262 && hcntL == 13'd2031) mode <= 2'd0; // NTSC + + // check for MONO + if(vcnt == 10'd500 && hcntL == 13'd895) mode <= 2'd2; // MONO end else vcnt <= vcnt + 10'd1; end - + + // the reset signal is sent to the HDMI generator. On reset the + // HDMI re-adjusts its counters to the start of the visible screen + // area + vreset <= 1'b0; - // account for back porches - if( (hcnt == 152 && vcnt == 28 && changed && pal) || - (hcnt == 152 && vcnt == 18 && changed && !pal) ) begin + // account for back porches to adjust image position within the + // HDMI frame + if( (hcnt == 244 && vcnt == 36 && changed && mode == 2'd2) || + (hcnt == 152 && vcnt == 28 && changed && mode == 2'd1) || + (hcnt == 152 && vcnt == 18 && changed && mode == 2'd0) ) begin vreset <= 1'b1; changed <= 1'b0; end diff --git a/src/tangnano20k/top.sv b/src/tangnano20k/top.sv index 8a5d508..94f3cfa 100644 --- a/src/tangnano20k/top.sv +++ b/src/tangnano20k/top.sv @@ -1,8 +1,5 @@ /* top.sv - atarist on tang nano toplevel */ -// `define BLACKBERRY_TRACKBALL -`define JOYSTICK_MOUSE - module top( input clk, @@ -33,6 +30,8 @@ module top( // generic IO, used for mouse/joystick/... input [7:0] io, + // config inputs + input [3:0] cfg, // SD card slot output sd_clk, @@ -79,8 +78,9 @@ flash flash ( .ready(flash_ready), .busy(), - // cpu expects ROM to start at fc0000 and it in fact is at 100000 - .address( { 5'b00100, rom_addr[17:1] } ), + // cpu expects ROM to start at $fc0000 and it is in fact is at $100000 in + // ST mode and at $140000 in STE mode + .address( { 4'b0010, !cfg[3], rom_addr[17:1] } ), .cs( !rom_n ), .dout(rom_dout), @@ -119,12 +119,15 @@ sdram sdram ( .sd_ras(O_sdram_ras_n), // row address select .sd_cas(O_sdram_cas_n), // columns address select + // allow RAM access to the entire 8MB provided by the + // Tang Nano 20k. It's up to the ST chipset to make use + // if this .refresh(refresh), .din(mdout), // data input from chipset/cpu .dout(mdin), .addr(ram_a[22:1]), // 22 bit word address .ds( { cash_n, casl_n } ), // upper/lower data strobe - .cs( !ras_n ), // cpu/chipset requests read/write + .cs( !ras_n && !ram_a[23] ),// cpu/chipset requests read/write .we( !we_n ) // cpu/chipset requests write ); @@ -137,7 +140,6 @@ wire [3:0] st_b; wire [14:0] audio_l; wire [14:0] audio_r; -`ifdef JOYSTICK_MOUSE // -------------------- simulate mouse from joystick signals ------------------------ reg [32:0] mouse_emu_cnt; always @(posedge clk_32) begin @@ -148,10 +150,9 @@ always @(posedge clk_32) begin end wire mbit = mouse_emu_cnt[19]; -wire [5:0] joy0 = { !io[0], !io[1], !io[3] & mbit, !io[2] & mbit, !io[5] & mbit, !io[4] & mbit }; -`endif +wire [5:0] mjoy_joy0 = { !io[0], !io[1], !io[3] & mbit, !io[2] & mbit, !io[5] & mbit, !io[4] & mbit }; -`ifdef BLACKBERRY_TRACKBALL +// -------------------- parse blackberry trackball signals ------------------------ reg [7:0] ioD; reg [1:0] mouse_x; @@ -167,9 +168,12 @@ always @(posedge clk_32) begin if(ioD[1] != ioD[0]) mouse_y <= { mouse_y[0], !mouse_y[1] }; end -wire [5:0] joy0 = { !io[0], !io[1], mouse_x[1], mouse_x[0], mouse_y[1], mouse_y[0] }; -`endif +wire [5:0] mbtb_joy0 = { !io[0], !io[1], mouse_x[1], mouse_x[0], mouse_y[1], mouse_y[0] }; + +// cfg[1] selects between "joystick mouse" and "blackberry trackball" +wire [5:0] joy0 = cfg[1]?mjoy_joy0:mbtb_joy0; +// signals to wire the floppy controller to the sd card wire [1:0] sd_rd; // fdc requests sector read wire [7:0] sd_rd_data; wire [31:0] sd_lba; @@ -192,7 +196,7 @@ atarist atarist ( .r(st_r), .g(st_g), .b(st_b), - .monomode(), + .mono_detect(cfg[0]), // mono=0, color=1 .keyboard_matrix_out(), .keyboard_matrix_in(8'hff), @@ -224,6 +228,9 @@ atarist atarist ( .rom_addr(rom_addr), .rom_data_out(rom_dout), + .ste(!cfg[3]), // enable STE mode if cfg[3] is tied to GND + .enable_extra_ram(!cfg[2]), // enable extra ram if cfg[2] is tied to gnd + // interface to sdram .ram_ras_n(ras_n), .ram_cash_n(cash_n), diff --git a/src/tangnano20k/video.v b/src/tangnano20k/video.v index dfc2a4f..b95d78c 100644 --- a/src/tangnano20k/video.v +++ b/src/tangnano20k/video.v @@ -57,7 +57,8 @@ always @(posedge clk_pixel) begin end end -wire vreset, vpal; +wire vreset; +wire [1:0] vmode; video_analyzer video_analyzer ( .clk(clk_pixel), @@ -65,7 +66,7 @@ video_analyzer video_analyzer ( .hs(hs_in_n), .de(de_in), - .pal(vpal), + .mode(vmode), .vreset(vreset) // reset signal ); @@ -77,8 +78,8 @@ wire [5:0] sd_b; scandoubler #(10) scandoubler ( // system interface .clk_sys(clk_pixel), - .bypass(1'b0), - .ce_divider(1'b1), // /2 + .bypass(vmode == 2'd2), // bypass in ST high/mono + .ce_divider(1'b1), .pixel_ena(), // scanlines (00-none 01-25% 10-50% 11-75%) @@ -115,7 +116,7 @@ hdmi #( .tmds_clock(tmds_clock), // video input - .pal(vpal), // current video mode is ST PAL 50Hz + .stmode(vmode), // current video mode PAL/NTSC/MONO .reset(vreset), // signal to synchronize HDMI // Atari STE outputs 4 bits per color. Scandoubler outputs 6 bits (to be