diff --git a/apple-one.qsf b/apple-one.qsf index e01907c..9e1ce2e 100644 --- a/apple-one.qsf +++ b/apple-one.qsf @@ -154,7 +154,11 @@ set_global_assignment -name PRE_FLOW_SCRIPT_FILE "quartus_sh:rtl/build_id.tcl" # end ENTITY(apple1_mist) # ----------------------- +set_global_assignment -name VERILOG_FILE rtl/aci.v set_global_assignment -name VERILOG_FILE rtl/display_ram.v +set_global_assignment -name VERILOG_FILE rtl/tms9918/vram.v +set_global_assignment -name VERILOG_FILE rtl/tms9918/tms9918_async.v +set_global_assignment -name VERILOG_FILE rtl/tms9918/tms9918.v set_global_assignment -name SYSTEMVERILOG_FILE rtl/ram.sv set_global_assignment -name SYSTEMVERILOG_FILE rtl/downloader.sv set_global_assignment -name VERILOG_FILE rtl/display.v @@ -183,4 +187,26 @@ set_global_assignment -name VERILOG_FILE rtl/ps2keyboard.v set_global_assignment -name VERILOG_FILE rtl/font_rom.v set_global_assignment -name QIP_FILE rtl/pll.qip set_global_assignment -name SYSTEMVERILOG_FILE rtl/apple1_mist.sv +set_global_assignment -name VHDL_FILE "rtl/tms9918/vdp18/vdp18_sprite-c.vhd" +set_global_assignment -name VHDL_FILE rtl/tms9918/vdp18/vdp18_sprite.vhd +set_global_assignment -name VHDL_FILE "rtl/tms9918/vdp18/vdp18_pattern-c.vhd" +set_global_assignment -name VHDL_FILE rtl/tms9918/vdp18/vdp18_pattern.vhd +set_global_assignment -name VHDL_FILE "rtl/tms9918/vdp18/vdp18_pack-p.vhd" +set_global_assignment -name VHDL_FILE "rtl/tms9918/vdp18/vdp18_hor_vert-c.vhd" +set_global_assignment -name VHDL_FILE rtl/tms9918/vdp18/vdp18_hor_vert.vhd +set_global_assignment -name VHDL_FILE "rtl/tms9918/vdp18/vdp18_ctrl-c.vhd" +set_global_assignment -name VHDL_FILE rtl/tms9918/vdp18/vdp18_ctrl.vhd +set_global_assignment -name VHDL_FILE "rtl/tms9918/vdp18/vdp18_cpuio-c.vhd" +set_global_assignment -name VHDL_FILE rtl/tms9918/vdp18/vdp18_cpuio.vhd +set_global_assignment -name VHDL_FILE "rtl/tms9918/vdp18/vdp18_core-c.vhd" +set_global_assignment -name VHDL_FILE "rtl/tms9918/vdp18/vdp18_core_comp_pack-p.vhd" +set_global_assignment -name VHDL_FILE rtl/tms9918/vdp18/vdp18_core.vhd +set_global_assignment -name VHDL_FILE "rtl/tms9918/vdp18/vdp18_comp_pack-p.vhd" +set_global_assignment -name VHDL_FILE "rtl/tms9918/vdp18/vdp18_col_pack-p.vhd" +set_global_assignment -name VHDL_FILE "rtl/tms9918/vdp18/vdp18_col_mux-c.vhd" +set_global_assignment -name VHDL_FILE rtl/tms9918/vdp18/vdp18_col_mux.vhd +set_global_assignment -name VHDL_FILE "rtl/tms9918/vdp18/vdp18_clk_gen-c.vhd" +set_global_assignment -name VHDL_FILE rtl/tms9918/vdp18/vdp18_clk_gen.vhd +set_global_assignment -name VHDL_FILE "rtl/tms9918/vdp18/vdp18_addr_mux-c.vhd" +set_global_assignment -name VHDL_FILE rtl/tms9918/vdp18/vdp18_addr_mux.vhd set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/rtl/aci.v b/rtl/aci.v new file mode 100644 index 0000000..ed10630 --- /dev/null +++ b/rtl/aci.v @@ -0,0 +1,35 @@ +// Apple-1 Audio cassette interface (ACI) + +// A good explanation of ACI can be found at: +// https://www.sbprojects.net/projects/apple1/aci.php + +module ACI ( + input clk, // clock signal + input cpu_clken, // CPU clock enable + + input [15:0] address, // address bus + output reg [7:0] dout, // 8-bit data bus (output) + + output reg tape_out, // tape output + input tape_in // tape input +); + + reg [7:0] rom_data[0:255]; + + initial + $readmemh("roms/aci.hex", rom_data, 0, 255); + + wire io_range = address >= 16'hC000 && address <= 16'hC0FF; + + wire [7:0] read_address = io_range ? { address[7:1], address[0] & tape_in } : address[7:0]; + + always @(posedge clk) begin + + if(cpu_clken & io_range) + tape_out <= ~tape_out; + + dout <= rom_data[read_address]; + end + +endmodule + \ No newline at end of file diff --git a/rtl/apple1_mist.sv b/rtl/apple1_mist.sv index 4501d28..d3b3baa 100644 --- a/rtl/apple1_mist.sv +++ b/rtl/apple1_mist.sv @@ -4,19 +4,24 @@ // // +// TODO use a CPU that allows illegal instructions // TODO make it work with SDRAM -// TODO ram refresh lost cycles +// TODO ram refresh lost CPU cycles // TODO power on-off key ? (init ram) // TODO ram powerup initial values // TODO reorganize file structure -// TODO support ACI interface for load and save -// TODO special expansion boards: TMS9918, SID, AY? +// TODO ACI: create ROM +// TODO ACI: implementation +// TODO more accurate chip selection circuit // TODO check diff with updated data_io.v and other modules +// TODO keyboard: use a PIA // TODO keyboard: isolate ps2 keyboard from apple1 // TODO keyboard: check ps2 clock // TODO keyboard: reset key // TODO keyboard: make a true ascii keyboard +// TODO keyboard: check backspace key // TODO osd menu yellow, why it doesn't work? +// TODO display: remove char_seen // TODO display: check NTSC AD724 hsync problem // TODO display: powerup values // TODO display: simplify rom font @@ -24,7 +29,10 @@ // TODO display: check parameters vs real apple1 // TODO display: check cursor blinking vs 555 timings // TODO display: emulate PIA registers - +// TODO tms9918: fix video sync on composite and mist_video +// TODO tms9918: make it selectable / use include in code +// TODO tms9918: connect /INT +// TODO sid: implement 6581 module apple1_mist( input CLOCK_27, @@ -75,9 +83,8 @@ module apple1_mist( localparam CONF_STR = { "APPLE 1;;", // 0 download index for "apple1.rom" - "F,PRG,Load program;", // 1 download index for ".prg" files - "F,ROM,Load firmware;", // 2 download index for ".rom" files - "O34,Scandoubler Fx,None,HQ2x,CRT 25%,CRT 50%;", + "F,PRG,Load program;", // 1 download index for ".prg" files + "O2,TMS9918 output,Off,On;", "T6,Reset;", "V,v1.01.",`BUILD_DATE }; @@ -94,6 +101,8 @@ wire [31:0] status; wire [1:0] buttons; wire [1:0] switches; +wire st_tms9918_output = status[2]; + wire scandoubler_disable; wire ypbpr; wire no_csync; @@ -113,6 +122,7 @@ wire pll_locked; wire sys_clock; // cpu x 7 x 8 system clock (sdram.v) wire osd_clock; // cpu x 7 x 2 for the OSD menu +wire vdp_clock; // tms9918 x 2 for osd menu pll pll ( @@ -121,7 +131,8 @@ pll pll .c0( osd_clock ), // cpu x 7 x 2 video clock for OSD menu .c2( sys_clock ), // cpu x 7 x 8 system clock (sdram.v) - .c3( SDRAM_CLK ) // cpu x 7 x 8 phase shifted -2.5 ns + .c3( SDRAM_CLK ), // cpu x 7 x 8 phase shifted -2.5 ns + .c4( vdp_clock ) // tms9918 x 2 for osd menu (10.738635 x 2 = 21.47727) ); /******************************************************************************************/ @@ -191,15 +202,6 @@ rom_wozmon rom_wozmon( .dout(rom_dout) ); -/* -// Basic ROM -wire [7:0] basic_dout; -rom_basic rom_basic( - .clk(sys_clock), - .address(cpu_addr[11:0]), - .dout(basic_dout) -); -*/ // Basic RAM wire [7:0] basic_dout; @@ -211,6 +213,42 @@ ram #(.SIZE(4096)) rom_basic( .dout (basic_dout) ); +/******************************************************************************************/ +/******************************************************************************************/ +/***************************************** @ACI *******************************************/ +/******************************************************************************************/ +/******************************************************************************************/ + +wire [7:0] aci_dout; +wire CASOUT; +ACI ACI( + .clk(sys_clock), + .cpu_clken(cpu_clken), + .address(sdram_addr[15:0]), + .dout(aci_dout), + .tape_in(CASIN), + .tape_out(CASOUT), +); + +// latches cassette audio input +reg CASIN; +always @(posedge sys_clock) begin + CASIN <= ~UART_RX; // on the Mistica UART_RX is the audio input +end + +wire audio; +dac #(.C_bits(16)) dac_AUDIO +( + .clk_i(sys_clock), + .res_n_i(pll_locked), + .dac_i({ CASOUT, 15'b0000000 }), // TODO not sure about polarity + .dac_o(audio) +); + +always @(posedge sys_clock) begin + AUDIO_L <= audio; + AUDIO_R <= audio; +end /******************************************************************************************/ /******************************************************************************************/ @@ -253,11 +291,15 @@ wire cpu_wr; wire ram_cs = sdram_addr < 'h4000; // 0x0000 -> 0x3FFF wire sdram_cs = sdram_addr >= 'h4000 && sdram_addr <= 'hBFFF; // 0x4000 -> 0xBFFF +wire aci_cs = sdram_addr >= 'hC000 && sdram_addr <= 'hC1FF; // 0xC000 -> 0xC1FF +wire tms_cs = sdram_addr >= 'hCC00 && sdram_addr <= 'hCC01; // 0xCC00 -> 0xCC01 wire basic_cs = sdram_addr >= 'hE000 && sdram_addr <= 'hEFFF; // 0xE000 -> 0xEFFF wire rom_cs = sdram_addr >= 'hFF00; // 0xFF00 -> 0xFFFF wire [7:0] bus_dout = rom_cs ? rom_dout : basic_cs ? basic_dout : + tms_cs ? vdp_dout : + aci_cs ? aci_dout : sdram_cs ? sdram_dout : ram_cs ? ram_dout : 8'b0; @@ -300,7 +342,9 @@ mist_video #( .COLOR_DEPTH(1), // 1 bit color depth .OSD_AUTO_CE(1), // OSD autodetects clock enable - .OSD_COLOR(3'b110) // yellow menu color + .OSD_COLOR(3'b110), // yellow menu color + .SYNC_AND(1), + .SD_HCNT_WIDTH(11) ) mist_video ( @@ -329,11 +373,73 @@ mist_video .VSync(vs), // video output signals that go into MiST hardware - .VGA_R(VGA_R), - .VGA_G(VGA_G), - .VGA_B(VGA_B), - .VGA_VS(VGA_VS), - .VGA_HS(VGA_HS) + .VGA_R(apple1_R), + .VGA_G(apple1_G), + .VGA_B(apple1_B), + .VGA_VS(apple1_VS), + .VGA_HS(apple1_HS) +); + +wire [5:0] apple1_R; +wire [5:0] apple1_G; +wire [5:0] apple1_B; +wire apple1_HS; +wire apple1_VS; + +// mix video +assign VGA_R = st_tms9918_output ? tms_R : apple1_R ; +assign VGA_G = st_tms9918_output ? tms_G : apple1_G ; +assign VGA_B = st_tms9918_output ? tms_B : apple1_B ; +assign VGA_HS = st_tms9918_output ? tms_HS & tms_VS : apple1_HS; +assign VGA_VS = st_tms9918_output ? tms_VS : apple1_VS; + +wire [5:0] tms_out_R; +wire [5:0] tms_out_G; +wire [5:0] tms_out_B; +wire tms_out_HS; +wire tms_out_VS; + +mist_video +#( + .COLOR_DEPTH(6), // 1 bit color depth + .OSD_AUTO_CE(1), // OSD autodetects clock enable + .OSD_COLOR(3'b110), // yellow menu color + .SYNC_AND(1), + .SD_HCNT_WIDTH(11) +) +tms_mist_video +( + //.clk_sys(vdp_clock), // OSD needs 2x the VDP clock for the scandoubler + .clk_sys(osd_clock), + + // OSD SPI interface + .SPI_DI(SPI_DI), + .SPI_SCK(SPI_SCK), + .SPI_SS3(SPI_SS3), + + .scanlines(2'b00), // scanline emulation disabled for now + .ce_divider(1), // non-scandoubled pixel clock divider 0 - clk_sys/4, 1 - clk_sys/2 + + .scandoubler_disable(scandoubler_disable), // disable scandoubler option from mist.ini + .no_csync(no_csync), // csync option from mist.ini + .ypbpr(ypbpr), // YPbPr option from mist.ini + + .rotate(2'b00), // no ODS rotation + .blend(0), // composite-like blending + + // video input signals to mist_video + .R (tms_R ), + .G (tms_G ), + .B (tms_B ), + .HSync(tms_HS), + .VSync(tms_vs), + + // video output signals that go into MiST hardware + .VGA_R(tms_out_R), + .VGA_G(tms_out_G), + .VGA_B(tms_out_B), + .VGA_VS(tms_out_VS), + .VGA_HS(tms_out_HS) ); /******************************************************************************************/ @@ -450,4 +556,85 @@ clock clock( .pixel_clken( pixel_clken ) // output: pixel clock enable ); + +/******************************************************************************************/ +/******************************************************************************************/ +/***************************************** @vdp *******************************************/ +/******************************************************************************************/ +/******************************************************************************************/ + +wire vram_we; +wire [0:13] vram_a; +wire [0:7] vram_din; +wire [0:7] vram_dout; + +vram vram +( + .clock ( vdp_clock ), + .address( vram_a ), + .data ( vram_din ), + .wren ( vram_we ), + .q ( vram_dout ) +); + +wire [7:0] vdp_dout; +wire VDP_INT_n; // TODO not connected yet + +// divide by two the vdp_clock (which is doubled for the scandoubler) +reg vdp_ena; +always @(posedge vdp_clock) begin + vdp_ena <= ~vdp_ena; +end + +wire csr = tms_cs & sdram_rd; +wire csw = tms_cs & sdram_wr; + +wire tms_HS; +wire tms_VS; +wire [5:0] tms_R; +wire [5:0] tms_G; +wire [5:0] tms_B; + +tms9918_async +#( + .HORIZONTAL_SHIFT(-36) // -36 good empiric value to center the image on the screen +) +tms9918 +( + // clock + .RESET(reset_button), + + .clk(vdp_clock), + .ena(vdp_ena), + + /* + .clk(sys_clock), + .ena(pixel_clken), + */ + + // control signals + .csr_n ( ~csr ), + .csw_n ( ~csw ), + .mode ( sdram_addr[0] ), + .int_n ( VDP_INT_n ), + + // cpu I/O + .cd_i ( sdram_din ), + .cd_o ( vdp_dout ), + + // vram + .vram_we ( vram_we ), + .vram_a ( vram_a ), + .vram_d_o ( vram_din ), + .vram_d_i ( vram_dout ), + + // video + .HS(tms_HS), + .VS(tms_VS), + .R (tms_R), + .G (tms_G), + .B (tms_B) +); + endmodule + diff --git a/rtl/display.v b/rtl/display.v index 7177b27..538f9a4 100644 --- a/rtl/display.v +++ b/rtl/display.v @@ -125,7 +125,7 @@ module display ( ////////////////////////////////////////////////////////////////////////// // Video RAM - vram vram( + display_ram display_ram( .clk(sys_clock), .read_addr(vram_r_addr), .write_addr(vram_w_addr), @@ -250,7 +250,7 @@ module display ( if (address == 1'b0) // address low == TX register begin - if (cpu_clken & w_en & ~char_seen & ready) + if (cpu_clken & w_en /*& ~char_seen*/ & ready) begin // incoming character char_seen <= 1; diff --git a/rtl/pll.v b/rtl/pll.v index e2e7a6b..a8e4d98 100644 --- a/rtl/pll.v +++ b/rtl/pll.v @@ -43,6 +43,7 @@ module pll ( c1, c2, c3, + c4, locked); input areset; @@ -51,6 +52,7 @@ module pll ( output c1; output c2; output c3; + output c4; output locked; `ifndef ALTERA_RESERVED_QIS // synopsys translate_off @@ -61,25 +63,27 @@ module pll ( `endif wire [4:0] sub_wire0; - wire sub_wire3; - wire [0:0] sub_wire8 = 1'h0; - wire [2:2] sub_wire5 = sub_wire0[2:2]; - wire [0:0] sub_wire4 = sub_wire0[0:0]; - wire [3:3] sub_wire2 = sub_wire0[3:3]; + wire sub_wire6; + wire [0:0] sub_wire9 = 1'h0; + wire [3:3] sub_wire5 = sub_wire0[3:3]; + wire [4:4] sub_wire4 = sub_wire0[4:4]; + wire [2:2] sub_wire3 = sub_wire0[2:2]; + wire [0:0] sub_wire2 = sub_wire0[0:0]; wire [1:1] sub_wire1 = sub_wire0[1:1]; wire c1 = sub_wire1; - wire c3 = sub_wire2; - wire locked = sub_wire3; - wire c0 = sub_wire4; - wire c2 = sub_wire5; - wire sub_wire6 = inclk0; - wire [1:0] sub_wire7 = {sub_wire8, sub_wire6}; + wire c0 = sub_wire2; + wire c2 = sub_wire3; + wire c4 = sub_wire4; + wire c3 = sub_wire5; + wire locked = sub_wire6; + wire sub_wire7 = inclk0; + wire [1:0] sub_wire8 = {sub_wire9, sub_wire7}; altpll altpll_component ( .areset (areset), - .inclk (sub_wire7), + .inclk (sub_wire8), .clk (sub_wire0), - .locked (sub_wire3), + .locked (sub_wire6), .activeclock (), .clkbad (), .clkena ({6{1'b1}}), @@ -131,6 +135,10 @@ module pll ( altpll_component.clk3_duty_cycle = 50, altpll_component.clk3_multiply_by = 715909, altpll_component.clk3_phase_shift = "-2500", + altpll_component.clk4_divide_by = 900000, + altpll_component.clk4_duty_cycle = 50, + altpll_component.clk4_multiply_by = 715909, + altpll_component.clk4_phase_shift = "0", altpll_component.compensate_clock = "CLK0", altpll_component.inclk0_input_frequency = 37037, altpll_component.intended_device_family = "Cyclone III", @@ -167,7 +175,7 @@ module pll ( altpll_component.port_clk1 = "PORT_USED", altpll_component.port_clk2 = "PORT_USED", altpll_component.port_clk3 = "PORT_USED", - altpll_component.port_clk4 = "PORT_UNUSED", + altpll_component.port_clk4 = "PORT_USED", altpll_component.port_clk5 = "PORT_UNUSED", altpll_component.port_clkena0 = "PORT_UNUSED", altpll_component.port_clkena1 = "PORT_UNUSED", @@ -208,14 +216,17 @@ endmodule // Retrieval info: PRIVATE: DIV_FACTOR1 NUMERIC "27" // Retrieval info: PRIVATE: DIV_FACTOR2 NUMERIC "1" // Retrieval info: PRIVATE: DIV_FACTOR3 NUMERIC "1" +// Retrieval info: PRIVATE: DIV_FACTOR4 NUMERIC "1" // Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" // Retrieval info: PRIVATE: DUTY_CYCLE1 STRING "50.00000000" // Retrieval info: PRIVATE: DUTY_CYCLE2 STRING "50.00000000" // Retrieval info: PRIVATE: DUTY_CYCLE3 STRING "50.00000000" +// Retrieval info: PRIVATE: DUTY_CYCLE4 STRING "50.00000000" // Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "14.318180" // Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE1 STRING "7.159090" // Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE2 STRING "57.272720" // Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE3 STRING "57.272720" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE4 STRING "21.477270" // Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" // Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" // Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" @@ -239,39 +250,47 @@ endmodule // Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT1 STRING "deg" // Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT2 STRING "ps" // Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT3 STRING "ps" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT4 STRING "ps" // Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" // Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" // Retrieval info: PRIVATE: MIRROR_CLK1 STRING "0" // Retrieval info: PRIVATE: MIRROR_CLK2 STRING "0" // Retrieval info: PRIVATE: MIRROR_CLK3 STRING "0" +// Retrieval info: PRIVATE: MIRROR_CLK4 STRING "0" // Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "25" // Retrieval info: PRIVATE: MULT_FACTOR1 NUMERIC "25" // Retrieval info: PRIVATE: MULT_FACTOR2 NUMERIC "1" // Retrieval info: PRIVATE: MULT_FACTOR3 NUMERIC "1" +// Retrieval info: PRIVATE: MULT_FACTOR4 NUMERIC "1" // Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" // Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "14.31818000" // Retrieval info: PRIVATE: OUTPUT_FREQ1 STRING "7.15909000" // Retrieval info: PRIVATE: OUTPUT_FREQ2 STRING "57.27272000" // Retrieval info: PRIVATE: OUTPUT_FREQ3 STRING "57.27272000" +// Retrieval info: PRIVATE: OUTPUT_FREQ4 STRING "21.47727000" // Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "1" // Retrieval info: PRIVATE: OUTPUT_FREQ_MODE1 STRING "1" // Retrieval info: PRIVATE: OUTPUT_FREQ_MODE2 STRING "1" // Retrieval info: PRIVATE: OUTPUT_FREQ_MODE3 STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE4 STRING "1" // Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" // Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT1 STRING "MHz" // Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT2 STRING "MHz" // Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT3 STRING "MHz" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT4 STRING "MHz" // Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "1" // Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" // Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" // Retrieval info: PRIVATE: PHASE_SHIFT1 STRING "0.00000000" // Retrieval info: PRIVATE: PHASE_SHIFT2 STRING "0.00000000" // Retrieval info: PRIVATE: PHASE_SHIFT3 STRING "-2500.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT4 STRING "0.00000000" // Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" // Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" // Retrieval info: PRIVATE: PHASE_SHIFT_UNIT1 STRING "deg" // Retrieval info: PRIVATE: PHASE_SHIFT_UNIT2 STRING "ps" // Retrieval info: PRIVATE: PHASE_SHIFT_UNIT3 STRING "ps" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT4 STRING "ps" // Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" // Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" // Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" @@ -297,6 +316,7 @@ endmodule // Retrieval info: PRIVATE: STICKY_CLK1 STRING "1" // Retrieval info: PRIVATE: STICKY_CLK2 STRING "1" // Retrieval info: PRIVATE: STICKY_CLK3 STRING "1" +// Retrieval info: PRIVATE: STICKY_CLK4 STRING "1" // Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" // Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" // Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" @@ -304,10 +324,12 @@ endmodule // Retrieval info: PRIVATE: USE_CLK1 STRING "1" // Retrieval info: PRIVATE: USE_CLK2 STRING "1" // Retrieval info: PRIVATE: USE_CLK3 STRING "1" +// Retrieval info: PRIVATE: USE_CLK4 STRING "1" // Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" // Retrieval info: PRIVATE: USE_CLKENA1 STRING "0" // Retrieval info: PRIVATE: USE_CLKENA2 STRING "0" // Retrieval info: PRIVATE: USE_CLKENA3 STRING "0" +// Retrieval info: PRIVATE: USE_CLKENA4 STRING "0" // Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" // Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" // Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all @@ -328,6 +350,10 @@ endmodule // Retrieval info: CONSTANT: CLK3_DUTY_CYCLE NUMERIC "50" // Retrieval info: CONSTANT: CLK3_MULTIPLY_BY NUMERIC "715909" // Retrieval info: CONSTANT: CLK3_PHASE_SHIFT STRING "-2500" +// Retrieval info: CONSTANT: CLK4_DIVIDE_BY NUMERIC "900000" +// Retrieval info: CONSTANT: CLK4_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK4_MULTIPLY_BY NUMERIC "715909" +// Retrieval info: CONSTANT: CLK4_PHASE_SHIFT STRING "0" // Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" // Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "37037" // Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III" @@ -363,7 +389,7 @@ endmodule // Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_USED" // Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_USED" // Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_USED" -// Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_USED" // Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" // Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" // Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" @@ -383,6 +409,7 @@ endmodule // Retrieval info: USED_PORT: c1 0 0 0 0 OUTPUT_CLK_EXT VCC "c1" // Retrieval info: USED_PORT: c2 0 0 0 0 OUTPUT_CLK_EXT VCC "c2" // Retrieval info: USED_PORT: c3 0 0 0 0 OUTPUT_CLK_EXT VCC "c3" +// Retrieval info: USED_PORT: c4 0 0 0 0 OUTPUT_CLK_EXT VCC "c4" // Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" // Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" // Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0 @@ -392,6 +419,7 @@ endmodule // Retrieval info: CONNECT: c1 0 0 0 0 @clk 0 0 1 1 // Retrieval info: CONNECT: c2 0 0 0 0 @clk 0 0 1 2 // Retrieval info: CONNECT: c3 0 0 0 0 @clk 0 0 1 3 +// Retrieval info: CONNECT: c4 0 0 0 0 @clk 0 0 1 4 // Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 // Retrieval info: GEN_FILE: TYPE_NORMAL pll.v TRUE // Retrieval info: GEN_FILE: TYPE_NORMAL pll.ppf TRUE diff --git a/rtl/roms/aci.hex b/rtl/roms/aci.hex new file mode 100644 index 0000000..f767bdf --- /dev/null +++ b/rtl/roms/aci.hex @@ -0,0 +1,256 @@ +A9 +AA +20 +EF +FF +A9 +8D +20 +EF +FF +A0 +FF +C8 +AD +11 +D0 +10 +FB +AD +10 +D0 +99 +00 +02 +20 +EF +FF +C9 +9B +F0 +E1 +C9 +8D +D0 +E9 +A2 +FF +A9 +00 +85 +24 +85 +25 +85 +26 +85 +27 +E8 +BD +00 +02 +C9 +D2 +F0 +56 +C9 +D7 +F0 +35 +C9 +AE +F0 +27 +C9 +8D +F0 +20 +C9 +A0 +F0 +E8 +49 +B0 +C9 +0A +90 +06 +69 +88 +C9 +FA +90 +AD +0A +0A +0A +0A +A0 +04 +0A +26 +24 +26 +25 +88 +D0 +F8 +F0 +CC +4C +1A +FF +A5 +24 +85 +26 +A5 +25 +85 +27 +B0 +BF +A9 +40 +20 +CC +C1 +88 +A2 +00 +A1 +26 +A2 +10 +0A +20 +DB +C1 +D0 +FA +20 +F1 +C1 +A0 +1E +90 +EC +A6 +28 +B0 +98 +20 +BC +C1 +A9 +16 +20 +CC +C1 +20 +BC +C1 +A0 +1F +20 +BF +C1 +B0 +F9 +20 +BF +C1 +A0 +3A +A2 +08 +48 +20 +BC +C1 +68 +2A +A0 +39 +CA +D0 +F5 +81 +26 +20 +F1 +C1 +A0 +35 +90 +EA +B0 +CD +20 +BF +C1 +88 +AD +81 +C0 +C5 +29 +F0 +F8 +85 +29 +C0 +80 +60 +86 +28 +A0 +42 +20 +E0 +C1 +D0 +F9 +69 +FE +B0 +F5 +A0 +1E +20 +E0 +C1 +A0 +2C +88 +D0 +FD +90 +05 +A0 +2F +88 +D0 +FD +BC +00 +C0 +A0 +29 +CA +60 +A5 +26 +C5 +24 +A5 +27 +E5 +25 +E6 +26 +D0 +02 +E6 +27 +60 diff --git a/rtl/tms9918/tms9918.v b/rtl/tms9918/tms9918.v new file mode 100644 index 0000000..1fca55a --- /dev/null +++ b/rtl/tms9918/tms9918.v @@ -0,0 +1,116 @@ +module tms9918 +( + input RESET, + input clk, + input ena, + + // control signals + input csr_n, + input csw_n, + input mode, + output int_n, + + // cpu I/O + input [0:7] cd_i, + output [0:7] cd_o, + + // vram + output vram_we, + output [0:13] vram_a, + output [0:7] vram_d_o, + input [0:7] vram_d_i, + + // video + output HS, + output VS, + output [5:0] R, + output [5:0] G, + output [5:0] B +); + +vdp18_core + +#( + .is_pal_g(0) // NTSC +) + +vdp +( + .clk_i ( clk ), + .clk_en_10m7_i ( ena ), + .reset_n_i ( ~RESET ), + + .csr_n_i ( csr_n ), + .csw_n_i ( csw_n ), + .mode_i ( mode ), + .int_n_o ( int_n ), + + .cd_i ( cd_i ), + .cd_o ( cd_o ), + + .vram_we_o ( vram_we ), + .vram_a_o ( vram_a ), + .vram_d_o ( vram_d_o ), + .vram_d_i ( vram_d_i ), + + .rgb_r_o ( vdp_r_ ), + .rgb_g_o ( vdp_g_ ), + .rgb_b_o ( vdp_b_ ), + .hsync_n_o ( vdp_hs ), + .vsync_n_o ( vdp_vs ) + +); + +// video wires +wire vdp_vs; +wire vdp_hs; +wire [0:7] vdp_r_; +wire [0:7] vdp_g_; +wire [0:7] vdp_b_; +wire [5:0] vdp_r = { vdp_r_[0],vdp_r_[1],vdp_r_[2],vdp_r_[3],vdp_r_[4],vdp_r_[5] } ; +wire [5:0] vdp_g = { vdp_g_[0],vdp_g_[1],vdp_g_[2],vdp_g_[3],vdp_g_[4],vdp_g_[5] } ; +wire [5:0] vdp_b = { vdp_b_[0],vdp_b_[1],vdp_b_[2],vdp_b_[3],vdp_b_[4],vdp_b_[5] } ; + + +/******************************************************************************************/ +/******************************************************************************************/ +/***************************************** @test ******************************************/ +/******************************************************************************************/ +/******************************************************************************************/ + +reg [15:0] hcnt; +reg [15:0] vcnt; +reg flip = 0; + +localparam EXTRA_PIXELS = 0; // 5 + +always @(posedge clk) begin + if(ena) begin + if(RESET) begin + hcnt <= -36; + vcnt <= 0; + end + else begin + flip = ~flip; + if(flip) begin + hcnt <= hcnt + 1; + if(hcnt == 341+EXTRA_PIXELS) begin + hcnt <= 0; + vcnt <= vcnt + 1; + if(vcnt == 260) vcnt <= 0; + end + end + end + end +end + +assign VS = 1 ? (vcnt < 4 ? 0 : 1) : vdp_hs; +assign HS = 1 ? (hcnt < 20 ? 0 : 1) : vdp_vs; + +wire blank = (vcnt < 8) || (hcnt < 60 || hcnt > 340); + +assign R = 1 ? (blank ? 0 : vdp_r) : vdp_r; +assign G = 1 ? (blank ? 0 : vdp_g) : vdp_r; +assign B = 1 ? (blank ? 0 : vdp_b) : vdp_r; + +endmodule diff --git a/rtl/tms9918/tms9918_async.v b/rtl/tms9918/tms9918_async.v new file mode 100644 index 0000000..f0e856d --- /dev/null +++ b/rtl/tms9918/tms9918_async.v @@ -0,0 +1,227 @@ +module tms9918_async +( + input RESET, + input clk, + input ena, + + // control signals + input csr_n, + input csw_n, + input mode, + output int_n, + + // cpu I/O + input [0:7] cd_i, + output [0:7] cd_o, + + // vram + output vram_we, + output [0:13] vram_a, + output [0:7] vram_d_o, + input [0:7] vram_d_i, + + // video + output HS, + output VS, + output [5:0] R, + output [5:0] G, + output [5:0] B +); + + +// cross clock domain resolution, from CPU clock to VDP clock; + +reg _metastable_csr_n; +reg _metastable_csw_n; +reg _metastable_mode; +reg [0:7] _metastable_cd_i; +reg [0:7] _metastable_cd_o; + +reg _stable_csr_n; +reg _stable_csw_n; +reg _stable_mode; +reg [0:7] _stable_cd_i; +reg [0:7] _stable_cd_o; + +reg [0:7] xcd_o; + +assign cd_o = _stable_cd_o; + +always @(posedge clk) begin + + { _stable_csr_n, _metastable_csr_n } <= { _metastable_csr_n, csr_n }; + { _stable_csw_n, _metastable_csw_n } <= { _metastable_csw_n, csw_n }; + { _stable_mode , _metastable_mode } <= { _metastable_mode , mode }; + { _stable_cd_i , _metastable_cd_i } <= { _metastable_cd_i , cd_i }; + { _stable_cd_o , _metastable_cd_o } <= { _metastable_cd_o , xcd_o }; + +end + +localparam IS_PAL = 0; +parameter HORIZONTAL_SHIFT = -36; + +vdp18_core + +#( + .is_pal_g(IS_PAL) // PAL or NTSC +) + +vdp +( + .clk_i ( clk ), + .clk_en_10m7_i ( ena ), + .reset_n_i ( ~RESET ), + + .csr_n_i ( _stable_csr_n ), + .csw_n_i ( _stable_csw_n ), + .mode_i ( _stable_mode ), + .int_n_o ( int_n ), + + .cd_i ( _stable_cd_i ), + .cd_o ( xcd_o ), + + .vram_we_o ( vram_we ), + .vram_a_o ( vram_a ), + .vram_d_o ( vram_d_o ), + .vram_d_i ( vram_d_i ), + + .rgb_r_o ( vdp_r_ ), + .rgb_g_o ( vdp_g_ ), + .rgb_b_o ( vdp_b_ ), + .hsync_n_o ( vdp_hs ), + .vsync_n_o ( vdp_vs ) + +); + +// video wires +wire vdp_vs; +wire vdp_hs; +wire [0:7] vdp_r_; +wire [0:7] vdp_g_; +wire [0:7] vdp_b_; +wire [5:0] vdp_r = { vdp_r_[0],vdp_r_[1],vdp_r_[2],vdp_r_[3],vdp_r_[4],vdp_r_[5] } ; +wire [5:0] vdp_g = { vdp_g_[0],vdp_g_[1],vdp_g_[2],vdp_g_[3],vdp_g_[4],vdp_g_[5] } ; +wire [5:0] vdp_b = { vdp_b_[0],vdp_b_[1],vdp_b_[2],vdp_b_[3],vdp_b_[4],vdp_b_[5] } ; + + +/******************************************************************************************/ +/******************************************************************************************/ +/***************************************** @test ******************************************/ +/******************************************************************************************/ +/******************************************************************************************/ + +/* +reg [15:0] hcnt; +reg [15:0] vcnt; +reg ena2 = 0; + +always @(posedge clk) begin + if(ena) begin + ena2 <= ~ena2; + end +end + +// screen geometry +// - NTSC: 342 x 261 +// - PAL: 342 x 312 + +localparam SCREEN_HWIDTH = 455; +localparam SCREEN_NLINES = IS_PAL ? 312 : 262; + +always @(posedge clk) begin + if(ena) begin + if(RESET) begin + hcnt <= 0; + vcnt <= 0; + end + else begin + hcnt <= hcnt + 1; + if(hcnt == (SCREEN_HWIDTH-1)) begin + hcnt <= 0; + vcnt <= vcnt + 1; + if(vcnt == SCREEN_NLINES-1) vcnt <= 0; + end + end + end +end + +wire active = (hcnt >= 104 && hcnt < 424) && (vcnt >= 42 && vcnt < 234); + +wire [2:0] bandcolor = (hcnt - 104) / 40; + +assign HS = hcnt < 32 ? 0 : 1; +assign VS = vcnt < 2 ? 0 : 1; +assign R = active ? { bandcolor[0], 5'b0 } : 6'b0; +assign G = active ? { bandcolor[1], 5'b0 } : 6'b0; +assign B = active ? { bandcolor[2], 5'b0 } : 6'b0; +*/ + +/* +localparam raw_output = 0; + +wire blank = (vcnt < 8) || (hcnt < 60 || hcnt > 340); + +wire filtered_hs = (hcnt < 20 ? 0 : 1); +wire filtered_vs = (vcnt < 4 ? 0 : 1); + +wire [5:0] filtered_R = (blank ? 0 : vdp_r); +wire [5:0] filtered_G = (blank ? 0 : vdp_g); +wire [5:0] filtered_B = (blank ? 0 : vdp_b); + +assign HS = raw_output ? vdp_hs : filtered_hs; +assign VS = raw_output ? vdp_vs : filtered_vs; +assign R = raw_output ? vdp_r : filtered_R; +assign G = raw_output ? vdp_g : filtered_G; +assign B = raw_output ? vdp_b : filtered_B; +*/ + +reg [15:0] hcnt; +reg [15:0] vcnt; +reg flip = 0; + + +// screen geometry +// - NTSC: 342 x 261 +// - PAL: 342 x 312 + +localparam SCREEN_HWIDTH = 342; +localparam SCREEN_NLINES = IS_PAL ? 312 : 261; + +always @(posedge clk) begin + if(ena) begin + if(RESET) begin + hcnt <= HORIZONTAL_SHIFT; // -36 is a good value for my CRT TV + vcnt <= 0; + end + else begin + flip = ~flip; + if(flip) begin + hcnt <= hcnt + 1; + if(hcnt == (SCREEN_HWIDTH-1)) begin + hcnt <= 0; + vcnt <= vcnt + 1; + if(vcnt == SCREEN_NLINES-1) vcnt <= 0; + end + end + end + end +end + +localparam raw_output = 0; + +wire blank = (vcnt < 8) || (hcnt < 60 || hcnt > 340); + +wire filtered_hs = (hcnt < 20 ? 0 : 1); +wire filtered_vs = (vcnt < 4 ? 0 : 1); + +wire [5:0] filtered_R = (blank ? 0 : vdp_r); +wire [5:0] filtered_G = (blank ? 0 : vdp_g); +wire [5:0] filtered_B = (blank ? 0 : vdp_b); + +assign HS = raw_output ? vdp_hs : filtered_hs; +assign VS = raw_output ? vdp_vs : filtered_vs; +assign R = raw_output ? vdp_r : filtered_R; +assign G = raw_output ? vdp_g : filtered_G; +assign B = raw_output ? vdp_b : filtered_B; + +endmodule diff --git a/rtl/tms9918/vdp18/COPYING b/rtl/tms9918/vdp18/COPYING new file mode 100644 index 0000000..60549be --- /dev/null +++ b/rtl/tms9918/vdp18/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/rtl/tms9918/vdp18/README b/rtl/tms9918/vdp18/README new file mode 100644 index 0000000..4576b2e --- /dev/null +++ b/rtl/tms9918/vdp18/README @@ -0,0 +1,201 @@ + +A Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A +========================================================== +Version: $Date: 2006/06/18 19:28:06 $ + +Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +See the file COPYING. + + +Integration +----------- + +The vdp18 design exhibits a set of interface signals that is compatible to the +original chips. It mainly differs in the video and VRAM interfaces, which are +tailored to better fit a modern SoC. + + generic ( + is_pal_g : integer := 0; + -- Select PAL or NTSC video timing. + -- 0 = NTSC + -- 1 = PAL + + compat_rgb_g : integer := 0 + -- Select full or compatibility RGB palettes. + -- Refer to vdp18_col_pack-p.vhd for details. + + ); + port ( + -- Global Interface ------------------------------------------------------- + clk_i : in std_logic; + -- Global clock input + -- Equivalent to XTAL1/2 on TMS9918A. + -- Drive with the target frequency of 10.7 MHz or any integer multiple. + + clk_en_10m7_i : in std_logic; + -- Clock enable + -- A '1' on this input qualifies a valid rising edge on clk_i. A '0' + -- disables the next rising clock edge, effectivley halting the design + -- until the next enabled rising clock edge. + -- Can be used to run the core at lower frequencies than applied on + -- clk_i. + + reset_n_i : in std_logic; + -- Asynchronous low active reset input + -- Sets all sequential elements to a known state. + -- NOTE: SYNC operation not supported. + + -- CPU Interface ---------------------------------------------------------- + csr_n_i : in std_logic; + -- CPU-VDP read strobe, low active + + csw_n_i : in std_logic; + -- CPU-VDP write strobe, low active + + mode_i : in std_logic; + -- CPU interface mode select + + int_n_o : out std_logic; + -- CPU interrupt output, low active + + cd_i : in std_logic_vector(0 to 7); + -- CPU data bus input + -- MSB 0 ... 7 LSB + + cd_o : out std_logic_vector(0 to 7); + -- CPU data bus output + -- MSB 0 ... 7 LSB + + -- VRAM Interface --------------------------------------------------------- + vram_we_o : out std_logic; + -- VRAM write enable + + vram_a_o : out std_logic_vector(0 to 13); + -- VRAM address output + -- MSB 0 ... 13 LSB + + vram_d_o : out std_logic_vector(0 to 7); + -- VRAM data output + -- MSB 0 ... 7 LSB + + vram_d_i : in std_logic_vector(0 to 7); + -- VRAM data input + -- MSB 0 ... 7 LSB + + -- Video Interface -------------------------------------------------------- + col_o : out std_logic_vector(0 to 3); + -- Color code output + -- Encoded pixel color information + + rgb_r_o : out std_logic_vector(0 to 7); + -- Red color information + + rgb_g_o : out std_logic_vector(0 to 7); + -- Green color information + + rgb_b_o : out std_logic_vector(0 to 7); + -- Blue color information + + hsync_n_o : out std_logic; + -- Horizontal synchronization pulse, active low + + vsync_n_o : out std_logic; + -- Vertical synchronization pulse, active low + + comp_sync_n_o : out std_logic + -- Composite synchronization pulse, active low + ); + + +All 8 bit vector ports are defined (0 to 7) which declares bit 0 to be the MSB +and bit 7 to be the LSB. This has been implemented according to TI's data +sheet, thus all register/data format figures apply 1:1 for this design. +Many systems will flip the system data bus bit wise before it is connected to +this PSG. This is simply achieved with the following VHDL construct: + + signal data_s : std_logic_vector(7 downto 0); + + ... + cd_i => data_s, + ... + +d_i and data_s will be assigned from left to right, resulting in the expected +bit assignment: + + cd_i data_s + 0 7 + 1 6 + ... + 6 1 + 7 0 + + +As this design is fully synchronous, care has to be taken when the design +replaces an TMS99x8 in asynchronous mode. No problems are expected when +interfacing the code to other synchronous components. + + +Design Hierarchy +---------------- + + vdp18_core + | + +-- vdp18_clk_gen + | + +-- vdp18_hor_vert + | + +-- vdp18_ctrl + | + +-- vdp18_cpuio + | + +-- vdp18_addr_mux + | + +-- vdp18_pattern + | + +-- vdp18_sprite + | + \-- vdp18_col_mux + +Resulting compolation sequence: + + vdp18_pack-p.vhd + vdp18_comp_pack-p.vhd + vdp18_core.vhd + vdp18_clk_gen.vhd + vdp18_clk_gen-c.vhd + vdp18_hor_vert.vhd + vdp18_hor_vert-c.vhd + vdp18_ctrl.vhd + vdp18_ctrl-c.vhd + vdp18_cpuio.vhd + vdp18_cpuio-c.vhd + vdp18_addr_mux.vhd + vdp18_addr_mux-c.vhd + vdp18_pattern.vhd + vdp18_pattern-c.vhd + vdp18_sprite.vhd + vdp18_sprite-c.vhd + vdp18_col_mux.vhd + vdp18_col_mux-c.vhd + vdp18_core-c.vhd + vdp18_core_com_pack-p.vhd + +Skip the files containing VHDL configurations when analyzing the code for +synthesis. + + +References +---------- + +* TI Data book TMS9918.pdf + http://www.bitsavers.org/pdf/ti/_dataBooks/TMS9918.pdf + +* Sean Young's tech article: + http://bifi.msxnet.org/msxnet/tech/tms9918a.txt + +* Paul Urbanus' discussion of the timing details + http://bifi.msxnet.org/msxnet/tech/tmsposting.txt + +* Richard F. Drushel's article series + "This Week With My Coleco ADAM" + http://junior.apk.net/~drushel/pub/coleco/twwmca/index.html diff --git a/rtl/tms9918/vdp18/vdp18_addr_mux-c.vhd b/rtl/tms9918/vdp18/vdp18_addr_mux-c.vhd new file mode 100644 index 0000000..7668360 --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_addr_mux-c.vhd @@ -0,0 +1,14 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_addr_mux-c.vhd,v 1.5 2006/06/18 10:47:01 arnim Exp $ +-- +------------------------------------------------------------------------------- + +configuration vdp18_addr_mux_rtl_c0 of vdp18_addr_mux is + + for rtl + end for; + +end vdp18_addr_mux_rtl_c0; diff --git a/rtl/tms9918/vdp18/vdp18_addr_mux.vhd b/rtl/tms9918/vdp18/vdp18_addr_mux.vhd new file mode 100644 index 0000000..9ff8c8f --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_addr_mux.vhd @@ -0,0 +1,228 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_addr_mux.vhd,v 1.10 2006/06/18 10:47:01 arnim Exp $ +-- +-- Address Multiplexer / Generator +-- +------------------------------------------------------------------------------- +-- +-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +use work.vdp18_pack.access_t; +use work.vdp18_pack.opmode_t; +use work.vdp18_pack.hv_t; + +entity vdp18_addr_mux is + + port ( + access_type_i : in access_t; + opmode_i : in opmode_t; + num_line_i : in hv_t; + reg_ntb_i : in std_logic_vector(0 to 3); + reg_ctb_i : in std_logic_vector(0 to 7); + reg_pgb_i : in std_logic_vector(0 to 2); + reg_satb_i : in std_logic_vector(0 to 6); + reg_spgb_i : in std_logic_vector(0 to 2); + reg_size1_i : in boolean; + cpu_vram_a_i : in std_logic_vector(0 to 13); + pat_table_i : in std_logic_vector(0 to 9); + pat_name_i : in std_logic_vector(0 to 7); + spr_num_i : in std_logic_vector(0 to 4); + spr_line_i : in std_logic_vector(0 to 3); + spr_name_i : in std_logic_vector(0 to 7); + vram_a_o : out std_logic_vector(0 to 13) + ); + +end vdp18_addr_mux; + + +use work.vdp18_pack.all; + +architecture rtl of vdp18_addr_mux is + +begin + + ----------------------------------------------------------------------------- + -- Process mux + -- + -- Purpose: + -- Generates the VRAM address based on the current access type. + -- + mux: process (access_type_i, opmode_i, + num_line_i, + reg_ntb_i, reg_ctb_i, reg_pgb_i, + reg_satb_i, reg_spgb_i, + reg_size1_i, + cpu_vram_a_i, + pat_table_i, pat_name_i, + spr_num_i, spr_name_i, + spr_line_i) + variable num_line_v : std_logic_vector(num_line_i'range); + begin + -- default assignment + vram_a_o <= (others => '0'); + num_line_v := std_logic_vector(num_line_i); + + case access_type_i is + -- CPU Access ----------------------------------------------------------- + when AC_CPU => + vram_a_o <= cpu_vram_a_i; + + -- Pattern Name Table Access -------------------------------------------- + when AC_PNT => + vram_a_o(0 to 3) <= reg_ntb_i; + vram_a_o(4 to 13) <= pat_table_i; + + -- Pattern Color Table Access ------------------------------------------- + when AC_PCT => + case opmode_i is + when OPMODE_GRAPH1 => + vram_a_o( 0 to 7) <= reg_ctb_i; + vram_a_o( 8) <= '0'; + vram_a_o( 9 to 13) <= pat_name_i(0 to 4); + + when OPMODE_GRAPH2 => + vram_a_o( 0) <= reg_ctb_i(0); + vram_a_o( 1 to 2) <= num_line_v(1 to 2) and + -- remaining bits in CTB mask color + -- lookups + (reg_ctb_i(1) & reg_ctb_i(2)); + vram_a_o( 3 to 10) <= pat_name_i and + -- remaining bits in CTB mask color + -- lookups + (reg_ctb_i(3) & reg_ctb_i(4) & + reg_ctb_i(5) & reg_ctb_i(6) & + reg_ctb_i(7) & "111"); + vram_a_o(11 to 13) <= num_line_v(6 to 8); + + when others => + null; + end case; + + -- Pattern Generator Table Access --------------------------------------- + when AC_PGT => + case opmode_i is + when OPMODE_TEXTM | + OPMODE_GRAPH1 => + vram_a_o( 0 to 2) <= reg_pgb_i; + vram_a_o( 3 to 10) <= pat_name_i; + vram_a_o(11 to 13) <= num_line_v(6 to 8); + + when OPMODE_MULTIC => + vram_a_o( 0 to 2) <= reg_pgb_i; + vram_a_o( 3 to 10) <= pat_name_i; + vram_a_o(11 to 13) <= num_line_v(4 to 6); + + when OPMODE_GRAPH2 => + vram_a_o( 0) <= reg_pgb_i(0); + vram_a_o( 1 to 2) <= num_line_v(1 to 2) and + -- remaining bits in PGB mask pattern + -- lookups + (reg_pgb_i(1) & reg_pgb_i(2)); + vram_a_o( 3 to 10) <= pat_name_i and + -- remaining bits in CTB mask pattern + -- lookups + (reg_ctb_i(3) & reg_ctb_i(4) & + reg_ctb_i(5) & reg_ctb_i(6) & + reg_ctb_i(7) & "111"); + vram_a_o(11 to 13) <= num_line_v(6 to 8); + + when others => + null; + end case; + + -- Sprite Test ---------------------------------------------------------- + when AC_STST | + AC_SATY => + vram_a_o( 0 to 6) <= reg_satb_i; + vram_a_o( 7 to 11) <= spr_num_i; + vram_a_o(12 to 13) <= "00"; + + -- Sprite Attribute Table: X -------------------------------------------- + when AC_SATX => + vram_a_o( 0 to 6) <= reg_satb_i; + vram_a_o( 7 to 11) <= spr_num_i; + vram_a_o(12 to 13) <= "01"; + + -- Sprite Attribute Table: Name ----------------------------------------- + when AC_SATN => + vram_a_o( 0 to 6) <= reg_satb_i; + vram_a_o( 7 to 11) <= spr_num_i; + vram_a_o(12 to 13) <= "10"; + + -- Sprite Attribute Table: Color ---------------------------------------- + when AC_SATC => + vram_a_o( 0 to 6) <= reg_satb_i; + vram_a_o( 7 to 11) <= spr_num_i; + vram_a_o(12 to 13) <= "11"; + + -- Sprite Pattern, Upper Part ------------------------------------------- + when AC_SPTH => + vram_a_o( 0 to 2) <= reg_spgb_i; + if not reg_size1_i then + -- 8x8 sprite + vram_a_o( 3 to 10) <= spr_name_i; + vram_a_o(11 to 13) <= spr_line_i(1 to 3); + else + -- 16x16 sprite + vram_a_o( 3 to 8) <= spr_name_i(0 to 5); + vram_a_o( 9) <= '0'; + vram_a_o(10 to 13) <= spr_line_i; + end if; + + -- Sprite Pattern, Lower Part ------------------------------------------- + when AC_SPTL => + vram_a_o( 0 to 2) <= reg_spgb_i; + vram_a_o( 3 to 8) <= spr_name_i(0 to 5); + vram_a_o( 9) <= '1'; + vram_a_o(10 to 13) <= spr_line_i; + + when others => + null; + + end case; + + end process mux; + -- + ----------------------------------------------------------------------------- + +end rtl; diff --git a/rtl/tms9918/vdp18/vdp18_clk_gen-c.vhd b/rtl/tms9918/vdp18/vdp18_clk_gen-c.vhd new file mode 100644 index 0000000..3549705 --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_clk_gen-c.vhd @@ -0,0 +1,14 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_clk_gen-c.vhd,v 1.5 2006/06/18 10:47:01 arnim Exp $ +-- +------------------------------------------------------------------------------- + +configuration vdp18_clk_gen_rtl_c0 of vdp18_clk_gen is + + for rtl + end for; + +end vdp18_clk_gen_rtl_c0; diff --git a/rtl/tms9918/vdp18/vdp18_clk_gen.vhd b/rtl/tms9918/vdp18/vdp18_clk_gen.vhd new file mode 100644 index 0000000..222e9da --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_clk_gen.vhd @@ -0,0 +1,154 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_clk_gen.vhd,v 1.8 2006/06/18 10:47:01 arnim Exp $ +-- +-- Clock Generator +-- +------------------------------------------------------------------------------- +-- +-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +entity vdp18_clk_gen is + + port ( + clk_i : in std_logic; + clk_en_10m7_i : in std_logic; + reset_i : in boolean; + clk_en_5m37_o : out boolean; + clk_en_3m58_o : out boolean; + clk_en_2m68_o : out boolean + ); + +end vdp18_clk_gen; + + +library ieee; +use ieee.numeric_std.all; + +architecture rtl of vdp18_clk_gen is + + signal cnt_q : unsigned(3 downto 0); + +begin + + ----------------------------------------------------------------------------- + -- Process seq + -- + -- Purpose: + -- Implements the sequential elements. + -- * clock counter + -- + seq: process (clk_i, reset_i) + variable cnt_v : integer range -256 to 255; + begin + if reset_i then + cnt_q <= (others => '0'); + + elsif clk_i'event and clk_i = '1' then + if clk_en_10m7_i = '1' then + if cnt_q = 11 then + -- wrap after counting 12 clocks + cnt_q <= (others => '0'); + else + cnt_q <= cnt_q + 1; + end if; + end if; + + end if; + end process seq; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process clk_en + -- + -- Purpose: + -- Generates the derived clock enable signals. + -- + clk_en: process (clk_en_10m7_i, + cnt_q) + variable cnt_v : integer range -256 to 255; + begin + cnt_v := to_integer(cnt_q); + + -- 5.37 MHz clock enable -------------------------------------------------- + if clk_en_10m7_i = '1' then + case cnt_v is + when 1 | 3 | 5 | 7 | 9 | 11 => + clk_en_5m37_o <= true; + when others => + clk_en_5m37_o <= false; + end case; + else + clk_en_5m37_o <= false; + end if; + + -- 3.58 MHz clock enable -------------------------------------------------- + if clk_en_10m7_i = '1' then + case cnt_v is + when 2 | 5 | 8 | 11 => + clk_en_3m58_o <= true; + when others => + clk_en_3m58_o <= false; + end case; + else + clk_en_3m58_o <= false; + end if; + + -- 2.68 MHz clock enable -------------------------------------------------- + if clk_en_10m7_i = '1' then + case cnt_v is + when 3 | 7 | 11 => + clk_en_2m68_o <= true; + when others => + clk_en_2m68_o <= false; + end case; + else + clk_en_2m68_o <= false; + end if; + + end process clk_en; + -- + ----------------------------------------------------------------------------- + +end rtl; diff --git a/rtl/tms9918/vdp18/vdp18_col_mux-c.vhd b/rtl/tms9918/vdp18/vdp18_col_mux-c.vhd new file mode 100644 index 0000000..21150c2 --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_col_mux-c.vhd @@ -0,0 +1,14 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_col_mux-c.vhd,v 1.3 2006/06/18 10:47:01 arnim Exp $ +-- +------------------------------------------------------------------------------- + +configuration vdp18_col_mux_rtl_c0 of vdp18_col_mux is + + for rtl + end for; + +end vdp18_col_mux_rtl_c0; diff --git a/rtl/tms9918/vdp18/vdp18_col_mux.vhd b/rtl/tms9918/vdp18/vdp18_col_mux.vhd new file mode 100644 index 0000000..afbb453 --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_col_mux.vhd @@ -0,0 +1,184 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_col_mux.vhd,v 1.10 2006/06/18 10:47:01 arnim Exp $ +-- +-- Color Information Multiplexer +-- +------------------------------------------------------------------------------- +-- +-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +entity vdp18_col_mux is + + generic ( + compat_rgb_g : integer := 0 + ); + port ( + clk_i : in std_logic; + clk_en_5m37_i : in boolean; + reset_i : in boolean; + vert_active_i : in boolean; + hor_active_i : in boolean; + blank_i : in boolean; + reg_col0_i : in std_logic_vector(0 to 3); + pat_col_i : in std_logic_vector(0 to 3); + spr0_col_i : in std_logic_vector(0 to 3); + spr1_col_i : in std_logic_vector(0 to 3); + spr2_col_i : in std_logic_vector(0 to 3); + spr3_col_i : in std_logic_vector(0 to 3); + col_o : out std_logic_vector(0 to 3); + rgb_r_o : out std_logic_vector(0 to 7); + rgb_g_o : out std_logic_vector(0 to 7); + rgb_b_o : out std_logic_vector(0 to 7) + ); + +end vdp18_col_mux; + + +library ieee; +use ieee.numeric_std.all; + +use work.vdp18_col_pack.all; + +architecture rtl of vdp18_col_mux is + + signal col_s : std_logic_vector(0 to 3); + +begin + + ----------------------------------------------------------------------------- + -- Process col_mux + -- + -- Purpose: + -- Multiplexes the color information from different sources. + -- + col_mux: process (blank_i, + hor_active_i, vert_active_i, + spr0_col_i, spr1_col_i, + spr2_col_i, spr3_col_i, + pat_col_i, + reg_col0_i) + begin + if not blank_i then + if hor_active_i and vert_active_i then + -- priority decoder + if spr0_col_i /= "0000" then + col_s <= spr0_col_i; + elsif spr1_col_i /= "0000" then + col_s <= spr1_col_i; + elsif spr2_col_i /= "0000" then + col_s <= spr2_col_i; + elsif spr3_col_i /= "0000" then + col_s <= spr3_col_i; + elsif pat_col_i /= "0000" then + col_s <= pat_col_i; + else + col_s <= reg_col0_i; + end if; + + else + -- display border + col_s <= reg_col0_i; + end if; + + else + -- blank color channels during horizontal and vertical + -- trace back + -- required to initialize colors for each new scan line + col_s <= (others => '0'); + end if; + end process col_mux; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process rgb_reg + -- + -- Purpose: + -- Converts the color information to simple RGB and saves these in + -- output registers. + -- + rgb_reg: process (clk_i, reset_i) + variable col_v : natural range 0 to 15; + variable rgb_r_v, + rgb_g_v, + rgb_b_v : rgb_val_t; + variable rgb_table_v : rgb_table_t; + begin + if reset_i then + rgb_r_o <= (others => '0'); + rgb_g_o <= (others => '0'); + rgb_b_o <= (others => '0'); + + elsif clk_i'event and clk_i = '1' then + if clk_en_5m37_i then + -- select requested RGB table + if compat_rgb_g = 1 then + rgb_table_v := compat_rgb_table_c; + else + rgb_table_v := full_rgb_table_c; + end if; + + -- assign color to RGB channels + col_v := to_integer(unsigned(col_s)); + rgb_r_v := rgb_table_v(col_v)(r_c); + rgb_g_v := rgb_table_v(col_v)(g_c); + rgb_b_v := rgb_table_v(col_v)(b_c); + -- + rgb_r_o <= std_logic_vector(to_unsigned(rgb_r_v, 8)); + rgb_g_o <= std_logic_vector(to_unsigned(rgb_g_v, 8)); + rgb_b_o <= std_logic_vector(to_unsigned(rgb_b_v, 8)); + end if; + + end if; + end process rgb_reg; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Output mapping + ----------------------------------------------------------------------------- + col_o <= col_s; + +end rtl; diff --git a/rtl/tms9918/vdp18/vdp18_col_pack-p.vhd b/rtl/tms9918/vdp18/vdp18_col_pack-p.vhd new file mode 100644 index 0000000..701a00d --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_col_pack-p.vhd @@ -0,0 +1,83 @@ +------------------------------------------------------------------------------- +-- +-- $Id: vdp18_col_pack-p.vhd,v 1.3 2006/02/28 22:30:41 arnim Exp $ +-- +-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +-- +-- All rights reserved +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +package vdp18_col_pack is + + constant r_c : natural := 0; + constant g_c : natural := 1; + constant b_c : natural := 2; + + subtype rgb_val_t is natural range 0 to 255; + type rgb_triple_t is array (natural range 0 to 2) of + rgb_val_t; + type rgb_table_t is array (natural range 0 to 15) of + rgb_triple_t; + + ----------------------------------------------------------------------------- + -- Simple RGB Value Array + -- + -- Refer to http://junior.apk.net/~drushel/pub/coleco/twwmca/wk970202.html + -- This is the MF & MdK variant. Note: only the upper three bits are used. + -- + -- + constant compat_rgb_table_c : rgb_table_t := ( + -- R G B + ( 0, 0, 0), -- Transparent + ( 0, 0, 0), -- Black + ( 32, 192, 32), -- Medium Green + ( 96, 224, 96), -- Light Green + ( 32, 32, 224), -- Dark Blue + ( 64, 96, 224), -- Light Blue + (160, 32, 32), -- Dark Red + ( 64, 192, 224), -- Cyan + (224, 32, 32), -- Medium Red + (224, 96, 96), -- Light Red + (192, 192, 32), -- Dark Yellow + (192, 192, 128), -- Light Yellow + ( 32, 128, 32), -- Dark Green + (192, 64, 160), -- Magenta + (160, 160, 160), -- Gray + (224, 224, 224) -- White + ); + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Full RGB Value Array + -- + -- Refer to tms9928a.c of the MAME source distribution. + -- + constant full_rgb_table_c : rgb_table_t := ( + -- R G B + ( 0, 0, 0), -- Transparent + ( 0, 0, 0), -- Black + ( 33, 200, 66), -- Medium Green + ( 94, 220, 120), -- Light Green + ( 84, 85, 237), -- Dark Blue + (125, 118, 252), -- Light Blue + (212, 82, 77), -- Dark Red + ( 66, 235, 245), -- Cyan + (252, 85, 84), -- Medium Red + (255, 121, 120), -- Light Red + (212, 193, 84), -- Dark Yellow + (230, 206, 128), -- Light Yellow + ( 33, 176, 59), -- Dark Green + (201, 91, 186), -- Magenta + (204, 204, 204), -- Gray + (255, 255, 255) -- White + ); + -- + ----------------------------------------------------------------------------- + +end vdp18_col_pack; diff --git a/rtl/tms9918/vdp18/vdp18_comp_pack-p.vhd b/rtl/tms9918/vdp18/vdp18_comp_pack-p.vhd new file mode 100644 index 0000000..e5ff65b --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_comp_pack-p.vhd @@ -0,0 +1,199 @@ +------------------------------------------------------------------------------- +-- +-- $Id: vdp18_comp_pack-p.vhd,v 1.23 2006/02/28 22:30:41 arnim Exp $ +-- +-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +-- +-- All rights reserved +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +use work.vdp18_pack.opmode_t; +use work.vdp18_pack.hv_t; +use work.vdp18_pack.access_t; + +package vdp18_comp_pack is + + component vdp18_clk_gen + port ( + clk_i : in std_logic; + clk_en_10m7_i : in std_logic; + reset_i : in boolean; + clk_en_5m37_o : out boolean; + clk_en_3m58_o : out boolean; + clk_en_2m68_o : out boolean + ); + end component; + + component vdp18_hor_vert + generic ( + is_pal_g : integer := 0 + ); + port ( + clk_i : in std_logic; + clk_en_5m37_i : in boolean; + reset_i : in boolean; + opmode_i : in opmode_t; + num_pix_o : out hv_t; + num_line_o : out hv_t; + vert_inc_o : out boolean; + hsync_n_o : out std_logic; + vsync_n_o : out std_logic; + blank_o : out boolean + ); + end component; + + component vdp18_ctrl + port ( + clk_i : in std_logic; + clk_en_5m37_i : in boolean; + reset_i : in boolean; + opmode_i : in opmode_t; + num_pix_i : in hv_t; + num_line_i : in hv_t; + vert_inc_i : in boolean; + reg_blank_i : in boolean; + reg_size1_i : in boolean; + stop_sprite_i : in boolean; + clk_en_acc_o : out boolean; + access_type_o : out access_t; + vert_active_o : out boolean; + hor_active_o : out boolean; + irq_o : out boolean + ); + end component; + + component vdp18_cpuio + port ( + clk_i : in std_logic; + clk_en_10m7_i : in boolean; + clk_en_acc_i : in boolean; + reset_i : in boolean; + rd_i : in boolean; + wr_i : in boolean; + mode_i : in std_logic; + cd_i : in std_logic_vector(0 to 7); + cd_o : out std_logic_vector(0 to 7); + cd_oe_o : out std_logic; + access_type_i : in access_t; + opmode_o : out opmode_t; + vram_we_o : out std_logic; + vram_a_o : out std_logic_vector(0 to 13); + vram_d_o : out std_logic_vector(0 to 7); + vram_d_i : in std_logic_vector(0 to 7); + spr_coll_i : in boolean; + spr_5th_i : in boolean; + spr_5th_num_i : in std_logic_vector(0 to 4); + reg_ev_o : out boolean; + reg_16k_o : out boolean; + reg_blank_o : out boolean; + reg_size1_o : out boolean; + reg_mag1_o : out boolean; + reg_ntb_o : out std_logic_vector(0 to 3); + reg_ctb_o : out std_logic_vector(0 to 7); + reg_pgb_o : out std_logic_vector(0 to 2); + reg_satb_o : out std_logic_vector(0 to 6); + reg_spgb_o : out std_logic_vector(0 to 2); + reg_col1_o : out std_logic_vector(0 to 3); + reg_col0_o : out std_logic_vector(0 to 3); + irq_i : in boolean; + int_n_o : out std_logic + ); + end component; + + component vdp18_addr_mux + port ( + access_type_i : in access_t; + opmode_i : in opmode_t; + num_line_i : in hv_t; + reg_ntb_i : in std_logic_vector(0 to 3); + reg_ctb_i : in std_logic_vector(0 to 7); + reg_pgb_i : in std_logic_vector(0 to 2); + reg_satb_i : in std_logic_vector(0 to 6); + reg_spgb_i : in std_logic_vector(0 to 2); + reg_size1_i : in boolean; + cpu_vram_a_i : in std_logic_vector(0 to 13); + pat_table_i : in std_logic_vector(0 to 9); + pat_name_i : in std_logic_vector(0 to 7); + spr_num_i : in std_logic_vector(0 to 4); + spr_line_i : in std_logic_vector(0 to 3); + spr_name_i : in std_logic_vector(0 to 7); + vram_a_o : out std_logic_vector(0 to 13) + ); + end component; + + component vdp18_pattern + port ( + clk_i : in std_logic; + clk_en_5m37_i : in boolean; + clk_en_acc_i : in boolean; + reset_i : in boolean; + opmode_i : in opmode_t; + access_type_i : in access_t; + num_line_i : in hv_t; + vram_d_i : in std_logic_vector(0 to 7); + vert_inc_i : in boolean; + vsync_n_i : in std_logic; + reg_col1_i : in std_logic_vector(0 to 3); + reg_col0_i : in std_logic_vector(0 to 3); + pat_table_o : out std_logic_vector(0 to 9); + pat_name_o : out std_logic_vector(0 to 7); + pat_col_o : out std_logic_vector(0 to 3) + ); + end component; + + component vdp18_sprite + port ( + clk_i : in std_logic; + clk_en_5m37_i : in boolean; + clk_en_acc_i : in boolean; + reset_i : in boolean; + access_type_i : in access_t; + num_pix_i : in hv_t; + num_line_i : in hv_t; + vram_d_i : in std_logic_vector(0 to 7); + vert_inc_i : in boolean; + reg_size1_i : in boolean; + reg_mag1_i : in boolean; + spr_5th_o : out boolean; + spr_5th_num_o : out std_logic_vector(0 to 4); + stop_sprite_o : out boolean; + spr_coll_o : out boolean; + spr_num_o : out std_logic_vector(0 to 4); + spr_line_o : out std_logic_vector(0 to 3); + spr_name_o : out std_logic_vector(0 to 7); + spr0_col_o : out std_logic_vector(0 to 3); + spr1_col_o : out std_logic_vector(0 to 3); + spr2_col_o : out std_logic_vector(0 to 3); + spr3_col_o : out std_logic_vector(0 to 3) + ); + end component; + + component vdp18_col_mux + generic ( + compat_rgb_g : integer := 0 + ); + port ( + clk_i : in std_logic; + clk_en_5m37_i : in boolean; + reset_i : in boolean; + vert_active_i : in boolean; + hor_active_i : in boolean; + blank_i : in boolean; + reg_col0_i : in std_logic_vector(0 to 3); + pat_col_i : in std_logic_vector(0 to 3); + spr0_col_i : in std_logic_vector(0 to 3); + spr1_col_i : in std_logic_vector(0 to 3); + spr2_col_i : in std_logic_vector(0 to 3); + spr3_col_i : in std_logic_vector(0 to 3); + col_o : out std_logic_vector(0 to 3); + rgb_r_o : out std_logic_vector(0 to 7); + rgb_g_o : out std_logic_vector(0 to 7); + rgb_b_o : out std_logic_vector(0 to 7) + ); + end component; + +end vdp18_comp_pack; diff --git a/rtl/tms9918/vdp18/vdp18_core-c.vhd b/rtl/tms9918/vdp18/vdp18_core-c.vhd new file mode 100644 index 0000000..a43ba8f --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_core-c.vhd @@ -0,0 +1,47 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_core-c.vhd,v 1.10 2006/06/18 10:47:01 arnim Exp $ +-- +------------------------------------------------------------------------------- + +configuration vdp18_core_struct_c0 of vdp18_core is + + for struct + + for clk_gen_b: vdp18_clk_gen + use configuration work.vdp18_clk_gen_rtl_c0; + end for; + + for hor_vert_b: vdp18_hor_vert + use configuration work.vdp18_hor_vert_rtl_c0; + end for; + + for ctrl_b: vdp18_ctrl + use configuration work.vdp18_ctrl_rtl_c0; + end for; + + for cpu_io_b: vdp18_cpuio + use configuration work.vdp18_cpuio_rtl_c0; + end for; + + for addr_mux_b: vdp18_addr_mux + use configuration work.vdp18_addr_mux_rtl_c0; + end for; + + for pattern_b: vdp18_pattern + use configuration work.vdp18_pattern_rtl_c0; + end for; + + for sprite_b: vdp18_sprite + use configuration work.vdp18_sprite_rtl_c0; + end for; + + for col_mux_b: vdp18_col_mux + use configuration work.vdp18_col_mux_rtl_c0; + end for; + + end for; + +end vdp18_core_struct_c0; diff --git a/rtl/tms9918/vdp18/vdp18_core.vhd b/rtl/tms9918/vdp18/vdp18_core.vhd new file mode 100644 index 0000000..76e384d --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_core.vhd @@ -0,0 +1,397 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_core.vhd,v 1.28 2006/06/18 10:47:01 arnim Exp $ +-- +-- Core Toplevel +-- +-- Notes: +-- This core implements a simple VRAM interface which is suitable for a +-- synchronous SRAM component. There is currently no support of the +-- original DRAM interface. +-- +-- Please be aware that the colors might me slightly different from the +-- original TMS9918. It is assumed that the simplified conversion to RGB +-- encoding is equivalent to the compatability mode of the V9938. +-- Implementing a 100% correct color encoding for RGB would require +-- significantly more logic and 8-bit wide RGB DACs. +-- +-- References: +-- +-- * TI Data book TMS9918.pdf +-- http://www.bitsavers.org/pdf/ti/_dataBooks/TMS9918.pdf +-- +-- * Sean Young's tech article: +-- http://bifi.msxnet.org/msxnet/tech/tms9918a.txt +-- +-- * Paul Urbanus' discussion of the timing details +-- http://bifi.msxnet.org/msxnet/tech/tmsposting.txt +-- +-- * Richard F. Drushel's article series +-- "This Week With My Coleco ADAM" +-- http://junior.apk.net/~drushel/pub/coleco/twwmca/index.html +-- +------------------------------------------------------------------------------- +-- +-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +entity vdp18_core is + + generic ( + is_pal_g : integer := 0; + compat_rgb_g : integer := 0 + ); + port ( + -- Global Interface ------------------------------------------------------- + clk_i : in std_logic; + clk_en_10m7_i : in std_logic; + reset_n_i : in std_logic; + -- CPU Interface ---------------------------------------------------------- + csr_n_i : in std_logic; + csw_n_i : in std_logic; + mode_i : in std_logic; + int_n_o : out std_logic; + cd_i : in std_logic_vector(0 to 7); + cd_o : out std_logic_vector(0 to 7); + -- VRAM Interface --------------------------------------------------------- + vram_we_o : out std_logic; + vram_a_o : out std_logic_vector(0 to 13); + vram_d_o : out std_logic_vector(0 to 7); + vram_d_i : in std_logic_vector(0 to 7); + -- Video Interface -------------------------------------------------------- + col_o : out std_logic_vector(0 to 3); + rgb_r_o : out std_logic_vector(0 to 7); + rgb_g_o : out std_logic_vector(0 to 7); + rgb_b_o : out std_logic_vector(0 to 7); + hsync_n_o : out std_logic; + vsync_n_o : out std_logic; + comp_sync_n_o : out std_logic + ); + +end vdp18_core; + + +use work.vdp18_comp_pack.all; +use work.vdp18_pack.opmode_t; +use work.vdp18_pack.hv_t; +use work.vdp18_pack.access_t; +use work.vdp18_pack.to_boolean_f; + +architecture struct of vdp18_core is + + signal reset_s : boolean; + + signal clk_en_10m7_s, + clk_en_5m37_s, + clk_en_3m58_s, + clk_en_acc_s : boolean; + + signal opmode_s : opmode_t; + + signal access_type_s : access_t; + + signal num_pix_s, + num_line_s : hv_t; + signal hsync_n_s, + vsync_n_s : std_logic; + signal blank_s : boolean; + + signal vert_inc_s : boolean; + + signal reg_blank_s, + reg_size1_s, + reg_mag1_s : boolean; + + signal spr_5th_s : boolean; + signal spr_5th_num_s : std_logic_vector(0 to 4); + + signal stop_sprite_s : boolean; + signal vert_active_s, + hor_active_s : boolean; + + signal rd_s, + wr_s : boolean; + + signal reg_ntb_s : std_logic_vector(0 to 3); + signal reg_ctb_s : std_logic_vector(0 to 7); + signal reg_pgb_s : std_logic_vector(0 to 2); + signal reg_satb_s : std_logic_vector(0 to 6); + signal reg_spgb_s : std_logic_vector(0 to 2); + signal reg_col1_s, + reg_col0_s : std_logic_vector(0 to 3); + signal cpu_vram_a_s : std_logic_vector(0 to 13); + + signal pat_table_s : std_logic_vector(0 to 9); + signal pat_name_s : std_logic_vector(0 to 7); + signal pat_col_s : std_logic_vector(0 to 3); + + signal spr_num_s : std_logic_vector(0 to 4); + signal spr_line_s : std_logic_vector(0 to 3); + signal spr_name_s : std_logic_vector(0 to 7); + signal spr0_col_s, + spr1_col_s, + spr2_col_s, + spr3_col_s : std_logic_vector(0 to 3); + signal spr_coll_s : boolean; + + signal irq_s : boolean; + + signal false_s : boolean; + +begin + + -- temporary defaults + false_s <= false; + + clk_en_10m7_s <= to_boolean_f(clk_en_10m7_i); + rd_s <= not to_boolean_f(csr_n_i); + wr_s <= not to_boolean_f(csw_n_i); + + reset_s <= reset_n_i = '0'; + + + ----------------------------------------------------------------------------- + -- Clock Generator + ----------------------------------------------------------------------------- + clk_gen_b : vdp18_clk_gen + port map ( + clk_i => clk_i, + clk_en_10m7_i => clk_en_10m7_i, + reset_i => reset_s, + clk_en_5m37_o => clk_en_5m37_s, + clk_en_3m58_o => clk_en_3m58_s, + clk_en_2m68_o => open + ); + + + ----------------------------------------------------------------------------- + -- Horizontal and Vertical Timing Generator + ----------------------------------------------------------------------------- + hor_vert_b : vdp18_hor_vert + generic map ( + is_pal_g => is_pal_g + ) + port map ( + clk_i => clk_i, + clk_en_5m37_i => clk_en_5m37_s, + reset_i => reset_s, + opmode_i => opmode_s, + num_pix_o => num_pix_s, + num_line_o => num_line_s, + vert_inc_o => vert_inc_s, + hsync_n_o => hsync_n_s, + vsync_n_o => vsync_n_s, + blank_o => blank_s + ); + + hsync_n_o <= hsync_n_s; + vsync_n_o <= vsync_n_s; + comp_sync_n_o <= not (hsync_n_s xor vsync_n_s); + + + ----------------------------------------------------------------------------- + -- Control Module + ----------------------------------------------------------------------------- + ctrl_b : vdp18_ctrl + port map ( + clk_i => clk_i, + clk_en_5m37_i => clk_en_5m37_s, + reset_i => reset_s, + opmode_i => opmode_s, + num_pix_i => num_pix_s, + num_line_i => num_line_s, + vert_inc_i => vert_inc_s, + reg_blank_i => reg_blank_s, + reg_size1_i => reg_size1_s, + stop_sprite_i => stop_sprite_s, + clk_en_acc_o => clk_en_acc_s, + access_type_o => access_type_s, + vert_active_o => vert_active_s, + hor_active_o => hor_active_s, + irq_o => irq_s + ); + + + ----------------------------------------------------------------------------- + -- CPU I/O Module + ----------------------------------------------------------------------------- + cpu_io_b : vdp18_cpuio + port map ( + clk_i => clk_i, + clk_en_10m7_i => clk_en_10m7_s, + clk_en_acc_i => clk_en_acc_s, + reset_i => reset_s, + rd_i => rd_s, + wr_i => wr_s, + mode_i => mode_i, + cd_i => cd_i, + cd_o => cd_o, + cd_oe_o => open, + access_type_i => access_type_s, + opmode_o => opmode_s, + vram_we_o => vram_we_o, + vram_a_o => cpu_vram_a_s, + vram_d_o => vram_d_o, + vram_d_i => vram_d_i, + spr_coll_i => spr_coll_s, + spr_5th_i => spr_5th_s, + spr_5th_num_i => spr_5th_num_s, + reg_ev_o => open, + reg_16k_o => open, + reg_blank_o => reg_blank_s, + reg_size1_o => reg_size1_s, + reg_mag1_o => reg_mag1_s, + reg_ntb_o => reg_ntb_s, + reg_ctb_o => reg_ctb_s, + reg_pgb_o => reg_pgb_s, + reg_satb_o => reg_satb_s, + reg_spgb_o => reg_spgb_s, + reg_col1_o => reg_col1_s, + reg_col0_o => reg_col0_s, + irq_i => irq_s, + int_n_o => int_n_o + ); + + + ----------------------------------------------------------------------------- + -- VRAM Address Multiplexer + ----------------------------------------------------------------------------- + addr_mux_b : vdp18_addr_mux + port map ( + access_type_i => access_type_s, + opmode_i => opmode_s, + num_line_i => num_line_s, + reg_ntb_i => reg_ntb_s, + reg_ctb_i => reg_ctb_s, + reg_pgb_i => reg_pgb_s, + reg_satb_i => reg_satb_s, + reg_spgb_i => reg_spgb_s, + reg_size1_i => reg_size1_s, + cpu_vram_a_i => cpu_vram_a_s, + pat_table_i => pat_table_s, + pat_name_i => pat_name_s, + spr_num_i => spr_num_s, + spr_line_i => spr_line_s, + spr_name_i => spr_name_s, + vram_a_o => vram_a_o + ); + + + ----------------------------------------------------------------------------- + -- Pattern Generator + ----------------------------------------------------------------------------- + pattern_b : vdp18_pattern + port map ( + clk_i => clk_i, + clk_en_5m37_i => clk_en_5m37_s, + clk_en_acc_i => clk_en_acc_s, + reset_i => reset_s, + opmode_i => opmode_s, + access_type_i => access_type_s, + num_line_i => num_line_s, + vram_d_i => vram_d_i, + vert_inc_i => vert_inc_s, + vsync_n_i => vsync_n_s, + reg_col1_i => reg_col1_s, + reg_col0_i => reg_col0_s, + pat_table_o => pat_table_s, + pat_name_o => pat_name_s, + pat_col_o => pat_col_s + ); + + + ----------------------------------------------------------------------------- + -- Sprite Generator + ----------------------------------------------------------------------------- + sprite_b : vdp18_sprite + port map ( + clk_i => clk_i, + clk_en_5m37_i => clk_en_5m37_s, + clk_en_acc_i => clk_en_acc_s, + reset_i => reset_s, + access_type_i => access_type_s, + num_pix_i => num_pix_s, + num_line_i => num_line_s, + vram_d_i => vram_d_i, + vert_inc_i => vert_inc_s, + reg_size1_i => reg_size1_s, + reg_mag1_i => reg_mag1_s, + spr_5th_o => spr_5th_s, + spr_5th_num_o => spr_5th_num_s, + stop_sprite_o => stop_sprite_s, + spr_coll_o => spr_coll_s, + spr_num_o => spr_num_s, + spr_line_o => spr_line_s, + spr_name_o => spr_name_s, + spr0_col_o => spr0_col_s, + spr1_col_o => spr1_col_s, + spr2_col_o => spr2_col_s, + spr3_col_o => spr3_col_s + ); + + + ----------------------------------------------------------------------------- + -- Color Multiplexer + ----------------------------------------------------------------------------- + col_mux_b : vdp18_col_mux + generic map ( + compat_rgb_g => compat_rgb_g + ) + port map ( + clk_i => clk_i, + clk_en_5m37_i => clk_en_5m37_s, + reset_i => reset_s, + vert_active_i => vert_active_s, + hor_active_i => hor_active_s, + blank_i => blank_s, + reg_col0_i => reg_col0_s, + pat_col_i => pat_col_s, + spr0_col_i => spr0_col_s, + spr1_col_i => spr1_col_s, + spr2_col_i => spr2_col_s, + spr3_col_i => spr3_col_s, + col_o => col_o, + rgb_r_o => rgb_r_o, + rgb_g_o => rgb_g_o, + rgb_b_o => rgb_b_o + ); + +end struct; diff --git a/rtl/tms9918/vdp18/vdp18_core_comp_pack-p.vhd b/rtl/tms9918/vdp18/vdp18_core_comp_pack-p.vhd new file mode 100644 index 0000000..ab4662f --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_core_comp_pack-p.vhd @@ -0,0 +1,45 @@ +------------------------------------------------------------------------------- +-- +-- $Id: vdp18_core_comp_pack-p.vhd,v 1.10 2006/02/28 22:30:41 arnim Exp $ +-- +-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +-- +-- All rights reserved +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +package vdp18_core_comp_pack is + + component vdp18_core + generic ( + is_pal_g : integer := 0; + compat_rgb_g : integer := 0 + ); + port ( + clk_i : in std_logic; + clk_en_10m7_i : in std_logic; + reset_n_i : in std_logic; + csr_n_i : in std_logic; + csw_n_i : in std_logic; + mode_i : in std_logic; + int_n_o : out std_logic; + cd_i : in std_logic_vector(0 to 7); + cd_o : out std_logic_vector(0 to 7); + vram_we_o : out std_logic; + vram_a_o : out std_logic_vector(0 to 13); + vram_d_o : out std_logic_vector(0 to 7); + vram_d_i : in std_logic_vector(0 to 7); + col_o : out std_logic_vector(0 to 3); + rgb_r_o : out std_logic_vector(0 to 7); + rgb_g_o : out std_logic_vector(0 to 7); + rgb_b_o : out std_logic_vector(0 to 7); + hsync_n_o : out std_logic; + vsync_n_o : out std_logic; + comp_sync_n_o : out std_logic + ); + end component; + +end vdp18_core_comp_pack; diff --git a/rtl/tms9918/vdp18/vdp18_cpuio-c.vhd b/rtl/tms9918/vdp18/vdp18_cpuio-c.vhd new file mode 100644 index 0000000..e64cf8a --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_cpuio-c.vhd @@ -0,0 +1,14 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_cpuio-c.vhd,v 1.5 2006/06/18 10:47:01 arnim Exp $ +-- +------------------------------------------------------------------------------- + +configuration vdp18_cpuio_rtl_c0 of vdp18_cpuio is + + for rtl + end for; + +end vdp18_cpuio_rtl_c0; diff --git a/rtl/tms9918/vdp18/vdp18_cpuio.vhd b/rtl/tms9918/vdp18/vdp18_cpuio.vhd new file mode 100644 index 0000000..439c5f2 --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_cpuio.vhd @@ -0,0 +1,570 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_cpuio.vhd,v 1.17 2006/06/18 10:47:01 arnim Exp $ +-- +-- CPU I/O Interface Module +-- +------------------------------------------------------------------------------- +-- +-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +use work.vdp18_pack.access_t; +use work.vdp18_pack.opmode_t; + +entity vdp18_cpuio is + + port ( + clk_i : in std_logic; + clk_en_10m7_i : in boolean; + clk_en_acc_i : in boolean; + reset_i : in boolean; + rd_i : in boolean; + wr_i : in boolean; + mode_i : in std_logic; + cd_i : in std_logic_vector(0 to 7); + cd_o : out std_logic_vector(0 to 7); + cd_oe_o : out std_logic; + access_type_i : in access_t; + opmode_o : out opmode_t; + vram_we_o : out std_logic; + vram_a_o : out std_logic_vector(0 to 13); + vram_d_o : out std_logic_vector(0 to 7); + vram_d_i : in std_logic_vector(0 to 7); + spr_coll_i : in boolean; + spr_5th_i : in boolean; + spr_5th_num_i : in std_logic_vector(0 to 4); + reg_ev_o : out boolean; + reg_16k_o : out boolean; + reg_blank_o : out boolean; + reg_size1_o : out boolean; + reg_mag1_o : out boolean; + reg_ntb_o : out std_logic_vector(0 to 3); + reg_ctb_o : out std_logic_vector(0 to 7); + reg_pgb_o : out std_logic_vector(0 to 2); + reg_satb_o : out std_logic_vector(0 to 6); + reg_spgb_o : out std_logic_vector(0 to 2); + reg_col1_o : out std_logic_vector(0 to 3); + reg_col0_o : out std_logic_vector(0 to 3); + irq_i : in boolean; + int_n_o : out std_logic + ); + +end vdp18_cpuio; + + +library ieee; +use ieee.numeric_std.all; + +use work.vdp18_pack.all; + +architecture rtl of vdp18_cpuio is + + type state_t is (ST_IDLE, + ST_RD_MODE0, ST_WR_MODE0, + ST_RD_MODE1, + ST_WR_MODE1_1ST, ST_WR_MODE1_1ST_IDLE, + ST_WR_MODE1_2ND_VREAD, ST_WR_MODE1_2ND_VWRITE, + ST_WR_MODE1_2ND_RWRITE); + signal state_s, + state_q : state_t; + + signal buffer_q : std_logic_vector(0 to 7); + + signal addr_q : unsigned(0 to 13); + + signal incr_addr_s, + load_addr_s : boolean; + + signal wrbuf_cpu_s : boolean; + signal sched_rdvram_s, + rdvram_sched_q, + rdvram_q : boolean; + signal abort_wrvram_s, + sched_wrvram_s, + wrvram_sched_q, + wrvram_q : boolean; + + signal write_tmp_s : boolean; + signal tmp_q : std_logic_vector(0 to 7); + signal write_reg_s : boolean; + + -- control register bits ---------------------------------------------------- + type ctrl_reg_t is array (natural range 7 downto 0) of + std_logic_vector(0 to 7); + signal ctrl_reg_q : ctrl_reg_t; + + -- status register ---------------------------------------------------------- + signal status_reg_s : std_logic_vector(0 to 7); + signal destr_rd_status_s : boolean; + signal sprite_5th_q : boolean; + signal sprite_5th_num_q : std_logic_vector(0 to 4); + signal sprite_coll_q : boolean; + signal int_n_q : std_logic; + + + type read_mux_t is (RDMUX_STATUS, RDMUX_READAHEAD); + signal read_mux_s : read_mux_t; + +begin + + ----------------------------------------------------------------------------- + -- Process seq + -- + -- Purpose: + -- Implements the sequential elements. + -- + seq: process (clk_i, reset_i) + variable incr_addr_v : boolean; + begin + if reset_i then + state_q <= ST_IDLE; + buffer_q <= (others => '0'); + addr_q <= (others => '0'); + rdvram_sched_q <= false; + rdvram_q <= false; + wrvram_sched_q <= false; + wrvram_q <= false; + + elsif clk_i'event and clk_i = '1' then + -- default assignments + incr_addr_v := incr_addr_s; + + if clk_en_10m7_i then + -- update state vector ------------------------------------------------ + state_q <= state_s; + + -- buffer and flag control -------------------------------------------- + if wrbuf_cpu_s then + -- write read-ahead buffer from CPU bus + buffer_q <= cd_i; + -- immediately stop read-ahead + rdvram_sched_q <= false; + rdvram_q <= false; + elsif clk_en_acc_i and + rdvram_q and + access_type_i = AC_CPU then + -- write read-ahead buffer from VRAM during CPU access slot + buffer_q <= vram_d_i; + -- stop scanning for CPU data + rdvram_q <= false; + -- increment read-ahead address + incr_addr_v := true; + end if; + + if sched_rdvram_s then + -- immediately stop write-back + wrvram_sched_q <= false; + wrvram_q <= false; + -- schedule read-ahead + rdvram_sched_q <= true; + end if; + + if sched_wrvram_s then + -- schedule write-back + wrvram_sched_q <= true; + end if; + + if abort_wrvram_s then + -- stop scanning for write-back + wrvram_q <= false; + end if; + + if rdvram_sched_q and clk_en_acc_i then + -- align scheduled read-ahead with access slot phase + rdvram_sched_q <= false; + rdvram_q <= true; + end if; + if wrvram_sched_q and clk_en_acc_i then + -- align scheduled write-back with access slot phase + wrvram_sched_q <= false; + wrvram_q <= true; + end if; + + -- manage address ----------------------------------------------------- + if load_addr_s then + addr_q(6 to 13) <= unsigned(tmp_q); + addr_q(0 to 5) <= unsigned(cd_i(2 to 7)); + elsif incr_addr_v then + addr_q <= addr_q + 1; + end if; + + end if; + end if; + end process seq; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process wback_ctrl + -- + -- Purpose: + -- Write-back control. + -- + wback_ctrl: process (clk_en_acc_i, + access_type_i, + wrvram_q) + begin + -- default assignments + abort_wrvram_s <= false; + incr_addr_s <= false; + vram_we_o <= '0'; + + if wrvram_q then + if access_type_i = AC_CPU then + -- signal write access to VRAM + vram_we_o <= '1'; + + if clk_en_acc_i then + -- clear write-back flag and increment address + abort_wrvram_s <= true; + incr_addr_s <= true; + end if; + end if; + end if; + end process wback_ctrl; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process reg_if + -- + -- Purpose: + -- Implements the register interface. + -- + reg_if: process (clk_i, reset_i) + variable reg_addr_v : unsigned(0 to 2); + begin + if reset_i then + tmp_q <= (others => '0'); + ctrl_reg_q <= (others => (others => '0')); + sprite_coll_q <= false; + sprite_5th_q <= false; + sprite_5th_num_q <= (others => '0'); + int_n_q <= '1'; + + elsif clk_i'event and clk_i = '1' then + if clk_en_10m7_i then + -- Temporary register ------------------------------------------------- + if write_tmp_s then + tmp_q <= cd_i; + end if; + + -- Registers 0 to 7 --------------------------------------------------- + if write_reg_s then + reg_addr_v := unsigned(cd_i(5 to 7)); + ctrl_reg_q(to_integer(reg_addr_v)) <= tmp_q; + end if; + + end if; + + -- Fifth sprite handling ------------------------------------------------ + if spr_5th_i and not sprite_5th_q then + sprite_5th_q <= true; + sprite_5th_num_q <= spr_5th_num_i; + elsif destr_rd_status_s then + sprite_5th_q <= false; + end if; + + -- Sprite collision flag ------------------------------------------------ + if spr_coll_i then + sprite_coll_q <= true; + elsif destr_rd_status_s then + sprite_coll_q <= false; + end if; + + -- Interrupt ------------------------------------------------------------ + if irq_i then + int_n_q <= '0'; + elsif destr_rd_status_s then + int_n_q <= '1'; + end if; + end if; + end process reg_if; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process access_ctrl + -- + -- Purpose: + -- Implements the combinational logic for the CPU I/F FSM. + -- Decodes the CPU I/F FSM state and generates the control signals for the + -- register and VRAM logic. + -- + access_ctrl: process (state_q, + rd_i, wr_i, + mode_i, + cd_i) + type transfer_mode_t is (TM_NONE, + TM_RD_MODE0, TM_WR_MODE0, + TM_RD_MODE1, TM_WR_MODE1); + variable transfer_mode_v : transfer_mode_t; + begin + -- default assignments + state_s <= state_q; + sched_rdvram_s <= false; + sched_wrvram_s <= false; + wrbuf_cpu_s <= false; + write_tmp_s <= false; + write_reg_s <= false; + load_addr_s <= false; + read_mux_s <= RDMUX_STATUS; + destr_rd_status_s <= false; + + -- determine transfer mode + transfer_mode_v := TM_NONE; + if mode_i = '0' then + if rd_i then + transfer_mode_v := TM_RD_MODE0; + end if; + if wr_i then + transfer_mode_v := TM_WR_MODE0; + end if; + else + if rd_i then + transfer_mode_v := TM_RD_MODE1; + end if; + if wr_i then + transfer_mode_v := TM_WR_MODE1; + end if; + end if; + + -- FSM state transitions + case state_q is + -- ST_IDLE: waiting for CPU access -------------------------------------- + when ST_IDLE => + case transfer_mode_v is + when TM_RD_MODE0 => + state_s <= ST_RD_MODE0; + when TM_WR_MODE0 => + state_s <= ST_WR_MODE0; + when TM_RD_MODE1 => + state_s <= ST_RD_MODE1; + when TM_WR_MODE1 => + state_s <= ST_WR_MODE1_1ST; + when others => + null; + end case; + + -- ST_RD_MODE0: read from VRAM ------------------------------------------ + when ST_RD_MODE0 => + -- set read mux + read_mux_s <= RDMUX_READAHEAD; + + if transfer_mode_v = TM_NONE then + -- CPU finished read access: + -- schedule new read-ahead and return to idle + state_s <= ST_IDLE; + sched_rdvram_s <= true; + end if; + + -- ST_WR_MODE0: write to VRAM ------------------------------------------- + when ST_WR_MODE0 => + -- write data from CPU to write-back/read-ahead buffer + wrbuf_cpu_s <= true; + + if transfer_mode_v = TM_NONE then + -- CPU finished write access: + -- schedule new write-back and return to idle + state_s <= ST_IDLE; + sched_wrvram_s <= true; + end if; + + -- ST_RD_MODE1: read from status register ------------------------------- + when ST_RD_MODE1 => + -- set read mux + read_mux_s <= RDMUX_STATUS; + + if transfer_mode_v = TM_NONE then + -- CPU finished read access: + -- destructive read of status register and return to IDLE + destr_rd_status_s <= true; + state_s <= ST_IDLE; + end if; + + -- ST_WR_MODE1_1ST: save first byte ------------------------------------- + when ST_WR_MODE1_1ST => + -- update temp register + write_tmp_s <= true; + + if transfer_mode_v = TM_NONE then + -- CPU finished write access: + -- become idle but remember that the first byte of a paired write + -- has been written + state_s <= ST_WR_MODE1_1ST_IDLE; + end if; + + -- ST_WR_MODE1_1ST_IDLE: wait for next access --------------------------- + when ST_WR_MODE1_1ST_IDLE => + -- determine type of next access + case transfer_mode_v is + when TM_RD_MODE0 => + state_s <= ST_RD_MODE0; + when TM_WR_MODE0 => + state_s <= ST_WR_MODE0; + when TM_RD_MODE1 => + state_s <= ST_RD_MODE1; + when TM_WR_MODE1 => + case cd_i(0 to 1) is + when "00" => + state_s <= ST_WR_MODE1_2ND_VREAD; + when "01" => + state_s <= ST_WR_MODE1_2ND_VWRITE; + when "10" | "11" => + state_s <= ST_WR_MODE1_2ND_RWRITE; + when others => + null; + end case; + when others => + null; + end case; + + -- ST_WR_MODE1_2ND_VREAD: write second byte of address, then read ahead - + when ST_WR_MODE1_2ND_VREAD => + load_addr_s <= true; + + if transfer_mode_v = TM_NONE then + -- CPU finished write access: + -- schedule new read-ahead and return to idle + sched_rdvram_s <= true; + state_s <= ST_IDLE; + end if; + + -- ST_WR_MODE1_2ND_VWRITE: write second byte of address + when ST_WR_MODE1_2ND_VWRITE => + load_addr_s <= true; + + if transfer_mode_v = TM_NONE then + -- CPU finished write access: + -- return to idle + state_s <= ST_IDLE; + end if; + + -- ST_WR_MODE1_2ND_RWRITE: write to register ---------------------------- + when ST_WR_MODE1_2ND_RWRITE => + write_reg_s <= true; + + if transfer_mode_v = TM_NONE then + -- CPU finished write access: + -- return to idle + state_s <= ST_IDLE; + end if; + + when others => + null; + + end case; + + end process access_ctrl; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process mode_decode + -- + -- Purpose: + -- Decodes the display mode from the M1, M2, M3 bits. + -- + mode_decode: process (ctrl_reg_q) + variable mode_v : std_logic_vector(0 to 2); + begin + mode_v := ctrl_reg_q(1)(3) & -- M1 + ctrl_reg_q(1)(4) & -- M2 + ctrl_reg_q(0)(6); -- M3 + + case mode_v is + when "000" => + opmode_o <= OPMODE_GRAPH1; + when "001" => + opmode_o <= OPMODE_GRAPH2; + when "010" => + opmode_o <= OPMODE_MULTIC; + when "100" => + opmode_o <= OPMODE_TEXTM; + when others => + opmode_o <= OPMODE_TEXTM; + end case; + end process mode_decode; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Build status register + ----------------------------------------------------------------------------- + status_reg_s <= not int_n_q & + to_std_logic_f(sprite_5th_q) & + to_std_logic_f(sprite_coll_q) & + sprite_5th_num_q; + + ----------------------------------------------------------------------------- + -- Output mapping + ----------------------------------------------------------------------------- + vram_a_o <= std_logic_vector(addr_q); + vram_d_o <= buffer_q; + + cd_o <= buffer_q + when read_mux_s = RDMUX_READAHEAD else + status_reg_s; + cd_oe_o <= '1' + when rd_i else + '0'; + + reg_ev_o <= to_boolean_f(ctrl_reg_q(0)(7)); + reg_16k_o <= to_boolean_f(ctrl_reg_q(1)(0)); + reg_blank_o <= not to_boolean_f(ctrl_reg_q(1)(1)); + reg_size1_o <= to_boolean_f(ctrl_reg_q(1)(6)); + reg_mag1_o <= to_boolean_f(ctrl_reg_q(1)(7)); + reg_ntb_o <= ctrl_reg_q(2)(4 to 7); + reg_ctb_o <= ctrl_reg_q(3); + reg_pgb_o <= ctrl_reg_q(4)(5 to 7); + reg_satb_o <= ctrl_reg_q(5)(1 to 7); + reg_spgb_o <= ctrl_reg_q(6)(5 to 7); + reg_col1_o <= ctrl_reg_q(7)(0 to 3); + reg_col0_o <= ctrl_reg_q(7)(4 to 7); + int_n_o <= int_n_q or not ctrl_reg_q(1)(2); + +end rtl; diff --git a/rtl/tms9918/vdp18/vdp18_ctrl-c.vhd b/rtl/tms9918/vdp18/vdp18_ctrl-c.vhd new file mode 100644 index 0000000..f502e93 --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_ctrl-c.vhd @@ -0,0 +1,14 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_ctrl-c.vhd,v 1.5 2006/06/18 10:47:01 arnim Exp $ +-- +------------------------------------------------------------------------------- + +configuration vdp18_ctrl_rtl_c0 of vdp18_ctrl is + + for rtl + end for; + +end vdp18_ctrl_rtl_c0; diff --git a/rtl/tms9918/vdp18/vdp18_ctrl.vhd b/rtl/tms9918/vdp18/vdp18_ctrl.vhd new file mode 100644 index 0000000..9e7d099 --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_ctrl.vhd @@ -0,0 +1,374 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_ctrl.vhd,v 1.26 2006/06/18 10:47:01 arnim Exp $ +-- +-- Timing Controller +-- +------------------------------------------------------------------------------- +-- +-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.vdp18_pack.opmode_t; +use work.vdp18_pack.hv_t; +use work.vdp18_pack.access_t; + +entity vdp18_ctrl is + + port ( + clk_i : in std_logic; + clk_en_5m37_i : in boolean; + reset_i : in boolean; + opmode_i : in opmode_t; + num_pix_i : in hv_t; + num_line_i : in hv_t; + vert_inc_i : in boolean; + reg_blank_i : in boolean; + reg_size1_i : in boolean; + stop_sprite_i : in boolean; + clk_en_acc_o : out boolean; + access_type_o : out access_t; + vert_active_o : out boolean; + hor_active_o : out boolean; + irq_o : out boolean + ); + +end vdp18_ctrl; + + +use work.vdp18_pack.all; + +architecture rtl of vdp18_ctrl is + + ----------------------------------------------------------------------------- + -- This enables a workaround for a bug in XST. + -- ISE 8.1.02i implements wrong functionality otherwise :-( + -- + constant xst_bug_wa_c : boolean := true; + -- + ----------------------------------------------------------------------------- + + signal access_type_s : access_t; + + -- pragma translate_off + -- Testbench signals -------------------------------------------------------- + -- + signal ac_s : std_logic_vector(3 downto 0); + -- + ----------------------------------------------------------------------------- + -- pragma translate_on + + signal vert_active_q, + hor_active_q : boolean; + signal sprite_active_q : boolean; + signal sprite_line_act_q : boolean; + +begin + + -- pragma translate_off + -- Testbench signals -------------------------------------------------------- + -- + ac_s <= enum_to_vec_f(access_type_s); + -- + ----------------------------------------------------------------------------- + -- pragma translate_on + + + ----------------------------------------------------------------------------- + -- Process decode_access + -- + -- Purpose: + -- Decode horizontal counter value to access type. + -- + decode_access: process (opmode_i, + num_pix_i, + vert_active_q, + sprite_line_act_q, + reg_size1_i) + variable num_pix_plus_6_v : hv_t; + variable mod_6_v : hv_t; + variable num_pix_plus_8_v : hv_t; + variable num_pix_plus_32_v : hv_t; + variable num_pix_spr_v : integer; + begin + -- default assignment + access_type_s <= AC_CPU; + + -- prepare number of pixels for pattern operations + num_pix_plus_6_v := num_pix_i + 6; + num_pix_plus_8_v := num_pix_i + 8; + num_pix_plus_32_v := num_pix_i + 32; + num_pix_spr_v := to_integer(num_pix_i and "111111110"); + + case opmode_i is + -- Graphics I, II and Multicolor Mode ----------------------------------- + when OPMODE_GRAPH1 | + OPMODE_GRAPH2 | + OPMODE_MULTIC => + -- + -- Patterns + -- + if vert_active_q then + if num_pix_plus_8_v(0) = '0' then + if not xst_bug_wa_c then + + -- original code, we want this + case num_pix_plus_8_v(6 to 7) is + when "01" => + access_type_s <= AC_PNT; + when "10" => + if opmode_i /= OPMODE_MULTIC then + -- no access to pattern color table in multicolor mode + access_type_s <= AC_PCT; + end if; + when "11" => + access_type_s <= AC_PGT; + when others => + null; + end case; + + else + + -- workaround for XST bug, we need this + if num_pix_plus_8_v(6 to 7) = "01" then + access_type_s <= AC_PNT; + elsif num_pix_plus_8_v(6 to 7) = "10" then + if opmode_i /= OPMODE_MULTIC then + access_type_s <= AC_PCT; + end if; + elsif num_pix_plus_8_v(6 to 7) = "11" then + access_type_s <= AC_PGT; + end if; + + end if; + end if; + end if; + + -- + -- Sprite test + -- + if sprite_line_act_q then + if num_pix_i(0) = '0' and + num_pix_i(0 to 5) /= "011111" and + num_pix_i(6 to 7) = "00" and + num_pix_i(4 to 5) /= "00" then + -- sprite test interleaved with pattern accesses - 23 slots + access_type_s <= AC_STST; + end if; + if num_pix_plus_32_v(0 to 4) = "00000" or + num_pix_plus_32_v(0 to 7) = "00001000" then + -- sprite tests before starting pattern phase - 9 slots + access_type_s <= AC_STST; + end if; + + -- + -- Sprite Attribute Table and Sprite Pattern Table + -- + case num_pix_spr_v is + when 250 | -78 | + -62 | -46 => + access_type_s <= AC_SATY; + when 254 | -76 | + -60 | -44 => + access_type_s <= AC_SATX; + when 252 | -74 | + -58 | -42 => + access_type_s <= AC_SATN; + when -86 | -70 | + -54 | -38 => + access_type_s <= AC_SATC; + when -84 | -68 | + -52 | -36 => + access_type_s <= AC_SPTH; + when -82 | -66 | + -50 | -34 => + if reg_size1_i then + access_type_s <= AC_SPTL; + end if; + when others => + null; + end case; + end if; + + -- Text Mode ------------------------------------------------------------ + when OPMODE_TEXTM => + if vert_active_q and + num_pix_plus_6_v(0) = '0' and + num_pix_plus_6_v(0 to 4) /= "01111" then + mod_6_v := mod_6_f(num_pix_plus_6_v); + case mod_6_v(6 to 7) is + when "00" => + access_type_s <= AC_PNT; + when "10" => + access_type_s <= AC_PGT; + when others => + null; + end case; + end if; + + -- Unknown -------------------------------------------------------------- + when others => + null; + + end case; + + end process decode_access; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process vert_flags + -- + -- Purpose: + -- Track the vertical position with flags. + -- + vert_flags: process (clk_i, reset_i) + begin + if reset_i then + vert_active_q <= false; + sprite_active_q <= false; + sprite_line_act_q <= false; + + elsif clk_i'event and clk_i = '1' then + if clk_en_5m37_i then + -- line-local sprite processing + if sprite_active_q then + -- sprites are globally enabled + if vert_inc_i then + -- reload at beginning of every new line + -- => scan with STST + sprite_line_act_q <= true; + end if; + + if num_pix_i = hv_sprite_start_c then + -- reload when access to sprite memory starts + sprite_line_act_q <= true; + end if; + end if; + + if vert_inc_i then + -- global sprite processing + if reg_blank_i then + sprite_active_q <= false; + sprite_line_act_q <= false; + elsif num_line_i = -2 then + -- start at line -1 + sprite_active_q <= true; + -- initialize immediately + sprite_line_act_q <= true; + elsif num_line_i = 191 then + -- stop at line 192 + sprite_active_q <= false; + -- force stop + sprite_line_act_q <= false; + end if; + + -- global vertical display + if reg_blank_i then + vert_active_q <= false; + elsif num_line_i = -1 then + -- start vertical display at line 0 + vert_active_q <= true; + elsif num_line_i = 191 then + -- stop at line 192 + vert_active_q <= false; + end if; + end if; + + if stop_sprite_i then + -- stop processing of sprites in this line + sprite_line_act_q <= false; + end if; + + end if; + end if; + end process vert_flags; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process hor_flags + -- + -- Purpose: + -- Track the horizontal position. + -- + hor_flags: process (clk_i, reset_i) + begin + if reset_i then + hor_active_q <= false; + + elsif clk_i'event and clk_i = '1' then + if clk_en_5m37_i then + if not reg_blank_i and + num_pix_i = -1 then + hor_active_q <= true; + end if; + + if opmode_i = OPMODE_TEXTM then + if num_pix_i = 239 then + hor_active_q <= false; + end if; + else + if num_pix_i = 255 then + hor_active_q <= false; + end if; + end if; + end if; + end if; + end process hor_flags; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Ouput mapping + ----------------------------------------------------------------------------- + -- generate clock enable for flip-flops working on access_type + clk_en_acc_o <= clk_en_5m37_i and num_pix_i(8) = '1'; + access_type_o <= access_type_s; + vert_active_o <= vert_active_q; + hor_active_o <= hor_active_q; + irq_o <= vert_inc_i and num_line_i = 191; + +end rtl; diff --git a/rtl/tms9918/vdp18/vdp18_hor_vert-c.vhd b/rtl/tms9918/vdp18/vdp18_hor_vert-c.vhd new file mode 100644 index 0000000..e04088d --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_hor_vert-c.vhd @@ -0,0 +1,14 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_hor_vert-c.vhd,v 1.5 2006/06/18 10:47:01 arnim Exp $ +-- +------------------------------------------------------------------------------- + +configuration vdp18_hor_vert_rtl_c0 of vdp18_hor_vert is + + for rtl + end for; + +end vdp18_hor_vert_rtl_c0; diff --git a/rtl/tms9918/vdp18/vdp18_hor_vert.vhd b/rtl/tms9918/vdp18/vdp18_hor_vert.vhd new file mode 100644 index 0000000..7796240 --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_hor_vert.vhd @@ -0,0 +1,217 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_hor_vert.vhd,v 1.11 2006/06/18 10:47:01 arnim Exp $ +-- +-- Horizontal / Vertical Timing Generator +-- +------------------------------------------------------------------------------- +-- +-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +use work.vdp18_pack.opmode_t; +use work.vdp18_pack.hv_t; + +entity vdp18_hor_vert is + + generic ( + is_pal_g : integer := 0 + ); + port ( + clk_i : in std_logic; + clk_en_5m37_i : in boolean; + reset_i : in boolean; + opmode_i : in opmode_t; + num_pix_o : out hv_t; + num_line_o : out hv_t; + vert_inc_o : out boolean; + hsync_n_o : out std_logic; + vsync_n_o : out std_logic; + blank_o : out boolean + ); + +end vdp18_hor_vert; + + +use work.vdp18_pack.all; + +architecture rtl of vdp18_hor_vert is + + signal last_line_s : hv_t; + signal first_line_s : hv_t; + + signal first_pix_s : hv_t; + signal last_pix_s : hv_t; + + signal cnt_hor_q : hv_t; + signal cnt_vert_q : hv_t; + + signal vert_inc_s : boolean; + + signal hblank_q, + vblank_q : boolean; + +begin + + ----------------------------------------------------------------------------- + -- Prepare comparison signals for NTSC and PAL. + -- + is_ntsc: if is_pal_g /= 1 generate + first_line_s <= hv_first_line_ntsc_c; + last_line_s <= hv_last_line_ntsc_c; + end generate; + -- + is_pal: if is_pal_g = 1 generate + first_line_s <= hv_first_line_pal_c; + last_line_s <= hv_last_line_pal_c; + end generate; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process opmode_mux + -- + -- Purpose: + -- Generates the horizontal counter limits based on the current operating + -- mode. + -- + opmode_mux: process (opmode_i) + begin + if opmode_i = OPMODE_TEXTM then + first_pix_s <= hv_first_pix_text_c; + last_pix_s <= hv_last_pix_text_c; + else + first_pix_s <= hv_first_pix_graph_c; + last_pix_s <= hv_last_pix_graph_c; + end if; + end process opmode_mux; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process counters + -- + -- Purpose: + -- Implements the horizontal and vertical counters. + -- + counters: process (clk_i, reset_i, first_line_s) + begin + if reset_i then + cnt_hor_q <= hv_first_pix_text_c; + cnt_vert_q <= first_line_s; + hsync_n_o <= '1'; + vsync_n_o <= '1'; + hblank_q <= false; + vblank_q <= false; + + elsif clk_i'event and clk_i = '1' then + if clk_en_5m37_i then + -- The horizontal counter --------------------------------------------- + if cnt_hor_q = last_pix_s then + cnt_hor_q <= first_pix_s; + else + cnt_hor_q <= cnt_hor_q + 1; + end if; + + -- The vertical counter ----------------------------------------------- + if cnt_vert_q = last_line_s then + cnt_vert_q <= first_line_s; + elsif vert_inc_s then + -- increment when horizontal counter is at trigger position + cnt_vert_q <= cnt_vert_q + 1; + end if; + + -- Horizontal sync ---------------------------------------------------- + if cnt_hor_q = -64 then + hsync_n_o <= '0'; + elsif cnt_hor_q = -38 then + hsync_n_o <= '1'; + end if; + if cnt_hor_q = -72 then + hblank_q <= true; + elsif cnt_hor_q = -14 then + hblank_q <= false; + end if; + + -- Vertical sync ------------------------------------------------------ + if is_pal_g = 1 then + if cnt_vert_q = 244 then + vsync_n_o <= '0'; + elsif cnt_vert_q = 247 then + vsync_n_o <= '1'; + end if; + else + if cnt_vert_q = 218 then + vsync_n_o <= '0'; + elsif cnt_vert_q = 221 then + vsync_n_o <= '1'; + end if; + + if cnt_vert_q = 215 then + vblank_q <= true; + elsif cnt_vert_q = first_line_s + 13 then + vblank_q <= false; + end if; + end if; + + end if; + end if; + end process counters; + -- + ----------------------------------------------------------------------------- + + + -- comparator for vertical line increment + vert_inc_s <= clk_en_5m37_i and cnt_hor_q = hv_vertical_inc_c; + + + ----------------------------------------------------------------------------- + -- Output mapping + ----------------------------------------------------------------------------- + num_pix_o <= cnt_hor_q; + num_line_o <= cnt_vert_q; + vert_inc_o <= vert_inc_s; + blank_o <= hblank_q or vblank_q; + +end rtl; diff --git a/rtl/tms9918/vdp18/vdp18_pack-p.vhd b/rtl/tms9918/vdp18/vdp18_pack-p.vhd new file mode 100644 index 0000000..50dbd47 --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_pack-p.vhd @@ -0,0 +1,281 @@ +------------------------------------------------------------------------------- +-- +-- $Id: vdp18_pack-p.vhd,v 1.14 2006/02/22 23:07:05 arnim Exp $ +-- +-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +-- +-- All rights reserved +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +package vdp18_pack is + + ----------------------------------------------------------------------------- + -- Subtype for horizontal/vertical counters/positions. + -- + subtype hv_t is signed(0 to 8); + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Constants for first and last vertical line of NTSC and PAL mode. + -- + constant hv_first_line_ntsc_c : hv_t := to_signed(-40, hv_t'length); + constant hv_last_line_ntsc_c : hv_t := to_signed(221, hv_t'length); + -- + constant hv_first_line_pal_c : hv_t := to_signed(-65, hv_t'length); + constant hv_last_line_pal_c : hv_t := to_signed(247, hv_t'length); + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Constants for first and last horizontal pixel in text and graphics. + -- + constant hv_first_pix_text_c : hv_t := to_signed(-102, hv_t'length); + constant hv_last_pix_text_c : hv_t := to_signed(239, hv_t'length); + -- + constant hv_first_pix_graph_c : hv_t := to_signed(-86, hv_t'length); + constant hv_last_pix_graph_c : hv_t := to_signed(255, hv_t'length); + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Miscellaneous constants for horizontal phases. + -- + constant hv_vertical_inc_c : hv_t := to_signed(-32, hv_t'length); + constant hv_sprite_start_c : hv_t := to_signed(247, hv_t'length); + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Operating modes of the VDP18 core. + -- + type opmode_t is (OPMODE_GRAPH1, OPMODE_GRAPH2, + OPMODE_MULTIC, OPMODE_TEXTM); + -- + constant opmode_graph1_c : std_logic_vector(0 to 2) := "000"; + constant opmode_graph2_c : std_logic_vector(0 to 2) := "001"; + constant opmode_multic_c : std_logic_vector(0 to 2) := "010"; + constant opmode_textm_c : std_logic_vector(0 to 2) := "100"; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Access types. + -- + type access_t is (-- pattern access + -- read Pattern Name Table + AC_PNT, + -- read Pattern Generator Table + AC_PGT, + -- read Pattern Color Table + AC_PCT, + -- sprite access + -- sprite test read (y coordinate) + AC_STST, + -- read Sprite Attribute Table/Y + AC_SATY, + -- read Sprite Attribute Table/X + AC_SATX, + -- read Sprite Attribute Table/N + AC_SATN, + -- read Sprite Attribute Table/C + AC_SATC, + -- read Sprite Pattern Table/high quadrant + AC_SPTH, + -- read Sprite Pattern Table/low quadrant + AC_SPTL, + -- + -- CPU access + AC_CPU, + -- + -- no access at all + AC_NONE + ); + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Function enum_to_vec_f + -- + -- Purpose: + -- Translate access_t enumeration type to std_logic_vector. + -- + function enum_to_vec_f(enum : in access_t) return + std_logic_vector; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Function to_boolean_f + -- + -- Purpose: + -- Converts a std_logic value to boolean. + -- + function to_boolean_f(val : in std_logic) return boolean; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Function to_std_logic_f + -- + -- Purpose: + -- Converts a boolean value to std_logic. + -- + function to_std_logic_f(val : in boolean) return std_logic; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Function mod_6_f + -- + -- Purpose: + -- Calculate the modulo of 6. + -- Only the positive part is considered. + -- + function mod_6_f(val : in hv_t) return hv_t; + -- + ----------------------------------------------------------------------------- + +end vdp18_pack; + + +package body vdp18_pack is + + ----------------------------------------------------------------------------- + -- Function enum_to_vec_f + -- + -- Purpose: + -- Translate access_t enumeration type to std_logic_vector. + -- + function enum_to_vec_f(enum : in access_t) return + std_logic_vector is + variable result_v : std_logic_vector(3 downto 0); + begin + case enum is + when AC_NONE => + result_v := "0000"; + when AC_PNT => + result_v := "0001"; + when AC_PGT => + result_v := "0010"; + when AC_PCT => + result_v := "0011"; + when AC_STST => + result_v := "0100"; + when AC_SATY => + result_v := "0101"; + when AC_SATX => + result_v := "0110"; + when AC_SATN => + result_v := "0111"; + when AC_SATC => + result_v := "1000"; + when AC_SPTL => + result_v := "1001"; + when AC_SPTH => + result_v := "1010"; + when AC_CPU => + result_v := "1111"; + when others => + result_v := "UUUU"; + end case; + + return result_v; + end; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Function to_boolean_f + -- + -- Purpose: + -- Converts a std_logic value to boolean. + -- + function to_boolean_f(val : in std_logic) return boolean is + variable result_v : boolean; + begin + case to_X01(val) is + when '1' => + result_v := true; + when '0' => + result_v := false; + when others => + result_v := false; + end case; + + return result_v; + end; + -- + ----------------------------------------------------------------------------- + + ----------------------------------------------------------------------------- + -- Function to_std_logic_f + -- + -- Purpose: + -- Converts a boolean value to std_logic. + -- + function to_std_logic_f(val : in boolean) return std_logic is + variable result_v : std_logic; + begin + case val is + when true => + result_v := '1'; + when false => + result_v := '0'; + end case; + + return result_v; + end; + -- + ----------------------------------------------------------------------------- + + ----------------------------------------------------------------------------- + -- Function mod_6_f + -- + -- Purpose: + -- Calculate the modulo of 6. + -- Only the positive part is considered. + -- + function mod_6_f(val : in hv_t) return hv_t is + variable mod_v : natural; + variable result_v : hv_t; + begin + if val(0) = '0' then + result_v := (others => '0'); + mod_v := 0; + for idx in 0 to 255 loop + if val = idx then + result_v := to_signed(mod_v, hv_t'length); + end if; + + if mod_v < 5 then + mod_v := mod_v + 1; + else + mod_v := 0; + end if; + end loop; + else + result_v := (others => '-'); + end if; + + return result_v; + end; + -- + ----------------------------------------------------------------------------- + +end vdp18_pack; diff --git a/rtl/tms9918/vdp18/vdp18_pattern-c.vhd b/rtl/tms9918/vdp18/vdp18_pattern-c.vhd new file mode 100644 index 0000000..a9ba79c --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_pattern-c.vhd @@ -0,0 +1,14 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_pattern-c.vhd,v 1.5 2006/06/18 10:47:06 arnim Exp $ +-- +------------------------------------------------------------------------------- + +configuration vdp18_pattern_rtl_c0 of vdp18_pattern is + + for rtl + end for; + +end vdp18_pattern_rtl_c0; diff --git a/rtl/tms9918/vdp18/vdp18_pattern.vhd b/rtl/tms9918/vdp18/vdp18_pattern.vhd new file mode 100644 index 0000000..0c97743 --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_pattern.vhd @@ -0,0 +1,233 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_pattern.vhd,v 1.8 2006/06/18 10:47:06 arnim Exp $ +-- +-- Pattern Generation Controller +-- +------------------------------------------------------------------------------- +-- +-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +use work.vdp18_pack.opmode_t; +use work.vdp18_pack.access_t; +use work.vdp18_pack.hv_t; + +entity vdp18_pattern is + + port ( + clk_i : in std_logic; + clk_en_5m37_i : in boolean; + clk_en_acc_i : in boolean; + reset_i : in boolean; + opmode_i : in opmode_t; + access_type_i : in access_t; + num_line_i : in hv_t; + vram_d_i : in std_logic_vector(0 to 7); + vert_inc_i : in boolean; + vsync_n_i : in std_logic; + reg_col1_i : in std_logic_vector(0 to 3); + reg_col0_i : in std_logic_vector(0 to 3); + pat_table_o : out std_logic_vector(0 to 9); + pat_name_o : out std_logic_vector(0 to 7); + pat_col_o : out std_logic_vector(0 to 3) + ); + +end vdp18_pattern; + + +library ieee; +use ieee.numeric_std.all; + +use work.vdp18_pack.all; + +architecture rtl of vdp18_pattern is + + signal pat_cnt_q : unsigned(0 to 9); + signal pat_name_q, + pat_tmp_q, + pat_shift_q, + pat_col_q : std_logic_vector(0 to 7); + +begin + + ----------------------------------------------------------------------------- + -- Process seq + -- + -- Purpose: + -- Implements the sequential elements: + -- * pattern shift register + -- * pattern color register + -- * pattern counter + -- + seq: process (clk_i, reset_i) + begin + if reset_i then + pat_cnt_q <= (others => '0'); + pat_name_q <= (others => '0'); + pat_tmp_q <= (others => '0'); + pat_shift_q <= (others => '0'); + pat_col_q <= (others => '0'); + + elsif clk_i'event and clk_i = '1' then + if clk_en_5m37_i then + -- shift pattern with every pixel clock + pat_shift_q(0 to 6) <= pat_shift_q(1 to 7); + end if; + + if clk_en_acc_i then + -- determine register update based on current access type ------------- + case access_type_i is + when AC_PNT => + -- store pattern name + pat_name_q <= vram_d_i; + -- increment pattern counter + pat_cnt_q <= pat_cnt_q + 1; + + when AC_PCT => + -- store pattern color in temporary register + pat_tmp_q <= vram_d_i; + + when AC_PGT => + if opmode_i = OPMODE_MULTIC then + -- set shift register to constant value + -- this value generates 4 bits of color1 + -- followed by 4 bits of color0 + pat_shift_q <= "11110000"; + -- set pattern color from pattern generator memory + pat_col_q <= vram_d_i; + else + -- all other modes: + -- store pattern line in shift register + pat_shift_q <= vram_d_i; + -- move pattern color from temporary register to color register + pat_col_q <= pat_tmp_q; + end if; + + when others => + null; + + end case; + + end if; + + if vert_inc_i then + -- redo patterns of if there are more lines inside this pattern + if num_line_i(0) = '0' then + case opmode_i is + when OPMODE_TEXTM => + if num_line_i(6 to 8) /= "111" then + pat_cnt_q <= pat_cnt_q - 40; + end if; + + when OPMODE_GRAPH1 | + OPMODE_GRAPH2 | + OPMODE_MULTIC => + if num_line_i(6 to 8) /= "111" then + pat_cnt_q <= pat_cnt_q - 32; + end if; + end case; + end if; + end if; + + if vsync_n_i = '0' then + -- reset pattern counter at end of active display area + pat_cnt_q <= (others => '0'); + end if; + + end if; + end process seq; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process col_gen + -- + -- Purpose: + -- Generates the color of the current pattern pixel. + -- + col_gen: process (opmode_i, + pat_shift_q, + pat_col_q, + reg_col1_i, + reg_col0_i) + variable pix_v : std_logic; + begin + -- default assignment + pat_col_o <= "0000"; + pix_v := pat_shift_q(0); + + case opmode_i is + -- Text Mode ------------------------------------------------------------ + when OPMODE_TEXTM => + if pix_v = '1' then + pat_col_o <= reg_col1_i; + else + pat_col_o <= reg_col0_i; + end if; + + -- Graphics I, II and Multicolor Mode ----------------------------------- + when OPMODE_GRAPH1 | + OPMODE_GRAPH2 | + OPMODE_MULTIC => + if pix_v = '1' then + pat_col_o <= pat_col_q(0 to 3); + else + pat_col_o <= pat_col_q(4 to 7); + end if; + + when others => + null; + + end case; + end process col_gen; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Output Mapping + ----------------------------------------------------------------------------- + pat_table_o <= std_logic_vector(pat_cnt_q); + pat_name_o <= pat_name_q; + +end rtl; diff --git a/rtl/tms9918/vdp18/vdp18_sprite-c.vhd b/rtl/tms9918/vdp18/vdp18_sprite-c.vhd new file mode 100644 index 0000000..711f144 --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_sprite-c.vhd @@ -0,0 +1,14 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_sprite-c.vhd,v 1.3 2006/06/18 10:47:06 arnim Exp $ +-- +------------------------------------------------------------------------------- + +configuration vdp18_sprite_rtl_c0 of vdp18_sprite is + + for rtl + end for; + +end vdp18_sprite_rtl_c0; diff --git a/rtl/tms9918/vdp18/vdp18_sprite.vhd b/rtl/tms9918/vdp18/vdp18_sprite.vhd new file mode 100644 index 0000000..b1665a2 --- /dev/null +++ b/rtl/tms9918/vdp18/vdp18_sprite.vhd @@ -0,0 +1,441 @@ +------------------------------------------------------------------------------- +-- +-- Synthesizable model of TI's TMS9918A, TMS9928A, TMS9929A. +-- +-- $Id: vdp18_sprite.vhd,v 1.11 2006/06/18 10:47:06 arnim Exp $ +-- +-- Sprite Generation Controller +-- +-- Copyright (c) 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +-- +-- All rights reserved +-- +-- Redistribution and use in source and synthezised forms, with or without +-- modification, are permitted provided that the following conditions are met: +-- +-- Redistributions of source code must retain the above copyright notice, +-- this list of conditions and the following disclaimer. +-- +-- Redistributions in synthesized form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- Neither the name of the author nor the names of other contributors may +-- be used to endorse or promote products derived from this software without +-- specific prior written permission. +-- +-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +-- POSSIBILITY OF SUCH DAMAGE. +-- +-- Please report bugs to the author, but before you do so, please +-- make sure that this is not a derivative work and that +-- you have the latest version of this file. +-- +------------------------------------------------------------------------------- + +library ieee; +use ieee.std_logic_1164.all; + +use work.vdp18_pack.hv_t; +use work.vdp18_pack.access_t; + +entity vdp18_sprite is + + port ( + clk_i : in std_logic; + clk_en_5m37_i : in boolean; + clk_en_acc_i : in boolean; + reset_i : in boolean; + access_type_i : in access_t; + num_pix_i : in hv_t; + num_line_i : in hv_t; + vram_d_i : in std_logic_vector(0 to 7); + vert_inc_i : in boolean; + reg_size1_i : in boolean; + reg_mag1_i : in boolean; + spr_5th_o : out boolean; + spr_5th_num_o : out std_logic_vector(0 to 4); + stop_sprite_o : out boolean; + spr_coll_o : out boolean; + spr_num_o : out std_logic_vector(0 to 4); + spr_line_o : out std_logic_vector(0 to 3); + spr_name_o : out std_logic_vector(0 to 7); + spr0_col_o : out std_logic_vector(0 to 3); + spr1_col_o : out std_logic_vector(0 to 3); + spr2_col_o : out std_logic_vector(0 to 3); + spr3_col_o : out std_logic_vector(0 to 3) + ); + +end vdp18_sprite; + + +library ieee; +use ieee.numeric_std.all; + +use work.vdp18_pack.all; + +architecture rtl of vdp18_sprite is + + subtype sprite_number_t is unsigned(0 to 4); + type sprite_numbers_t is array (natural range 0 to 3) of sprite_number_t; + signal sprite_numbers_q : sprite_numbers_t; + + signal sprite_num_q : unsigned(0 to 4); + signal sprite_idx_q : unsigned(0 to 2); + signal sprite_name_q : std_logic_vector(0 to 7); + + subtype sprite_x_pos_t is unsigned(0 to 7); + type sprite_xpos_t is array (natural range 0 to 3) of sprite_x_pos_t; + signal sprite_xpos_q : sprite_xpos_t; + type sprite_ec_t is array (natural range 0 to 3) of std_logic; + signal sprite_ec_q : sprite_ec_t; + type sprite_xtog_t is array (natural range 0 to 3) of std_logic; + signal sprite_xtog_q : sprite_xtog_t; + + subtype sprite_col_t is std_logic_vector(0 to 3); + type sprite_cols_t is array (natural range 0 to 3) of sprite_col_t; + signal sprite_cols_q : sprite_cols_t; + + subtype sprite_pat_t is std_logic_vector(0 to 15); + type sprite_pats_t is array (natural range 0 to 3) of sprite_pat_t; + signal sprite_pats_q : sprite_pats_t; + + signal sprite_line_s, + sprite_line_q : std_logic_vector(0 to 3); + signal sprite_visible_s : boolean; + +begin + + ----------------------------------------------------------------------------- + -- Process seq + -- + -- Purpose: + -- Implements the sequential elements. + -- + seq: process (clk_i, reset_i) + variable sprite_idx_inc_v, + sprite_idx_dec_v : unsigned(sprite_idx_q'range); + variable sprite_idx_v : natural range 0 to 3; + begin + if reset_i then + sprite_numbers_q <= (others => (others => '0')); + sprite_num_q <= (others => '0'); + sprite_idx_q <= (others => '0'); + sprite_line_q <= (others => '0'); + sprite_name_q <= (others => '0'); + sprite_cols_q <= (others => (others => '0')); + sprite_xpos_q <= (others => (others => '0')); + sprite_ec_q <= (others => '0'); + sprite_xtog_q <= (others => '0'); + sprite_pats_q <= (others => (others => '0')); + + elsif clk_i'event and clk_i = '1' then + -- sprite index will be incremented during sprite tests + sprite_idx_inc_v := sprite_idx_q + 1; + -- sprite index will be decremented at end of sprite pattern data + sprite_idx_dec_v := sprite_idx_q - 1; + -- just save typing + sprite_idx_v := to_integer(sprite_idx_q(1 to 2)); + + if clk_en_5m37_i then + -- pre-decrement index counter when sprite reading starts + if num_pix_i = hv_sprite_start_c and sprite_idx_q > 0 then + sprite_idx_q <= sprite_idx_dec_v; + end if; + + ----------------------------------------------------------------------- + -- X position counters + ----------------------------------------------------------------------- + for idx in 0 to 3 loop + if num_pix_i(0) = '0' or + (sprite_ec_q(idx) = '1' and num_pix_i(0 to 3) = "1111") then + if sprite_xpos_q(idx) /= 0 then + -- decrement counter until 0 + sprite_xpos_q(idx) <= sprite_xpos_q(idx) - 1; + else + -- toggle magnification flag + sprite_xtog_q(idx) <= not sprite_xtog_q(idx); + end if; + end if; + end loop; + + ----------------------------------------------------------------------- + -- Sprite pattern shift registers + ----------------------------------------------------------------------- + for idx in 0 to 3 loop + if sprite_xpos_q(idx) = 0 then -- x counter elapsed + -- decide when to shift pattern information + -- case 1: pixel number is >= 0 + -- => active display area + -- case 2: early clock bit is set and pixel number is between + -- -32 and 0 + -- shift if + -- magnification not enbled + -- or + -- magnification enabled and toggle marker true + if (num_pix_i(0) = '0' or + (sprite_ec_q(idx) = '1' and num_pix_i(0 to 3) = "1111")) and + (sprite_xtog_q(idx) = '1' or not reg_mag1_i) then + -- + -- shift pattern left and fill vacated position with + -- transparent information + sprite_pats_q(idx)(0 to 14) <= sprite_pats_q(idx)(1 to 15); + sprite_pats_q(idx)(15) <= '0'; + end if; + end if; + + -- clear pattern at end of visible display + -- this removes "left-overs" when a sprite overlaps the right border + if num_pix_i = "011111111" then + sprite_pats_q(idx) <= (others => '0'); + end if; + end loop; + end if; + + + if vert_inc_i then + -- reset sprite num counter and sprite index counter + sprite_num_q <= (others => '0'); + sprite_idx_q <= (others => '0'); + + elsif clk_en_acc_i then + case access_type_i is + when AC_STST => + -- increment sprite number counter + sprite_num_q <= sprite_num_q + 1; + + if sprite_visible_s then + if sprite_idx_q < 4 then + -- store sprite number + sprite_numbers_q(sprite_idx_v) <= sprite_num_q; + -- and increment index counter + sprite_idx_q <= sprite_idx_inc_v; + end if; + end if; + + when AC_SATY => + -- store sprite line + sprite_line_q <= sprite_line_s; + + when AC_SATX => + -- save x position + sprite_xpos_q(sprite_idx_v) <= unsigned(vram_d_i); + -- reset toggle flag for magnified sprites + sprite_xtog_q(sprite_idx_v) <= '0'; + + when AC_SATN => + -- save sprite name + sprite_name_q <= vram_d_i; + + when AC_SATC => + -- save sprite color + sprite_cols_q(sprite_idx_v) <= vram_d_i(4 to 7); + -- and save early clock bit + sprite_ec_q(sprite_idx_v) <= vram_d_i(0); + + when AC_SPTH => + -- save upper pattern data + sprite_pats_q(sprite_idx_v)(0 to 7) + <= vram_d_i; + -- set lower part to transparent + sprite_pats_q(sprite_idx_v)(8 to 15) + <= (others => '0'); + + if not reg_size1_i then + -- decrement index counter in 8-bit mode + sprite_idx_q <= sprite_idx_dec_v; + end if; + + when AC_SPTL => + -- save lower pattern data + sprite_pats_q(sprite_idx_v)(8 to 15) <= vram_d_i; + + -- always decrement index counter + sprite_idx_q <= sprite_idx_dec_v; + + when others => + null; + end case; + + end if; + + end if; + end process seq; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process calc_vert + -- + -- Purpose: + -- Calculates the displayed line of the sprite and determines whether it + -- is visible on the current line or not. + -- + calc_vert: process (clk_en_acc_i, access_type_i, + vram_d_i, + num_pix_i, num_line_i, + sprite_num_q, sprite_idx_q, + reg_size1_i, reg_mag1_i) + variable sprite_line_v : signed(0 to 8); + variable vram_d_v : signed(0 to 8); + begin + -- default assignments + sprite_visible_s <= false; + stop_sprite_o <= false; + + vram_d_v := resize(signed(vram_d_i), 9); + -- determine if y information from VRAM should be treated + -- as a signed or unsigned number + if vram_d_v < -31 then + -- treat as unsigned number + vram_d_v(0) := '0'; + end if; + + sprite_line_v := num_line_i - vram_d_v; + if reg_mag1_i then + -- unmagnify line number + sprite_line_v := shift_right(sprite_line_v, 1); + end if; + + -- check result bounds + if sprite_line_v >= 0 then + if reg_size1_i then + -- double sized sprite: 16 data lines + if sprite_line_v < 16 then + sprite_visible_s <= true; + end if; + else + -- standard sized sprite: 8 data lines + if sprite_line_v < 8 then + sprite_visible_s <= true; + end if; + end if; + end if; + + -- finally: line number of current sprite + sprite_line_s <= std_logic_vector(sprite_line_v(5 to 8)); + + if clk_en_acc_i then + -- determine when to stop sprite scanning + if access_type_i = AC_STST then + if vram_d_v = 208 then + -- stop upon Y position 208 + stop_sprite_o <= true; + end if; + + if sprite_idx_q = 4 then + -- stop when all sprite positions have been vacated + stop_sprite_o <= true; + end if; + + if sprite_num_q = 31 then + -- stop when all sprites have been read + stop_sprite_o <= true; + end if; + end if; + + -- stop sprite reading when last active sprite has been processed + if sprite_idx_q = 0 and + ( access_type_i = AC_SPTL or + (access_type_i = AC_SPTH and not reg_size1_i)) then + stop_sprite_o <= true; + end if; + end if; + + -- stop sprite reading when no sprite is active on current line + if num_pix_i = hv_sprite_start_c and sprite_idx_q = 0 then + stop_sprite_o <= true; + end if; + end process calc_vert; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process fifth + -- + -- Purpose: + -- Detects the fifth sprite. + -- + fifth: process (clk_en_acc_i, access_type_i, + sprite_visible_s, + sprite_idx_q, + sprite_num_q) + begin + -- default assignments + spr_5th_o <= false; + spr_5th_num_o <= (others => '0'); + + if clk_en_acc_i and access_type_i = AC_STST then + if sprite_visible_s and sprite_idx_q = 4 then + spr_5th_o <= true; + spr_5th_num_o <= std_logic_vector(sprite_num_q); + end if; + end if; + end process fifth; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Process col_mux + -- + -- Purpose: + -- Implements the color multiplexers. + -- + col_mux: process (sprite_cols_q, + sprite_pats_q, + sprite_xpos_q) + variable num_spr_pix_v : unsigned(0 to 2); + begin + -- default assignments + -- sprite colors are set to transparent + spr0_col_o <= (others => '0'); + spr1_col_o <= (others => '0'); + spr2_col_o <= (others => '0'); + spr3_col_o <= (others => '0'); + num_spr_pix_v := (others => '0'); + + if sprite_xpos_q(0) = 0 and sprite_pats_q(0)(0) = '1' then + spr0_col_o <= sprite_cols_q(0); + num_spr_pix_v := num_spr_pix_v + 1; + end if; + if sprite_xpos_q(1) = 0 and sprite_pats_q(1)(0) = '1' then + spr1_col_o <= sprite_cols_q(1); + num_spr_pix_v := num_spr_pix_v + 1; + end if; + if sprite_xpos_q(2) = 0 and sprite_pats_q(2)(0) = '1' then + spr2_col_o <= sprite_cols_q(2); + num_spr_pix_v := num_spr_pix_v + 1; + end if; + if sprite_xpos_q(3) = 0 and sprite_pats_q(3)(0) = '1' then + spr3_col_o <= sprite_cols_q(3); + num_spr_pix_v := num_spr_pix_v + 1; + end if; + + spr_coll_o <= num_spr_pix_v > 1; + end process col_mux; + -- + ----------------------------------------------------------------------------- + + + ----------------------------------------------------------------------------- + -- Output mapping + ----------------------------------------------------------------------------- + spr_num_o <= std_logic_vector(sprite_num_q) + when access_type_i = AC_STST else + std_logic_vector(sprite_numbers_q(to_integer(sprite_idx_q(1 to 2)))); + spr_line_o <= sprite_line_q; + spr_name_o <= sprite_name_q; + +end rtl; diff --git a/rtl/tms9918/vram.qip b/rtl/tms9918/vram.qip new file mode 100644 index 0000000..4b27b7a --- /dev/null +++ b/rtl/tms9918/vram.qip @@ -0,0 +1,4 @@ +set_global_assignment -name IP_TOOL_NAME "RAM: 1-PORT" +set_global_assignment -name IP_TOOL_VERSION "13.1" +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "vram.v"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "vram_bb.v"] diff --git a/rtl/tms9918/vram.v b/rtl/tms9918/vram.v new file mode 100644 index 0000000..b045a0f --- /dev/null +++ b/rtl/tms9918/vram.v @@ -0,0 +1,172 @@ +// megafunction wizard: %RAM: 1-PORT% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altsyncram + +// ============================================================ +// File Name: vram.v +// Megafunction Name(s): +// altsyncram +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 13.1.0 Build 162 10/23/2013 SJ Web Edition +// ************************************************************ + + +//Copyright (C) 1991-2013 Altera Corporation +//Your use of Altera Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Altera Program License +//Subscription Agreement, Altera MegaCore Function License +//Agreement, or other applicable license agreement, including, +//without limitation, that your use is for the sole purpose of +//programming logic devices manufactured by Altera and sold by +//Altera or its authorized distributors. Please refer to the +//applicable agreement for further details. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module vram ( + address, + clock, + data, + wren, + q); + + input [13:0] address; + input clock; + input [7:0] data; + input wren; + output [7:0] q; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri1 clock; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire [7:0] sub_wire0; + wire [7:0] q = sub_wire0[7:0]; + + altsyncram altsyncram_component ( + .address_a (address), + .clock0 (clock), + .data_a (data), + .wren_a (wren), + .q_a (sub_wire0), + .aclr0 (1'b0), + .aclr1 (1'b0), + .address_b (1'b1), + .addressstall_a (1'b0), + .addressstall_b (1'b0), + .byteena_a (1'b1), + .byteena_b (1'b1), + .clock1 (1'b1), + .clocken0 (1'b1), + .clocken1 (1'b1), + .clocken2 (1'b1), + .clocken3 (1'b1), + .data_b (1'b1), + .eccstatus (), + .q_b (), + .rden_a (1'b1), + .rden_b (1'b1), + .wren_b (1'b0)); + defparam + altsyncram_component.clock_enable_input_a = "BYPASS", + altsyncram_component.clock_enable_output_a = "BYPASS", + altsyncram_component.intended_device_family = "Cyclone III", + altsyncram_component.lpm_hint = "ENABLE_RUNTIME_MOD=NO", + altsyncram_component.lpm_type = "altsyncram", + altsyncram_component.numwords_a = 16384, + altsyncram_component.operation_mode = "SINGLE_PORT", + altsyncram_component.outdata_aclr_a = "NONE", + altsyncram_component.outdata_reg_a = "CLOCK0", + altsyncram_component.power_up_uninitialized = "FALSE", + altsyncram_component.read_during_write_mode_port_a = "NEW_DATA_NO_NBE_READ", + altsyncram_component.widthad_a = 14, + altsyncram_component.width_a = 8, + altsyncram_component.width_byteena_a = 1; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0" +// Retrieval info: PRIVATE: AclrAddr NUMERIC "0" +// Retrieval info: PRIVATE: AclrByte NUMERIC "0" +// Retrieval info: PRIVATE: AclrData NUMERIC "0" +// Retrieval info: PRIVATE: AclrOutput NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8" +// Retrieval info: PRIVATE: BlankMemory NUMERIC "1" +// Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0" +// Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0" +// Retrieval info: PRIVATE: Clken NUMERIC "0" +// Retrieval info: PRIVATE: DataBusSeparated NUMERIC "1" +// Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0" +// Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A" +// Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0" +// Retrieval info: PRIVATE: JTAG_ID STRING "NONE" +// Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0" +// Retrieval info: PRIVATE: MIFfilename STRING "" +// Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "16384" +// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" +// Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_A NUMERIC "3" +// Retrieval info: PRIVATE: RegAddr NUMERIC "1" +// Retrieval info: PRIVATE: RegData NUMERIC "1" +// Retrieval info: PRIVATE: RegOutput NUMERIC "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: SingleClock NUMERIC "1" +// Retrieval info: PRIVATE: UseDQRAM NUMERIC "1" +// Retrieval info: PRIVATE: WRCONTROL_ACLR_A NUMERIC "0" +// Retrieval info: PRIVATE: WidthAddr NUMERIC "14" +// Retrieval info: PRIVATE: WidthData NUMERIC "8" +// Retrieval info: PRIVATE: rden NUMERIC "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS" +// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: CONSTANT: LPM_HINT STRING "ENABLE_RUNTIME_MOD=NO" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram" +// Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "16384" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "SINGLE_PORT" +// Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE" +// Retrieval info: CONSTANT: OUTDATA_REG_A STRING "CLOCK0" +// Retrieval info: CONSTANT: POWER_UP_UNINITIALIZED STRING "FALSE" +// Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_PORT_A STRING "NEW_DATA_NO_NBE_READ" +// Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "14" +// Retrieval info: CONSTANT: WIDTH_A NUMERIC "8" +// Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" +// Retrieval info: USED_PORT: address 0 0 14 0 INPUT NODEFVAL "address[13..0]" +// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock" +// Retrieval info: USED_PORT: data 0 0 8 0 INPUT NODEFVAL "data[7..0]" +// Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL "q[7..0]" +// Retrieval info: USED_PORT: wren 0 0 0 0 INPUT NODEFVAL "wren" +// Retrieval info: CONNECT: @address_a 0 0 14 0 address 0 0 14 0 +// Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 +// Retrieval info: CONNECT: @data_a 0 0 8 0 data 0 0 8 0 +// Retrieval info: CONNECT: @wren_a 0 0 0 0 wren 0 0 0 0 +// Retrieval info: CONNECT: q 0 0 8 0 @q_a 0 0 8 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL vram.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL vram.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL vram.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL vram.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL vram_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL vram_bb.v TRUE +// Retrieval info: LIB_FILE: altera_mf diff --git a/rtl/tms9918/vram_bb.v b/rtl/tms9918/vram_bb.v new file mode 100644 index 0000000..e70a40c --- /dev/null +++ b/rtl/tms9918/vram_bb.v @@ -0,0 +1,123 @@ +// megafunction wizard: %RAM: 1-PORT%VBB% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altsyncram + +// ============================================================ +// File Name: vram.v +// Megafunction Name(s): +// altsyncram +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 13.1.0 Build 162 10/23/2013 SJ Web Edition +// ************************************************************ + +//Copyright (C) 1991-2013 Altera Corporation +//Your use of Altera Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Altera Program License +//Subscription Agreement, Altera MegaCore Function License +//Agreement, or other applicable license agreement, including, +//without limitation, that your use is for the sole purpose of +//programming logic devices manufactured by Altera and sold by +//Altera or its authorized distributors. Please refer to the +//applicable agreement for further details. + +module vram ( + address, + clock, + data, + wren, + q); + + input [13:0] address; + input clock; + input [7:0] data; + input wren; + output [7:0] q; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri1 clock; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0" +// Retrieval info: PRIVATE: AclrAddr NUMERIC "0" +// Retrieval info: PRIVATE: AclrByte NUMERIC "0" +// Retrieval info: PRIVATE: AclrData NUMERIC "0" +// Retrieval info: PRIVATE: AclrOutput NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "0" +// Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8" +// Retrieval info: PRIVATE: BlankMemory NUMERIC "1" +// Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0" +// Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0" +// Retrieval info: PRIVATE: Clken NUMERIC "0" +// Retrieval info: PRIVATE: DataBusSeparated NUMERIC "1" +// Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0" +// Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A" +// Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0" +// Retrieval info: PRIVATE: JTAG_ID STRING "NONE" +// Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0" +// Retrieval info: PRIVATE: MIFfilename STRING "" +// Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "16384" +// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" +// Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_A NUMERIC "3" +// Retrieval info: PRIVATE: RegAddr NUMERIC "1" +// Retrieval info: PRIVATE: RegData NUMERIC "1" +// Retrieval info: PRIVATE: RegOutput NUMERIC "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: SingleClock NUMERIC "1" +// Retrieval info: PRIVATE: UseDQRAM NUMERIC "1" +// Retrieval info: PRIVATE: WRCONTROL_ACLR_A NUMERIC "0" +// Retrieval info: PRIVATE: WidthAddr NUMERIC "14" +// Retrieval info: PRIVATE: WidthData NUMERIC "8" +// Retrieval info: PRIVATE: rden NUMERIC "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS" +// Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone III" +// Retrieval info: CONSTANT: LPM_HINT STRING "ENABLE_RUNTIME_MOD=NO" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram" +// Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "16384" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "SINGLE_PORT" +// Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE" +// Retrieval info: CONSTANT: OUTDATA_REG_A STRING "CLOCK0" +// Retrieval info: CONSTANT: POWER_UP_UNINITIALIZED STRING "FALSE" +// Retrieval info: CONSTANT: READ_DURING_WRITE_MODE_PORT_A STRING "NEW_DATA_NO_NBE_READ" +// Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "14" +// Retrieval info: CONSTANT: WIDTH_A NUMERIC "8" +// Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" +// Retrieval info: USED_PORT: address 0 0 14 0 INPUT NODEFVAL "address[13..0]" +// Retrieval info: USED_PORT: clock 0 0 0 0 INPUT VCC "clock" +// Retrieval info: USED_PORT: data 0 0 8 0 INPUT NODEFVAL "data[7..0]" +// Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL "q[7..0]" +// Retrieval info: USED_PORT: wren 0 0 0 0 INPUT NODEFVAL "wren" +// Retrieval info: CONNECT: @address_a 0 0 14 0 address 0 0 14 0 +// Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 +// Retrieval info: CONNECT: @data_a 0 0 8 0 data 0 0 8 0 +// Retrieval info: CONNECT: @wren_a 0 0 0 0 wren 0 0 0 0 +// Retrieval info: CONNECT: q 0 0 8 0 @q_a 0 0 8 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL vram.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL vram.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL vram.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL vram.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL vram_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL vram_bb.v TRUE +// Retrieval info: LIB_FILE: altera_mf diff --git a/rtl/vram.qip b/rtl/vram.qip new file mode 100644 index 0000000..e69de29 diff --git a/rtl/vram.v b/rtl/vram.v deleted file mode 100644 index 4f860ac..0000000 --- a/rtl/vram.v +++ /dev/null @@ -1,46 +0,0 @@ -// Licensed to the Apache Software Foundation (ASF) under one -// or more contributor license agreements. See the NOTICE file -// distributed with this work for additional information -// regarding copyright ownership. The ASF licenses this file -// to you under the Apache License, Version 2.0 (the -// "License"); you may not use this file except in compliance -// with the License. You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, -// software distributed under the License is distributed on an -// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -// KIND, either express or implied. See the License for the -// specific language governing permissions and limitations -// under the License. -// -// Description: Video RAM for system -// -// Author.....: Alan Garfield -// Niels A. Moseley -// Date.......: 26-1-2018 -// - -module vram ( - input clk, // clock signal - input [10:0] read_addr, // read address bus - input [10:0] write_addr, // write address bus - input r_en, // active high read enable strobe - input w_en, // active high write enable strobe - input [5:0] din, // 6-bit data bus (input) - output reg [5:0] dout // 6-bit data bus (output) -); - - reg [5:0] ram_data[0:2047]; - - initial - $readmemb("roms/vga_vram.bin", ram_data, 0, 2047); - - always @(posedge clk) - begin - if (r_en) dout <= ram_data[read_addr]; - if (w_en) ram_data[write_addr] <= din; - end - -endmodule