diff --git a/cores/bbc/fpga/mist/bbc_mist.sdc b/cores/bbc/fpga/mist/bbc_mist.sdc new file mode 100644 index 0000000..2252a6b --- /dev/null +++ b/cores/bbc/fpga/mist/bbc_mist.sdc @@ -0,0 +1,52 @@ +#************************************************************ +# THIS IS A WIZARD-GENERATED FILE. +# +# Version 13.1.4 Build 182 03/12/2014 SJ Full Version +# +#************************************************************ + +# Copyright (C) 1991-2014 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. + + + +# Clock constraints + +create_clock -name "CLOCK_27" -period 37.037 [get_ports {CLOCK_27[0]}] +create_clock -name {SPI_SCK} -period 41.666 -waveform { 20.8 41.666 } [get_ports {SPI_SCK}] + +# Automatically constrain PLL and other generated clocks +derive_pll_clocks -create_base_clocks + +# Automatically calculate clock uncertainty to jitter and other effects. +derive_clock_uncertainty + +# Clock groups +set_clock_groups -asynchronous -group [get_clocks {SPI_SCK}] -group [get_clocks {CLOCKS|altpll_component|auto_generated|pll1|clk[*]}] + + +# Some relaxed constrain to the VGA pins. The signals should arrive together, the delay is not really important. +set_output_delay -clock [get_clocks {CLOCKS|altpll_component|auto_generated|pll1|clk[0]}] -max 0 [get_ports {VGA_*}] +set_output_delay -clock [get_clocks {CLOCKS|altpll_component|auto_generated|pll1|clk[0]}] -min -5 [get_ports {VGA_*}] + +# SDRAM delays +set_input_delay -clock [get_clocks {CLOCKS|altpll_component|auto_generated|pll1|clk[0]}] -max 6.4 [get_ports SDRAM_DQ[*]] +set_input_delay -clock [get_clocks {CLOCKS|altpll_component|auto_generated|pll1|clk[0]}] -min 3.2 [get_ports SDRAM_DQ[*]] + +set_output_delay -clock [get_clocks {CLOCKS|altpll_component|auto_generated|pll1|clk[0]}] -max 1.5 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}] +set_output_delay -clock [get_clocks {CLOCKS|altpll_component|auto_generated|pll1|clk[0]}] -min -0.8 [get_ports {SDRAM_D* SDRAM_A* SDRAM_BA* SDRAM_n* SDRAM_CKE}] + +set_false_path -to [get_ports {AUDIO_L}] +set_false_path -to [get_ports {AUDIO_R}] +set_false_path -to [get_ports {LED}] diff --git a/cores/bbc/fpga/mist/bbc_mist_top.qsf b/cores/bbc/fpga/mist/bbc_mist_top.qsf index 2be9912..8a251ba 100644 --- a/cores/bbc/fpga/mist/bbc_mist_top.qsf +++ b/cores/bbc/fpga/mist/bbc_mist_top.qsf @@ -133,7 +133,7 @@ set_location_assignment PIN_65 -to AUDIO_L set_location_assignment PIN_80 -to AUDIO_R set_global_assignment -name ENABLE_SIGNALTAP OFF -set_global_assignment -name USE_SIGNALTAP_FILE signal_tap.stp +set_global_assignment -name USE_SIGNALTAP_FILE output_files/stp2.stp set_global_assignment -name ENABLE_CONFIGURATION_PINS OFF set_global_assignment -name ENABLE_NCE_PIN OFF set_global_assignment -name ENABLE_BOOT_SEL_PIN OFF @@ -158,10 +158,9 @@ set_location_assignment PIN_7 -to LED set_global_assignment -name ADV_NETLIST_OPT_SYNTH_WYSIWYG_REMAP ON set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V" + set_global_assignment -name VERILOG_FILE ../../rtl/adc.v set_global_assignment -name VERILOG_FILE sdram.v -set_global_assignment -name VERILOG_FILE ../../rtl/cpu.v -set_global_assignment -name VERILOG_FILE ../../rtl/ALU.v set_global_assignment -name VERILOG_FILE ../../rtl/mc6845.v set_global_assignment -name VERILOG_FILE ../../rtl/ps2_intf.v set_global_assignment -name VERILOG_FILE ../../rtl/vidproc.v @@ -185,6 +184,7 @@ set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_clock_div-c set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_clock_div.vhd" set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_attenuator-c.vhd" set_global_assignment -name VHDL_FILE "../../rtl/sn76489-1.0/sn76489_attenuator.vhd" +set_global_assignment -name VERILOG_FILE sd_card.v set_global_assignment -name VERILOG_FILE user_io.v set_global_assignment -name VERILOG_FILE osd.v set_global_assignment -name VERILOG_FILE data_io.v @@ -192,9 +192,11 @@ set_global_assignment -name VERILOG_FILE clockgen.v set_global_assignment -name VERILOG_FILE ../rtl/scandoubler.v set_global_assignment -name VERILOG_FILE ../../rtl/bbc.v set_global_assignment -name CDF_FILE output_files/Chain4.cdf -set_global_assignment -name VERILOG_FILE ../../rtl/m6522.v -set_global_assignment -name QIP_FILE smmc.qip +set_global_assignment -name VHDL_FILE ../../rtl/m6522.vhd +set_global_assignment -name QIP_FILE ../../rtl/T65/T65.qip +set_global_assignment -name QIP_FILE mmfs.qip set_global_assignment -name QIP_FILE os12.qip set_global_assignment -name QIP_FILE basic2.qip set_global_assignment -name QIP_FILE dfs09.qip +set_global_assignment -name SDC_FILE bbc_mist.sdc set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top \ No newline at end of file diff --git a/cores/bbc/fpga/mist/bbc_mist_top.v b/cores/bbc/fpga/mist/bbc_mist_top.v index 823352c..0b1f7fe 100755 --- a/cores/bbc/fpga/mist/bbc_mist_top.v +++ b/cores/bbc/fpga/mist/bbc_mist_top.v @@ -34,7 +34,7 @@ module bbc_mist_top( // SPI - inout SPI_DO, + output SPI_DO, input SPI_DI, input SPI_SCK, input SPI_SS2, // data_io @@ -157,6 +157,8 @@ wire [7:0] sd_dout; wire sd_dout_strobe; wire [7:0] sd_din; wire sd_din_strobe; +wire [8:0] sd_buff_addr; +wire sd_ack_conf; wire [7:0] joystick_0; wire [7:0] joystick_1; @@ -167,8 +169,9 @@ wire scandoubler_disable; user_io #(.STRLEN(CONF_STR_LEN)) user_io( .conf_str ( CONF_STR ), - // the spi interface + .clk_sys(clk_32m), + // the spi interface .SPI_CLK ( SPI_SCK ), .SPI_SS_IO ( CONF_DATA0 ), .SPI_MISO ( SPI_DO ), // tristate handling inside user_io @@ -196,6 +199,8 @@ user_io #(.STRLEN(CONF_STR_LEN)) user_io( .sd_dout_strobe(sd_dout_strobe ), .sd_din ( sd_din ), .sd_din_strobe (sd_din_strobe ), + .sd_buff_addr (sd_buff_addr ), + .sd_ack_conf (sd_ack_conf ), .ps2_clk ( clk_14k ), .ps2_kbd_clk ( ps2_clk ), @@ -203,28 +208,29 @@ user_io #(.STRLEN(CONF_STR_LEN)) user_io( ); // wire the sd card to the user port -wire sd_sck = user_via_pb_out[1]; -wire sd_cs = 1'b0; -wire sd_sdi = user_via_pb_out[0]; -wire sd_sdo = user_via_cb2_in; -assign user_via_cb1_in = user_via_pb_out[1]; +wire sd_sck; +wire sd_cs; +wire sd_sdi; +wire sd_sdo; -sd_card sd_card ( - // connection to io controller - .io_lba (sd_lba ), - .io_rd (sd_rd), - .io_wr (sd_wr), - .io_ack (sd_ack), - .io_conf (sd_conf), - .io_sdhc (sd_sdhc), - .io_din (sd_dout), - .io_din_strobe (sd_dout_strobe), - .io_dout (sd_din), - .io_dout_strobe ( sd_din_strobe), + sd_card sd_card ( + // connection to io controller + .clk(clk_32m), + .io_lba (sd_lba ), + .io_rd (sd_rd), + .io_wr (sd_wr), + .io_ack (sd_ack), + .io_ack_conf (sd_ack_conf ), + .io_conf (sd_conf), + .io_sdhc (sd_sdhc), + .io_din (sd_dout), + .io_din_strobe (sd_dout_strobe), + .io_dout (sd_din), + .io_dout_strobe ( sd_din_strobe), + .io_buff_addr (sd_buff_addr ), + .allow_sdhc ( 1'b1), // SDHC not supported - .allow_sdhc ( 1'b0), // SDHC not supported - - // connection to local CPU + // connection to local CPU .sd_cs ( sd_cs ), .sd_sck ( sd_sck ), .sd_sdi ( sd_sdi ), @@ -317,11 +323,12 @@ bbc BBC( .VID_ADR ( vid_adr ), .VID_DI ( vid_data ), - .SHIFT ( autoboot_shift ), - - .user_via_pb_out ( user_via_pb_out ), - .user_via_cb1_in ( user_via_cb1_in ), - .user_via_cb2_in ( user_via_cb2_in ), + .SHIFT ( autoboot_shift ), + + .SDCLK (sd_sck ), + .SDSS (sd_cs ), + .SDMISO (sd_sdo ), + .SDMOSI (sd_sdi ), .joy_but ( { joystick_1[4], joystick_0[4] } ), .joy0_axis0 ( joystick_analog_0[15:8] ), @@ -398,11 +405,11 @@ basic2 basic2 ( .q ( basic_do ) ); -wire [7:0] smmc_do; -smmc smmc ( +wire [7:0] mmfs_do; +mmfs mmfs ( .clock ( clk_32m ), .address ( mem_adr[13:0] ), - .q ( smmc_do ) + .q ( mmfs_do ) ); audio AUDIO ( @@ -459,11 +466,11 @@ wire sideways_ram = // status[2] is '1' of low mapping is selected in the menu wire basic_map = status[2]?(mem_romsel == 4'h0):(mem_romsel == 4'he); -wire smmc_map = status[2]?(mem_romsel == 4'h2):(mem_romsel == 4'hc); +wire mmfs_map = status[2]?(mem_romsel == 4'h2):(mem_romsel == 4'hc); assign mem_di = ((mem_adr[15:14] == 2'b10) && basic_map) ? basic_do : - ((mem_adr[15:14] == 2'b10) && smmc_map) ? smmc_do : + ((mem_adr[15:14] == 2'b10) && mmfs_map) ? mmfs_do : ((mem_adr[15:14] == 2'b10) && (mem_romsel == 4'ha)) ? ram_do : mos_rom ? os_do : cpu_ram ? ram_do : diff --git a/cores/bbc/fpga/mist/smmc.qip b/cores/bbc/fpga/mist/mmfs.qip similarity index 89% rename from cores/bbc/fpga/mist/smmc.qip rename to cores/bbc/fpga/mist/mmfs.qip index 6e4e45f..0d0ccd7 100644 --- a/cores/bbc/fpga/mist/smmc.qip +++ b/cores/bbc/fpga/mist/mmfs.qip @@ -1,3 +1,3 @@ set_global_assignment -name IP_TOOL_NAME "ROM: 1-PORT" set_global_assignment -name IP_TOOL_VERSION "13.1" -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "smmc.v"] +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "mmfs.v"] diff --git a/cores/bbc/fpga/mist/smmc.v b/cores/bbc/fpga/mist/mmfs.v similarity index 90% rename from cores/bbc/fpga/mist/smmc.v rename to cores/bbc/fpga/mist/mmfs.v index aa24fb3..f482105 100644 --- a/cores/bbc/fpga/mist/smmc.v +++ b/cores/bbc/fpga/mist/mmfs.v @@ -4,7 +4,7 @@ // MODULE: altsyncram // ============================================================ -// File Name: smmc.v +// File Name: mmfs.v // Megafunction Name(s): // altsyncram // @@ -36,7 +36,7 @@ // synopsys translate_off `timescale 1 ps / 1 ps // synopsys translate_on -module smmc ( +module mmfs ( address, clock, q); @@ -84,9 +84,9 @@ module smmc ( altsyncram_component.clock_enable_input_a = "BYPASS", altsyncram_component.clock_enable_output_a = "BYPASS", `ifdef NO_PLI - altsyncram_component.init_file = "../../roms/smmc.rif" + altsyncram_component.init_file = "../../roms/mmfs.rif" `else - altsyncram_component.init_file = "../../roms/smmc.hex" + altsyncram_component.init_file = "../../roms/mmfs.hex" `endif , altsyncram_component.intended_device_family = "Cyclone III", @@ -123,7 +123,7 @@ endmodule // 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 "../../roms/smmc.hex" +// Retrieval info: PRIVATE: MIFfilename STRING "../../roms/mmfs.hex" // Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "16384" // Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" // Retrieval info: PRIVATE: RegAddr NUMERIC "1" @@ -138,7 +138,7 @@ endmodule // Retrieval info: CONSTANT: ADDRESS_ACLR_A STRING "NONE" // Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "BYPASS" // Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS" -// Retrieval info: CONSTANT: INIT_FILE STRING "../../roms/smmc.hex" +// Retrieval info: CONSTANT: INIT_FILE STRING "../../roms/mmfs.hex" // 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" @@ -155,10 +155,10 @@ endmodule // 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: q 0 0 8 0 @q_a 0 0 8 0 -// Retrieval info: GEN_FILE: TYPE_NORMAL smmc.v TRUE -// Retrieval info: GEN_FILE: TYPE_NORMAL smmc.inc FALSE -// Retrieval info: GEN_FILE: TYPE_NORMAL smmc.cmp FALSE -// Retrieval info: GEN_FILE: TYPE_NORMAL smmc.bsf FALSE -// Retrieval info: GEN_FILE: TYPE_NORMAL smmc_inst.v FALSE -// Retrieval info: GEN_FILE: TYPE_NORMAL smmc_bb.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL mmfs.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL mmfs.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL mmfs.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL mmfs.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL mmfs_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL mmfs_bb.v FALSE // Retrieval info: LIB_FILE: altera_mf diff --git a/cores/bbc/fpga/mist/sd_card.v b/cores/bbc/fpga/mist/sd_card.v index 5e7fed3..fa7ef95 100644 --- a/cores/bbc/fpga/mist/sd_card.v +++ b/cores/bbc/fpga/mist/sd_card.v @@ -25,25 +25,29 @@ // http://elm-chan.org/docs/mmc/mmc_e.html module sd_card ( + input clk, // link to user_io for io controller output [31:0] io_lba, output reg io_rd, output reg io_wr, - input io_ack, - output io_conf, - output io_sdhc, - + input io_ack, + input io_ack_conf, + output io_conf, + output io_sdhc, + // data coming in from io controller - input [7:0] io_din, - input io_din_strobe, + input [7:0] io_din, + input io_din_strobe, // data going out to io controller - output [7:0] io_dout, - input io_dout_strobe, + output [7:0] io_dout, + input io_dout_strobe, + + input [8:0] io_buff_addr, // configuration input input allow_sdhc, - + input sd_cs, input sd_sck, input sd_sdi, @@ -53,15 +57,23 @@ module sd_card ( // set io_rd once read_state machine starts waiting (rising edge of req_io_rd) // and clear it once io controller uploads something (io_ack==1) reg req_io_rd = 1'b0; // set when write_state is changed to RD_STATE_WAIT_IO -always @(posedge req_io_rd or posedge io_ack) begin - if(io_ack) io_rd <= 1'b0; - else io_rd <= 1'b1; -end reg req_io_wr = 1'b0; // set when write_state is changed to WR_STATE_BUSY -always @(posedge req_io_wr or posedge io_ack) begin - if(io_ack) io_wr <= 1'b0; - else io_wr <= 1'b1; + +always @(posedge clk) begin + reg old_io_ack; + reg req_io_rdD; + reg req_io_wrD; + + old_io_ack <= io_ack; + req_io_rdD <= req_io_rd; + req_io_wrD <= req_io_wr; + + if(~old_io_ack & io_ack) { io_rd, io_wr } <= 2'b00; + else begin + if (~req_io_rdD & req_io_rd) io_rd <= 1; + if (~req_io_wrD & req_io_wr) io_wr <= 1; + end end wire [31:0] OCR = { 1'b0, io_sdhc, 30'h0 }; // bit30 = 1 -> high capaciry card (sdhc) @@ -88,7 +100,6 @@ reg [2:0] write_state = WR_STATE_IDLE; reg card_is_reset = 1'b0; // flag that card has received a reset command reg [6:0] sbuf; reg cmd55; -reg new_cmd_rcvd; reg [7:0] cmd = 8'h00; reg [2:0] bit_cnt = 3'd0; // counts bits 0-7 0-7 ... reg [3:0] byte_cnt= 4'd15; // counts bytes @@ -104,118 +115,92 @@ reg [3:0] reply_len; // the sector buffer by the io controller. This signal is kept set as long // as the read state machine is in the "wait for io controller" state (state 1) wire rd_wait_io = (read_state != RD_STATE_IDLE); -reg rd_io_ack_i = 1'b0; -always @(negedge io_ack or negedge rd_wait_io) begin - if(!rd_wait_io) rd_io_ack_i <= 1'b0; - else rd_io_ack_i <= 1'b1; -end +reg rd_io_ack = 1'b0; wire wr_wait_io = (write_state == WR_STATE_BUSY); -reg wr_io_ack_i = 1'b0; -always @(negedge io_ack or negedge wr_wait_io) begin - if(!wr_wait_io) wr_io_ack_i <= 1'b0; - else wr_io_ack_i <= 1'b1; -end +reg wr_io_ack = 1'b0; -// bring xx_io_ack into sd cards clock domain -reg wr_io_ack; -reg rd_io_ack; -always @(posedge sd_sck) begin - rd_io_ack <= rd_io_ack_i; - wr_io_ack <= wr_io_ack_i; +always @(posedge clk) begin + reg old_io_ack; + old_io_ack <= io_ack; + + if(!wr_wait_io) wr_io_ack <= 1'b0; + else if (~io_ack & old_io_ack) begin + wr_io_ack <= 1'b1; + end + + if(!rd_wait_io) rd_io_ack <= 1'b0; + else if (~io_ack & old_io_ack) begin + rd_io_ack <= 1'b1; + end end // ------------------------- SECTOR BUFFER ----------------------- // the buffer itself. Can hold one sector -reg [7:0] buffer [511:0]; +reg [8:0] buffer_ptr; +wire [7:0] buffer_dout; +reg [7:0] buffer_din; +reg buffer_write_strobe; -// ---------------- buffer read engine ----------------------- -reg [8:0] buffer_rptr; -reg buffer_read_strobe; -wire buffer_dout_strobe = buffer_read_strobe || io_dout_strobe; -reg [7:0] buffer_dout; -assign io_dout = buffer_dout; +sd_card_dpram #(8, 9) buffer_dpram +( + .clock_a (clk), + .address_a (io_buff_addr), + .data_a (io_din), + .wren_a (io_din_strobe & io_ack), + .q_a (io_dout), -// buffer_rptr is increased in a diferent clock domain than it's -// evaluated. These single bit registers bring certain states from -// one domain into the other one in a safe (atomic) way -reg buffer_read_sector_done; -reg buffer_read_ciscid_done; - -always @(posedge buffer_dout_strobe or posedge new_cmd_rcvd) begin - if(new_cmd_rcvd == 1) begin - buffer_rptr <= 9'd0; - buffer_read_sector_done <= 1'b0; - buffer_read_ciscid_done <= 1'b0; - end else begin - buffer_dout <= buffer[buffer_rptr]; - buffer_rptr <= buffer_rptr + 9'd1; - if(buffer_rptr == 511) buffer_read_sector_done <= 1'b1; - if(buffer_rptr == 15) buffer_read_ciscid_done <= 1'b1; - end -end - -// ---------------- buffer write engine ----------------------- -reg [8:0] buffer_wptr; -reg buffer_write_strobe; -wire buffer_din_strobe = io_din_strobe || buffer_write_strobe; -wire [7:0] buffer_din = (cmd == 8'h51)?io_din:{sbuf, sd_sdi}; - -always @(posedge buffer_din_strobe or posedge new_cmd_rcvd) begin - if(new_cmd_rcvd == 1) - buffer_wptr <= 9'd0; - else begin - buffer[buffer_wptr] <= buffer_din; - buffer_wptr <= buffer_wptr + 9'd1; - end -end + .clock_b (clk), + .address_b (buffer_ptr), + .data_b (buffer_din), + .wren_b (buffer_write_strobe), + .q_b (buffer_dout) +); wire [7:0] WRITE_DATA_RESPONSE = 8'h05; // ------------------------- CSD/CID BUFFER ---------------------- -assign io_conf = (csd_wptr == 0); // csd_wptr still 0 -> configuration required +reg [7:0] conf; +assign io_conf = io_configuring; -// the 32 bytes as sent from the io controller -reg [7:0] cid [15:0]; -reg [7:0] csd [15:0]; -reg [7:0] conf; +reg io_configuring = 1; +reg [4:0] conf_buff_ptr; +wire [7:0] conf_byte; -reg [7:0] cid_byte; -reg [7:0] csd_byte; -reg [5:0] csd_wptr = 6'd0; +sd_card_dpram #(8, 6) conf_dpram +( + .clock_a (clk), + .address_a (io_buff_addr), + .data_a (io_din), + .wren_a (io_din_strobe & io_ack_conf), + + .clock_b (clk), + .address_b (conf_buff_ptr), + .q_b (conf_byte) +); // conf[0]==1 -> io controller is using an sdhc card wire io_has_sdhc = conf[0]; assign io_sdhc = allow_sdhc && io_has_sdhc; -always @(posedge io_din_strobe) begin - // if io controller sends data without asserting io_ack, then it's - // updating the config - if(!io_ack && (csd_wptr <= 32)) begin - - if(csd_wptr < 16) // first 16 bytes are cid - cid[csd_wptr[3:0]] <= io_din; - if((csd_wptr >= 16) && (csd_wptr < 32)) // then comes csd - csd[csd_wptr[3:0]] <= io_din; - if(csd_wptr == 32) // finally a config byte - conf <= io_din; - - csd_wptr <= csd_wptr + 6'd1; +always @(posedge clk) begin + if(io_din_strobe && io_ack_conf && io_buff_addr== 32) begin + conf <= io_din; + io_configuring <= 0; end end - -always @(posedge buffer_dout_strobe) begin - cid_byte <= cid[buffer_rptr[3:0]]; - csd_byte <= csd[buffer_rptr[3:0]]; -end - -// ----------------- spi transmitter -------------------- + +always@(posedge clk) begin + + reg illegal_write_state /* synthesis noprune */; + reg old_sd_sck; + old_sd_sck <= sd_sck; // advance transmitter state machine on falling sck edge, so data is valid on the // rising edge -always@(negedge sd_sck) begin - if(sd_cs == 0) begin - buffer_read_strobe <= 1'b0; +// ----------------- spi transmitter -------------------- + if(sd_cs == 0 && old_sd_sck && ~sd_sck) begin + sd_sdo <= 1'b1; // default: send 1's (busy/wait) req_io_rd <= 1'b0; @@ -257,8 +242,10 @@ always@(negedge sd_sck) begin // waiting for io controller to return data RD_STATE_WAIT_IO: begin + buffer_ptr <= 0; if(rd_io_ack && (bit_cnt == 7)) read_state <= RD_STATE_SEND_TOKEN; + end // send data token @@ -267,7 +254,7 @@ always@(negedge sd_sck) begin if(bit_cnt == 7) begin read_state <= RD_STATE_SEND_DATA; // next: send data - buffer_read_strobe <= 1'b1; // trigger read of first data byte + conf_buff_ptr <= (cmd == 8'h4a) ? 5'h0 : 5'h10; end end @@ -276,27 +263,29 @@ always@(negedge sd_sck) begin if(cmd == 8'h51) // CMD17: READ_SINGLE_BLOCK sd_sdo <= buffer_dout[~bit_cnt]; else if(cmd == 8'h49) // CMD9: SEND_CSD - sd_sdo <= csd_byte[~bit_cnt]; + sd_sdo <= conf_byte[~bit_cnt]; else if(cmd == 8'h4a) // CMD10: SEND_CID - sd_sdo <= cid_byte[~bit_cnt]; + sd_sdo <= conf_byte[~bit_cnt]; else sd_sdo <= 1'b1; if(bit_cnt == 7) begin // sent 512 sector data bytes? - if((cmd == 8'h51) && buffer_read_sector_done) // (buffer_rptr == 0)) + if((cmd == 8'h51) && &buffer_ptr) // (buffer_ptr ==511)) read_state <= RD_STATE_IDLE; // next: send crc. It's ignored so return to idle state - + // sent 16 cid/csd data bytes? - else if(((cmd == 8'h49)||(cmd == 8'h4a)) && buffer_read_ciscid_done) // && (buffer_rptr == 16)) + else if(((cmd == 8'h49)||(cmd == 8'h4a)) && conf_buff_ptr[3:0] == 4'h0f) // && (buffer_rptr == 16)) read_state <= RD_STATE_IDLE; // return to idle state - - else - buffer_read_strobe <= 1'b1; // not done yet -> trigger read of next data byte + + else begin + buffer_ptr <= buffer_ptr + 1'd1; + conf_buff_ptr<= conf_buff_ptr+ 1'd1; + end end end endcase - + // ------------------ write support ---------------------- // send write data response if(write_state == WR_STATE_SEND_DRESP) @@ -306,19 +295,18 @@ always@(negedge sd_sck) begin if(write_state == WR_STATE_BUSY) sd_sdo <= 1'b0; end -end -// spi receiver -reg illegal_write_state /* synthesis noprune */; + if (buffer_write_strobe) begin + buffer_write_strobe <= 1'b0; + buffer_ptr <= buffer_ptr + 1'd1; + end -always @(posedge sd_sck or posedge sd_cs) begin + // spi receiver // cs is active low if(sd_cs == 1) begin bit_cnt <= 3'd0; - end else begin + end else if (~old_sd_sck & sd_sck) begin illegal_write_state <= 1'b0; - new_cmd_rcvd <= 1'b0; - buffer_write_strobe <= 1'b0; req_io_wr <= 1'b0; bit_cnt <= bit_cnt + 3'd1; @@ -338,7 +326,6 @@ always @(posedge sd_sck or posedge sd_cs) begin (read_state == RD_STATE_IDLE) && sbuf[6:5] == 2'b01) begin byte_cnt <= 4'd0; cmd <= { sbuf, sd_sdi}; - new_cmd_rcvd <= 1'b1; // set cmd55 flag if previous command was 55 cmd55 <= (cmd == 8'h77); @@ -434,16 +421,19 @@ always @(posedge sd_sck or posedge sd_cs) begin // waiting for data token WR_STATE_EXP_DTOKEN: - if({ sbuf, sd_sdi} == 8'hfe ) + if({ sbuf, sd_sdi} == 8'hfe ) begin write_state <= WR_STATE_RECV_DATA; + buffer_ptr <= 9'd0; + end // transfer 512 bytes WR_STATE_RECV_DATA: begin // push one byte into local buffer buffer_write_strobe <= 1'b1; + buffer_din <= { sbuf, sd_sdi }; // all bytes written? - if(buffer_wptr == 511) + if(&buffer_ptr) write_state <= WR_STATE_RECV_CRC0; end @@ -465,7 +455,7 @@ always @(posedge sd_sck or posedge sd_cs) begin WR_STATE_BUSY: if(wr_io_ack) write_state <= WR_STATE_IDLE; - + default: illegal_write_state <= 1'b1; endcase @@ -474,3 +464,38 @@ always @(posedge sd_sck or posedge sd_cs) begin end endmodule + +module sd_card_dpram #(parameter DATAWIDTH=8, ADDRWIDTH=9) +( + input clock_a, + input [ADDRWIDTH-1:0] address_a, + input [DATAWIDTH-1:0] data_a, + input wren_a, + output reg [DATAWIDTH-1:0] q_a, + + input clock_b, + input [ADDRWIDTH-1:0] address_b, + input [DATAWIDTH-1:0] data_b, + input wren_b, + output reg [DATAWIDTH-1:0] q_b +); + +reg [DATAWIDTH-1:0] ram[0:(1<= 2) && (byte_cnt < 6)) - SPI_MISO <= sd_lba[{5-byte_cnt, ~bit_cnt}]; - else - SPI_MISO <= 1'b0; - end - - // reading sd card write data - else if(cmd == 8'h18) - SPI_MISO <= sd_din[~bit_cnt]; - - else - SPI_MISO <= 1'b0; - end - end -end +//wire [7:0] spi_sck_D = { spi_sck_D[6:0], SPI_CLK } /* synthesis keep */; +//wire spi_sck = (spi_sck && spi_sck_D != 8'h00) || (!spi_sck && spi_sck_D == 8'hff); +wire spi_sck = SPI_CLK; // ---------------- PS2 --------------------- @@ -307,108 +261,210 @@ always@(negedge spi_sck or posedge status[0]) begin end end -// SPI receiver -always@(posedge spi_sck or posedge SPI_SS_IO) begin +// SPI bit and byte counters +always@(posedge spi_sck or posedge SPI_SS_IO) begin if(SPI_SS_IO == 1) begin - bit_cnt <= 3'd0; - byte_cnt <= 8'd0; - sd_ack <= 1'b0; - sd_dout_strobe <= 1'b0; - sd_din_strobe <= 1'b0; + bit_cnt <= 0; + byte_cnt <= 0; end else begin - sd_dout_strobe <= 1'b0; - sd_din_strobe <= 1'b0; - - if(bit_cnt != 7) - sbuf[6:0] <= { sbuf[5:0], SPI_MOSI }; - - bit_cnt <= bit_cnt + 3'd1; if((bit_cnt == 7)&&(byte_cnt != 8'd255)) byte_cnt <= byte_cnt + 8'd1; - // finished reading command byte - if(bit_cnt == 7) begin - if(byte_cnt == 0) begin - cmd <= { sbuf, SPI_MOSI}; - - // fetch first byte when sectore FPGA->IO command has been seen - if({ sbuf, SPI_MOSI} == 8'h18) - sd_din_strobe <= 1'b1; - - if(({ sbuf, SPI_MOSI} == 8'h17) || ({ sbuf, SPI_MOSI} == 8'h18)) - sd_ack <= 1'b1; - - end else begin - - // buttons and switches - if(cmd == 8'h01) - but_sw <= { sbuf[3:0], SPI_MOSI }; + bit_cnt <= bit_cnt + 1'd1; + end +end - if(cmd == 8'h02) - joystick_0 <= { sbuf, SPI_MOSI }; - - if(cmd == 8'h03) - joystick_1 <= { sbuf, SPI_MOSI }; - - if(cmd == 8'h04) begin - // store incoming ps2 mouse bytes - ps2_mouse_fifo[ps2_mouse_wptr] <= { sbuf, SPI_MOSI }; - ps2_mouse_wptr <= ps2_mouse_wptr + 1; - end +// SPI transmitter FPGA -> IO +reg [7:0] spi_byte_out; - if(cmd == 8'h05) begin - // store incoming ps2 keyboard bytes - ps2_kbd_fifo[ps2_kbd_wptr] <= { sbuf, SPI_MOSI }; - ps2_kbd_wptr <= ps2_kbd_wptr + 1; - end - - if(cmd == 8'h15) - status <= { sbuf[6:0], SPI_MOSI }; - - // send sector IO -> FPGA - if(cmd == 8'h17) begin - // flag that download begins -// sd_dout <= { sbuf, SPI_MOSI}; - sd_dout_strobe <= 1'b1; - end - - // send sector FPGA -> IO - if(cmd == 8'h18) - sd_din_strobe <= 1'b1; - - // send SD config IO -> FPGA - if(cmd == 8'h19) begin - // flag that download begins -// sd_dout <= { sbuf, SPI_MOSI}; - // sd card knows data is config if sd_dout_strobe is asserted - // with sd_ack still being inactive (low) - sd_dout_strobe <= 1'b1; - end - - // joystick analog - if(cmd == 8'h1a) begin - // first byte is joystick indes - if(byte_cnt == 1) - stick_idx <= { sbuf[1:0], SPI_MOSI }; - else if(byte_cnt == 2) begin - // second byte is x axis - if(stick_idx == 0) - joystick_analog_0[15:8] <= { sbuf, SPI_MOSI }; - else if(stick_idx == 1) - joystick_analog_1[15:8] <= { sbuf, SPI_MOSI }; - end else if(byte_cnt == 3) begin - // third byte is y axis - if(stick_idx == 0) - joystick_analog_0[7:0] <= { sbuf, SPI_MOSI }; - else if(stick_idx == 1) - joystick_analog_1[7:0] <= { sbuf, SPI_MOSI }; - end - end +always@(negedge spi_sck or posedge SPI_SS_IO) begin + if(SPI_SS_IO == 1) begin + SPI_MISO <= 1'bZ; + end else begin + SPI_MISO <= spi_byte_out[~bit_cnt]; + end +end - end +always@(posedge spi_sck or posedge SPI_SS_IO) begin + reg [31:0] sd_lba_r; + + if(SPI_SS_IO == 1) begin + spi_byte_out <= core_type; + end else begin + // read the command byte to choose the response + if(bit_cnt == 7) begin + if(!byte_cnt) cmd <= {sbuf, SPI_MOSI}; + + spi_byte_out <= 0; + case({(!byte_cnt) ? {sbuf, SPI_MOSI} : cmd}) + // reading config string + 8'h14: if(byte_cnt < STRLEN) spi_byte_out <= conf_str[(STRLEN - byte_cnt - 1)<<3 +:8]; + + // reading sd card status + 8'h16: if(byte_cnt == 0) begin + spi_byte_out <= sd_cmd; + sd_lba_r <= sd_lba; + end + else if(byte_cnt < 5) spi_byte_out <= sd_lba_r[(4-byte_cnt)<<3 +:8]; + + // reading sd card write data + 8'h18: spi_byte_out <= sd_din; + 8'h1b: + // send alternating flag byte and data + if(byte_cnt[0]) spi_byte_out <= serial_out_status; + else spi_byte_out <= serial_out_byte; + endcase end end end - + +// SPI receiver IO -> FPGA + +reg spi_receiver_strobe_r; +reg spi_transfer_end_r; +reg [7:0] spi_byte_in_r; + +// Read at spi_sck clock domain, assemble bytes for transferring to clk_sys +always@(posedge spi_sck or posedge SPI_SS_IO) begin + + if(SPI_SS_IO == 1) begin + spi_receiver_strobe_r <= 0; + spi_transfer_end_r <= 1; + end else begin + spi_receiver_strobe_r <= 0; + spi_transfer_end_r <= 0; + + if(bit_cnt != 7) + sbuf[6:0] <= { sbuf[5:0], SPI_MOSI }; + + // finished reading a byte, prepare to transfer to clk_sys + if(bit_cnt == 7) begin + spi_byte_in_r <= { sbuf, SPI_MOSI}; + spi_receiver_strobe_r <= 1; + end + end +end + +// Process bytes from SPI at the clk_sys domain +always @(posedge clk_sys) begin + + reg spi_receiver_strobe; + reg spi_transfer_end; + reg [7:0] spi_byte_in; + reg spi_receiver_strobeD; + reg spi_transfer_endD; + reg [7:0] spi_byte_inD; + reg [7:0] acmd; + reg [7:0] abyte_cnt; // counts bytes + + //synchronize between SPI and sys clock domains + spi_receiver_strobeD <= spi_receiver_strobe_r; + spi_receiver_strobe <= spi_receiver_strobeD; + spi_transfer_endD <= spi_transfer_end_r; + spi_transfer_end <= spi_transfer_endD; + spi_byte_inD <= spi_byte_in_r; + spi_byte_in <= spi_byte_inD; + + if(sd_dout_strobe) begin + sd_dout_strobe<= 0; + if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1; + end + + if(sd_din_strobe) begin + sd_din_strobe<= 0; + if(~&sd_buff_addr) sd_buff_addr <= sd_buff_addr + 1'b1; + end + + if (~spi_transfer_endD & spi_transfer_end) begin + abyte_cnt <= 8'd0; + sd_ack <= 1'b0; + sd_ack_conf <= 1'b0; + sd_dout_strobe <= 1'b0; + sd_din_strobe <= 1'b0; + sd_buff_addr<= 0; + end else if (~spi_receiver_strobeD & spi_receiver_strobe) begin + + if(abyte_cnt != 8'd255) + abyte_cnt <= byte_cnt + 8'd1; + + if(abyte_cnt == 0) begin + acmd <= spi_byte_in; + + // fetch first byte when sectore FPGA->IO command has been seen + if(spi_byte_in == 8'h18) + sd_din_strobe <= 1'b1; + + if((spi_byte_in == 8'h17) || (spi_byte_in == 8'h18)) + sd_ack <= 1'b1; + + end else begin + + // buttons and switches + if(acmd == 8'h01) + but_sw <= spi_byte_in; + + if(acmd == 8'h02) + joystick_0 <= spi_byte_in; + + if(acmd == 8'h03) + joystick_1 <= spi_byte_in; + + if(acmd == 8'h04) begin + // store incoming ps2 mouse bytes + ps2_mouse_fifo[ps2_mouse_wptr] <= spi_byte_in; + ps2_mouse_wptr <= ps2_mouse_wptr + 1; + end + + if(acmd == 8'h05) begin + // store incoming ps2 keyboard bytes + ps2_kbd_fifo[ps2_kbd_wptr] <= spi_byte_in; + ps2_kbd_wptr <= ps2_kbd_wptr + 1; + end + + if(acmd == 8'h15) + status <= spi_byte_in; + + // send sector IO -> FPGA + if(acmd == 8'h17) begin + // flag that download begins + sd_dout_strobe <= 1'b1; + sd_dout <= spi_byte_in; + end + + // send sector FPGA -> IO + if(acmd == 8'h18) + sd_din_strobe <= 1'b1; + + // send SD config IO -> FPGA + if(acmd == 8'h19) begin + // flag that download begins + sd_dout_strobe <= 1'b1; + sd_ack_conf <= 1'b1; + sd_dout <= spi_byte_in; + end + + // joystick analog + if(acmd == 8'h1a) begin + // first byte is joystick indes + if(abyte_cnt == 1) + stick_idx <= spi_byte_in[2:0]; + else if(abyte_cnt == 2) begin + // second byte is x axis + if(stick_idx == 0) + joystick_analog_0[15:8] <= spi_byte_in; + else if(stick_idx == 1) + joystick_analog_1[15:8] <= spi_byte_in; + end else if(abyte_cnt == 3) begin + // third byte is y axis + if(stick_idx == 0) + joystick_analog_0[7:0] <= spi_byte_in; + else if(stick_idx == 1) + joystick_analog_1[7:0] <= spi_byte_in; + end + end + end + end +end + endmodule diff --git a/cores/bbc/roms/mmfs.hex b/cores/bbc/roms/mmfs.hex new file mode 100644 index 0000000..a40d941 --- /dev/null +++ b/cores/bbc/roms/mmfs.hex @@ -0,0 +1,513 @@ +:200000000000004CAE8E821A7B4D6F64656C2042204D4D465300312E3431002843293230E1 +:200020003131204D61746865720055524F4D6C1E02A2068E40FEE88E40FE60200584A976BE +:200040004CF4FF205880004469736320902120588000426164209017ADDD10D003209D968F +:20006000A9FF8D82108DDD10A202A9008D0001203B806885AE6885AFA00020FE83B1AE8D25 +:200080000101CA20FE83E8B1AE9D0001302FD0F3206B8D4C000148A90D20E980686085B300 +:2000A0006885AE6885AFA5B3489848A00020FE83B1AE300620E9804CAD8068A868186CAE07 +:2000C0000085B36885AE6885AFA5B3489848A00020FE83B1AE300620E3FF4CD08068A86845 +:2000E000186CAE00200D81A92E20058448A9EC2051938A48091020419368AA6820E3FF4C18 +:20010000429320748448202A82200D8168202F81D0D720748448202A82201D8168202F812F +:200120004CE3FF20268148A92020E3FF681860290FC90A90026906693060204A81CACA2033 +:200140004281B1B09D7210E8C860204D81B1B095BAE8C86020528C4C6A8120528CA5BA8587 +:20016000F2A5BB85F3A00020CB81A22020B081B01B8D0010C92ED00486CCF0EEC93AD0154B +:2001800020658C20B081B004C92EF0DE204E80CC6E616D6500AA20B081B034C92EF0D9A2E8 +:2001A000019D0010E820B081B027E007D0F3F0DC20C5FF08297FC90DF008C92090CEC97F1A +:2001C000F0CA286086F284F3A00060184CC2FFA201A9209D0010E8E040D0F8A206BD00106B +:2001E00095C5CA10F860200584B90F0E08297FD005202381F00620E98020E780A206B9083C +:200200000E297F20E980C8CA10F4202381A920281002A94C20E980A00120268188D0FA60AA +:200220004A4A4A4A4A4A2903604A4A4A4A4A600A0A0A0A0A602054813003205A8120A682A7 +:20024000B0F2206880D64E6F7420666F756E640020C48120528C20CB81F00320348AA92A3E +:200260008D001020CF81201A92203D824C7F8220C481A94E85BF201A9220CC992035822091 +:200280005C8320A282B0F8602099A4A900F01EA206B5C59D5810CA10F8A9208D5F10A95860 +:2002A000D006A200F00CA900482099A468AAA90085B6A000A90E85B7A5B6CD050FB0496955 +:2002C0000885B620DD8290EAA5CCA007200A83D0E1A4B63888888888888888886020058491 +:2002E000BD0010CDCE10D013E820DD82B01BC8C00790F6BD0010C920D00E60C007B0F420DD +:200300000A83D004E8C8D0D81860CDCE10F010CDCD10F00B20498351B6B002295F297F6027 +:2003200008204983B002295F297F286020CE92B9100E99080EB9100F99080FC8CC050F9099 +:20034000EE98E9088D050F186048295FC9419004C95B90013868602CC61030EC2005842003 +:20036000E6819848A96085B0A91085B120A883A00220268120908320908320908368A8B9F3 +:200380000E0F2903200D81B90F0F2005814C9680A203B9621020058188CAD0F620BC884C49 +:2003A00026812005844CA1A42005849848AAA012A9008891B0C002D0F920F383C8C8C00E86 +:2003C000D0F768AABD0F0E1004A90891B0BD0E0FA00420E183A00C4A4A48290391B068A065 +:2003E000084A4A482903C903D005A9FF91B0C891B0686020F683BD080F91B0E8C860E6AE40 +:20040000D002E6AF60488A489848A98448A92748A005BABD07014888D0F8A00ABD09019DC4 +:200420000B01CA88D0F6686868A868AA6860488A489848201084BA9D03014C2884A6B8A0DF +:200440000084B68AC90A9010E90AAAF818986910A8D890EFE6B6B0EBF884B565B5A89003EB +:20046000E6B618A6B9F0096956A8A5B6690285B6D884B560202E84A8F00A18F8A900690100 +:2004800088D0FBD860297FC97FF004C920B002A92E609848A90085B085B120CB81F04EC9B4 +:2004A00022F04A20C5FFB04538E9303040C90AB03C48A5B00A4826B1A6B10A26B10A26B1A8 +:2004C00085B06865B085B08A65B1AA6865B085B08A690085B1C902B01420C5FF90CAA6B0ED +:2004E000A5B1F004E8F006CA68A5B1186068A8A900AA386020C481205D8C20A1A4A0FF84E3 +:20050000A8C884AAB9000EC0089003B9F80E20E980C8C00CD0EE209E802028A6CD2081AD3A +:20052000209E80290D447269766520A5CD200D81A00D201982209E804F7074696F6E20AD21 +:20054000060F202A8248200D81209E802028A003680A0AAABD408620E980E88810F6209E35 +:2005600080290D4469722E203AADCA1020E480ADC91020E980A00B201982209E804C696249 +:200580002E203AADCC1020E480ADCB1020E980209680A000CC050FB017B90F0E4DC9102913 +:2005A0005FD008B90F0E2980990F0E20BB8890E4A00020C2859016A9FF8D82104C96802002 +:2005C000BB88CC050FB005B9080E30F36084ABA200B9080E2020839D6010C8E8E008D0F128 +:2005E00020C285B02338A206B90E0E202083FD601088CA10F320BC88B90F0E202083ED6736 +:200600001090CA20BB88B0D8A4ABB9080E098099080EAD6710C5AAF010A6AA85AAD00A2023 +:200620009680209680A0FFD009A4A8D0F5A005201982C884A8A4AB20238120E6814CB08576 +:200640006F6666004C4F414452554E0045584543B90E0F20228285C218A9FF790C0FB90F28 +:200660000F790D0F85C3B90E0F290365C285C238B9070FE5C348B9060F2903E5C2AAA90033 +:20068000C5C068E5C18AE5C460FF414343455353B24241434B55508C434C4F534580434F07 +:2006A0004D5041435485434F5059AC44454C4554458844455354524F598244495286445277 +:2006C00049564581454E41424C4580455886464F524DDF4652454584494E464F824C49422D +:2006E000864D41508452454E414D458D5449544C458A56455249465985574950458200149C +:200700004255494C448844554D50884C49535488524F4D538B5459504588001A444953438C +:20072000804449534B804D4D465380001E445554494C53804D4D4653805554494C538000A4 +:2007400022424F4F54874341548E4452495645844652454580494EF44F50C94F55548452F5 +:20076000454341548041424F55548000A58A4F9CCA93F49AAC9C62887488E889CE881D8C3E +:200780005282F91D589F7582EC895B9F038D608AF51D3088C58787B308B3C6B28BB1BFB268 +:2007A0008786BE8DBE8DC88D5F8FB1997299B899BF99DF2D062E7D2FC92EF12D8730F72D79 +:2007C000402CBBAD1E89A2B720CB81B1F2C80920C964F009884C1F8920C481A200BD8986D0 +:2007E00085BE9848E6BE6848A820CB81E8BD8986F028CA8886BFE8C8BD8986301651F229DD +:200800005FF0F3CAE8BD898610FAB1F2C92ED0D4C8B007B1F220498390CA68A5BE0AAABD2C +:200820006D87100648BD6C874860206CAB0980D0F3201A9220CC99203582B90F0E301E201F +:20084000E681201D9CD013A6B620649486B620C48884AB20B2A4A5AB85B620968020A282AF +:20086000B0D86020119220CC99203582205783202C834CB2A420C99B201A9220CC992035DC +:2008800082B90F0E300620E68120968020A282B0F020259CF0034C968020649420A682B9DA +:2008A0000F0E300320C48820A282B0F320B2A4209E800D44656C657465640DC8C8C8C8C828 +:2008C000C8C8C860202C83A4B620D48284B66020628C8DCA1060290385CD60203A8220F088 +:2008E0009220A88384BAA200A5BED006C8C8A202D008B90E0F85C220248CB9080F95BCC820 +:20090000E8E008D0F5203B8CA4BA2057834C73A4204E8B20F09220A8834C8AA420C48120BB +:20092000DC898CDA10205A818CD910208882B022ACDA10ADCB1085CCADCC1020D688205D7D +:2009400081208882B00C204E80FE636F6D6D616E6400B90E0F202082C903D044B90A0F39E2 +:200960000B0FC9FFD03AA206BD00109D0710CA10F7A90D8D0E10A9458D0010A92E8D011030 +:20098000A93A8D0210A5CD09308D0310A92E8D04108D0610A5CC8D0510A200A0104CF7FFC8 +:2009A00020E48818ADD910A865F28DD910A5F369008DDA10AD76102D77100DD610C9FFF07E +:2009C00016A5BE8D7410A5BF8D751020618DA274A010A9044C0604A9016CBE00A9FF85BE81 +:2009E000A5F285BAA5F385BB60A200F002A20220238A9DCA10A5CC9DC91060200584A5B028 +:200A000048A5B148202693A000C0C09005B90010B003B9001191B0C8C0F0D0ED6885B168A0 +:200A200085B060ADC91085CC20CB81D007A90020D688F02AADCA1020D68820B081B010C9E7 +:200A40003AD01420658C20B081B013C92EF0EB204E80CE6469720085CC20B08190F1A5CDF1 +:200A60006020CC9920528C20A283A20BA90020878ACA10FAE820B081B00720878AE00B9057 +:200A8000F320B2A44C968A9D0010E00890049DF80E609D000E60201DA5A00BB9001091B0B3 +:200AA0008810F84CB2A5201A9220CC99205481A20020CB81D02486AA20A682B0034C428280 +:200AC00020D192B90F0E297F05AA990F0E20578320A282B0EB4CB2A4A28020B081B0D72912 +:200AE0005FC94CF0F3204E80CF617474726962757465002005848AC904F01EC905F034C945 +:200B000002900B204E80CB6F7074696F6E00A2FF98F002A2008EC61060984820528C20A1B6 +:200B2000A4682030824D060F29304D060F8D060F4CB2A49808A6F4BDF00D29BF28F0020977 +:200B4000409DF00D60204380C666756C6C00205A8120A6829003202C83A5C048A5C14838C7 +:200B6000A5C2E5C085C0A5C3E5C185C1AD7A10ED781085C4208A8BAD79108D7510AD781029 +:200B80008D74106885BD6885BC60A90085C2A90285C3AC050FC0F8B056206F864CA78BF0AD +:200BA000A420D4822050869890F584B0AC050FC4B0F00FB9070E990F0EB9070F990F0F880F +:200BC000B0EDA20020FC8BB5C599080EC8E8E008D0F5B5BB8899080FCAD0F7205783984896 +:200BE000AC050F20BB888C050F20B2A468A860205880BE4361742066756C6C00AD7610294F +:200C0000030A0A45C429FC45C40A0A4D741029FC4D74100A0A45C229FC45C285C260A90113 +:200C20008DC71060A9008D7510A5C229088D7410F008A9FF8D75108D741060A9008D7710AC +:200C4000A5C2202082C903D005A9FF8D77108D761060ADC91085CCADCA104CD68820CB8127 +:200C6000F0F520CC9920B081B012C93AF0F738E9309009C904B00520D6881860204E80CDF0 +:200C80006472697665004CD299204380D66E6F7420666F756E640020CC99C922D0018884F0 +:200CA000B420B081C93AD00520658C9021A4B420578C209284B02A20CB81F01CC922D001F6 +:200CC00088A5B1D0B7A5B0C904B0B120D688209284B00E20CB81D0AEA5B185B9A5B085B8AA +:200CE0006020BAACA90085B720C9A5AD0D10F096AD0E10D091A5B930902009AD90E220EDAC +:200D0000A54CF58C20119220CC992054819848203D8220CE9284C468A820CC99A5CD48202E +:200D2000548168C5CDD01420A6829012C4C4F00E205880C4457869737473004C7C8CA4C498 +:200D400020BB88A207B5C599070E88CA10F74CB2A4A9EAA200A0FF20F4FF8A49FF8DD61038 +:200D60006048A9CA20060490F9686020518D300748A98A200604686024FF101D20469320D2 +:200D80006880114573636170650048202A8220928D68202F81990001C8604C2E21424F4F41 +:200DA000540D452E21424F4F540DA5B3209E804D6F64656C2042204D4D46530D0D900CA665 +:200DC000F4BDF00D2940F00160A9FF20009648A906202E80A20DBD58939D1202CA10F7A906 +:200DE000A820519384B186B0A207A01BB94B9391B0C8B94B9391B0C8A5F491B0C8CAD0EC10 +:200E00008C82108C831086CD8E9F10A20F204D93202693A0D3B1B01037A0D4B1B0303A2001 +:200E20001193A000B1B0C0C09005990010B00399001188D0EF20B8A2CDEE10D016A9A0A88F +:200E400048A93F20839768991D11E91FD0F1F009201193207E8E209E8E20518D68D00B209A +:200E6000A1A4AD060F202A82D00160A08DA29AC9029008F004A2A2D002A2A44CF7FFA92443 +:200E80008DC9108DCB10A9038DCC10A0008CCA108CC010888CC7108CC6108CDD1060A00E39 +:200EA000A90099E0108810FAA9018DEE106020ECB548BDF00D301E68C912F031C90BB014CC +:200EC0000AAABDD88E48BDD78E488AA6F44AC90B90026915606860D38EF68EFD8E3E8F577B +:200EE0008FD38ED38ED38E638FB48FC58FC004D0E32005844CC98DC017B002A01760984875 +:200F000085B1BCF00D98294005B19DF00DA90085B0C4B1F004A0D391B0A9FD205193CA8A98 +:200F2000A0D331B091B008C8281007B1B0100320FB89A90091B0A6F468A8A902C8C86020A6 +:200F4000058484B3A97A20F4FF8A3009C965D0EEA97820F4FF4CAA8D200584A2924CDD87A8 +:200F6000A276D0F9200584A4EF3030C07D902C20009620E88FD024A6F086B0A6F186B1A47C +:200F8000EFC81007085820BEB0286020528C20A283C83008A000AD040F91B060A900A891E7 +:200FA000B0C8AD070F91B0C8AD060F290391B0C8A90091B060200584B1F2A2A3C90DD09DD8 +:200FC00098A0034C7899200584202693A0D4B1B01015A00020E79520FB89202693A0D4A927 +:200FE0000091B0BA9D050160A90720F08FE011606C1E02202E844820119286B08EDB1084B7 +:20100000B18CDC10A200A000204A81203A81C012D0F968AAE8E008B008BD9B9348BD939354 +:2010200048A90060C90CB0F986B5AABD879348BD7B93488AA6B560C909B0FB20058420003F +:20104000968E7D108C7E10A8205690082C8110100320708D2860B9A3938DD710B9AC938DB2 +:20106000D810B9B5934A084A088D7F1020C891A00CB1B49960108810F8AD63102D64100DD6 +:20108000D610186901F00620618D18A9FF8D8110AD7F10B007A261A01020060428B0042832 +:2010A0006CD710A203BD691095B6CA10F8A2B6AC6010A90028B00320D998204796A203B505 +:2010C000B69D6910CA10F820BA91300DAC601020A090B00DA20920AE91A20520AE91D0ECD5 +:2010E000180820BA91A20520AE91A00C20C891B9601091B48810F8286020528C2099A4A9B0 +:201100000B8DD710A9918DD810D0BCAC6910CC050FB028B90F0E20498345CCB00229DF2982 +:201120007FF00520BB88D0E6A90720DC9185B0B9080E20DC91C8C6B0D0F5188C6910AD0483 +:201140000F8D60106020528C2099A4A90C20DC91A000C008B005B9000E9003B9F80E20DC54 +:2011600091C8C00CD0ECAD060F202A8220DC91A5CD4CDC9120D391ADCA10093020DC912057 +:20118000D391ADC910D05520D391ADCC10093020DC9120D391ADCB10D04248AD611085B8AC +:2011A000AD621085B9A2006860200584A201A004FE6010D004E888D0F760A203A9FF5D6590 +:2011C000109D6510CA10F560AD7D1085B4AD7E1085B560A901D005200197B0F62C811010CC +:2011E000058DE5FE30C3209A9181B84CA99120F69120EF9718602C81101006ADE5FE4CA960 +:2012000091209A91A1B84CA9912CC7103003CEC710A9FF8DCE108DCD1060A92A8DCE10A974 +:2012200023D0F320DC9220A883A9016020B99220A883202C83902420DC92206192207D92DC +:20124000501620DC92207D92501120DC92206192500920DC9220D19220A09220D58AA90184 +:2012600060200584A002B1B09D080FC8B1B09D090FC8B1B00A0A5D0E0F290C101B20058410 +:20128000A006B1B09D0A0FC8B1B09D0B0FC8B1B06A6A6A5D0E0F29C05D0E0F9D0E0FB8609B +:2012A000200584A00EB1B0290AF002A9805D0F0E29805D0F0E9D0F0E6020E6929023B90F5E +:2012C0000E1022205880C34C6F636B65640020BE9220058420909590214CF49420E692B096 +:2012E000196868A90060205A8120A682900C98AAADDB1085B0ADDC1085B160A98320F4FFA0 +:201300008CCF10A98420F4FF9838EDCF108DD01060A20A204D93202693A0D3A9FF91B08D4B +:20132000D310C891B06048A90085B0A6F4BDF00D293F85B16860200584A90FA201A000F0ED +:2013400014AAA903D00F200584A97ED008A98FD004A200A0FF4CF4FF1BFF1EFF21FF24FF96 +:2013600027FF2AFF2DFFF38F000D9600019700EF97003790007E9400249000F2C91BD71B5A +:20138000F3C2BD084F6E1B8A9689878984939392828289DA0F36494151222B88899292926B +:2013A00092929288EEEED7D7457487F9869191919191919190040203060704040404A21146 +:2013C000A01560200584A9774CF4FFA9208D861020C693A900186920F0E8A820EB93D0F55E +:2013E000A9208D861098F0E820E29648206696B046B91B1149FF2DC0108DC010B91711290E +:2014000060F034203C94B917112D8610F026AEC310B914119D0C0FB915119D0D0FB916110F +:201420002030825D0E0F29305D0E0F9D0E0F20B2A4ACC210208B97AEC5106860205794A2A5 +:2014400006B90C1195C58888CA10F6208F8290228CC310ACC21060B90E11297F85CCB917B5 +:20146000114CD688200584AD040F20A283CD040FF0E4204380C86368616E6765640029C0F1 +:20148000D0062005844CE093202E8486BA84BB85B424B408205A8120119220A682B02428A2 +:2014A0005003A9006008A900A20795BC9D7410CA10F8C6BEC6BFCE7610CE7710A94085C34F +:2014C000204E8B2808700320BE92209095900EB90C1110202808301C208B95B0F2ACC2103B +:2014E000D01B205880C0546F6F206D616E79206F70656E00205880C24F70656E00A9088DE6 +:20150000C410BD080E990011C8BD080F990011C8E8CEC410D0ECA210A900990011C8CAD0BF +:20152000F9ADC210A82029826911991311ADC110991B110DC0108DC010B9091169FFB90B0D +:20154000116900991911B90D11090F6900202282991A1128502E3008A980190C11990C117B +:20156000B90911991411B90B11991511B90D11202282991611A5CD19171199171198202996 +:2015800082091060A920991711D0EA8A484CCF95A9008DC210A90885B598AAA0A084B38A54 +:2015A00048A90885B2A5B52CC010F01DB9171145CD2903D01ABD080E590011297FD010E8E2 +:2015C000C8C8C6B2D0EF38B0108CC2108DC11038A5B3E92085B306B51868AAA4B3A5B5B079 +:2015E00002D0BA60200096ADC01048A9008D861098D00520D393F00320E093688DC010601A +:20160000488A48A900BA9D090168AA6860200584C9FFF0D0C000F00EC903B023200096C9BF +:2016200001D0244CD998C902B015200096F011A9FF95029503ADD9109500ADDA1095016022 +:20164000A904BA9D05016020E2968CC2100A6DC210A8B910119500B911119501B9121195E8 +:2016600002A900950360488EC5109829E08DC210F013202982A8A900386A88D0FCACC21089 +:201680002CC010D0036838606818604898C9109004C9189002A908202F82A86860A9C6205A +:2016A00051938AF00920C196D004A9C6D00CA9C720519320C196D011A9C7A200A0004CF46F +:2016C000FF8AA8208B96CCC210604898488AA820E29698204B99D004A2FFD002A20068A813 +:2016E0006860208B9620669690F7209D96205880DE4368616E6E656C00205880DF454F46AB +:2017000000202E8420E29698204B99D013B917112910D0E5A910207C97AEC510A9FE386063 +:20172000B91711300A205794208B9738209397B9101185BAB9131185BBA000B1BA48ACC2C8 +:2017400010A6BAE88A991011D01418B911116901991111B912116900991211208197186838 +:201760006018B90F1179111185C3991C11B90D11290379121185C2991D11A980191711D088 +:2017800005A97F3917119917111860B917112940F0451808EEDD10ACC210B9131185BDA9C2 +:2017A000FF8D74108D7510A90085BC85C0A90185C128B017B91C1185C3B91D1185C2208AF3 +:2017C000A4ACC210A9BF20839790062061972073A4CEDD10ACC210604CC392205880C1521B +:2017E000656164206F6E6C79002005844CF59720058420E29648B90C1130E0B90E1130D80D +:2018000020579498186904204B99D066203F94AEC31038BD070FFD0F0F48BD060FFD0E0F98 +:201820002903D91A11D01F68D91911D03484B48CC210209D96205880BF43616E2774206548 +:201840007874656E6400B91A11186901991A110A0A0A0A5D0E0F29305D0E0F9D0E0F68A9FB +:20186000009D0D0F991911A9009D0C0F20B2A4ACC210B917113017208B97B91411D00B98DC +:20188000204B99D005206197D00438209397B9101185BAB9131185BB68A00091BAACC210FA +:2018A000A940207C97E6BAA5BA991011D013208197B911116901991111B912116900991248 +:2018C0001198204B999011A920207C97A202B91011991411C8CA10F66020058420E296AC9D +:2018E000C210206399B02FB91411991011B91511991111B91611991211202599A5B648A527 +:20190000B748A5B848A90020E9976885B86885B76885B64CE298B500991011B50199111148 +:20192000B502991211A96F208397B90F117911118DC410B90D112903791211D91D11D098FF +:20194000ADC410D91C11D0904C7A97AAB91211DD1611D00EB91111DD1511D006B91011DD70 +:20196000141160B91411D500B91511F501B91611F5026098A200A01448209E800D4D4D46C2 +:20198000532086BF84B7A200BD1680F00620E980E8D0F5A90D20E980A90085B9A0012050FC +:2019A0009A20EB99209680C6B7D0ED68A8A2A34CDD8798A2B7A008D0BF98A276A005D0B86F +:2019C00020CB81F07820B08190FBB0E120CB81F00160206880DC53796E7461783A2086B905 +:2019E00020EB99A900203E9A4C0001A90785B8A6BFE0B79005A944203E9AE8BD8986300608 +:201A0000203E9A4CFA99A4B8300320509A86BFBD8986297F201A9A202A82200584290FF02C +:201A20001CA8A920203E9AA2FFE8BD5D9A10FA88D0F7297F203E9AE8BD5D9A10F7602005C3 +:201A400084A6B9F006E6B99D000160C6B84CE980A5B9D008A920203E9A8810FA60BC647262 +:201A60006976653EBC616673703EA84C29A83C64726976653E29A83C64726976653E292E2B +:201A80002E2EA83C6469723E29BC646E6F3E2F3C6473703EBC6673703ED02F552F4E2F4BA7 +:201AA0002F52BC7469746C653EA83C726F6D3E29BC736F757263653E203C646573742E3EED +:201AC000BC6F6C64206673703E203C6E6577206673703EA8283C662E646E6F3E29203C74FF +:201AE0002E646E6F3E2920283C616473703E29B4302F3830FF205D8C209E80436F6D7061CC +:201B00006374696E67203A8DD1108DD210200D81209680A00020EB9320FB9220A283AC05B4 +:201B20000F84CAA90285C8A90085C9A4CA20D482C0F8D028AD070F38E5C848AD060F2903E7 +:201B4000E5C9200D8168200581209E80206672656520736563746F72730DEA6084CA2057DC +:201B600083A4CAB90C0FC901A90085BC85C0790D0F85C4B90E0F0820228228690085C5B993 +:201B80000F0F85C6B90E0F290385C7C5C9D014A5C6C5C8D00E1865C485C8A5C965C585C9D2 +:201BA0004CC19BA5C8990F0FB90E0F29FC05C9990E0FA90085A885A920B2A420719D209979 +:201BC000A4A4CA205C834C2B9B2CC710104B20259CF00268684C968020628C8DD110206281 +:201BE0008C8DD210CDD110F031984820FB92209E80436F7079696E672066726F6D203AAD9C +:201C0000D110200D81209E8020746F203AADD210200D8120968068A818604C7C8C209E800D +:201C2000203A20900F209E80476F2028592F4E29203F20EA20369320E0FFB00E295FC95997 +:201C400008F002A94E20E98028604C7C8D4C458B20D89B20C99BA90085C785C985C885C61F +:201C600085A8ADD11085CD20A1A4AD070F85C4AD060F290385C5ADD21085CD20A1A4AD06B5 +:201C80000F2903C5C590C6D007AD070FC5C490BD20719D20A1A4A20AE0089005BDF80EB08A +:201CA00003BD000E9D0010CA10EE4C968A201A9220D89B20CC99205481ADD11020D6882070 +:201CC0003D82A5CC48A5B685AB205C83A200B9080E95C59D5010B9080F95BB9D4710E8C876 +:201CE000E008D0EAA5C120228285C3A5BF1869FFA5C0690085C4A5C3690085C5AD4E10852A +:201D0000C6AD4D10290385C7A9FF85A820719DADD11020D68820A283A5AB85B66885CC20C3 +:201D2000A282B09E6020609DADD21085CDA5CC4820A283208F829003202C836885CC202445 +:201D40008C203B8CA5C220228285C4208A8BA5C2290348A5C34820609D6885C86885C960F4 +:201D6000A211BD4510B4BA95BA989D4510CA10F260A90085BC85C0F06DA5C4A8CDD010A53C +:201D8000C5E9009003ACD01084C1A5C685C3A5C785C2ADCF1085BDADD11085CD20ED9D2053 +:201DA00073A4ADD21085CD24A8100720259DA90085A8A5C885C3A5C985C2ADCF1085BD2038 +:201DC000ED9D208AA4A5C11865C885C89002E6C9A5C11865C685C69002E6C738A5C4E5C178 +:201DE00085C4B002C6C5A5C405C5D08D60A9FF8D74108D751060A900F002A9FF85C985B27A +:201E0000101820CC99209284B00D0AD00A86B5E028F007E050F0034CD29920CB8184CAD0A0 +:201E20004B24C9300B209E80566572696679900A209E80466F726D6174EA209E8020776814 +:201E4000696368206472697665203F20EA20E0FFB031C920903020E98038E9309028C904C3 +:201E6000B02485CD209680A4CA4C6F9E20658C84CA24B2100320C99B20899EA4CA20CB8152 +:201E8000D0EA604C7C8D4C7C8C24C930112071A3209E80566572696679696E679017206EF7 +:201EA000A320239F209E80466F726D617474696E67A6CD86B2209E8020647269766520A55C +:201EC000CD200D81209E8020747261636B202020EA24C9300820349F8AF04585B5A2FF8E8A +:201EE0008210E886B4A90820E98020E980A5B420058120CCA4E6B4A5B4C5B5D0E824C910BA +:201F00001F20CAAF20239FA5B5C928D006A001A290D004A003A2208E070F8C060F20B2A43F +:201F20004C9680A0FF8C8210C89899000E99000FC8D0F76020A1A4AD060F2903AAAD070F24 +:201F4000A00A84B0A0FF38C8E5B0B0FBCA10F765B04898AA68F001E86038B0011866C62066 +:201F60005D8C20A28324C6301520C18041646472657373203A20204C656E6774680DAD0621 +:201F80000F290385C585C2AD070F85C438E90285C1B002C6C2A90285BBA90085BC85BF8528 +:201FA000C0AD050F29F8A8F028D0112048A020D482A5C438E5BBA5C5E5BC9015B9070F3868 +:201FC000E5BB85C108B9060F290328E5BC85C290DA84BD24C63009A5C105C2F0032024A037 +:201FE000A5C11865BF85BFA5C265C085C0A4BDD0BA24C6102EA8A6BFA9F838ED050F20739D +:20200000A020C180467265650DA5C438E5BFAAA5C5E5C0A8AD050F2073A020C18055736508 +:20202000640DEA60A5BC201D81A5BB20158120C18020202020203A2020A5C2201D81A5C1AA +:20204000201581A90D20E3FFB9060F4820228285BC6829031865BC85BCB9040FF002A90181 +:202060001879050F9002E6BC1879070F85BB9002E6BC60202B8220128120C1802046696CF0 +:2020800065732086BC84BD98201D818A20158120C18020536563746F727320A90085BB853D +:2020A000BEA21F86C1A2099D0010CA10FA06BB26BC26BD26BEA200A009BD00102AC90A901F +:2020C00002E90A9D0010E88810EFC6C110DFA020A205D002A02CBD0010D008C02CF004A946 +:2020E00020D005A02C18693020E3FFE003D0049820E3FFCA10DC20C18020427974657320BD +:20210000EA60A2FFD002A200A0FF8C821085B086B1203B806885B86885B9A0008C9F108CAA +:202120000001C8F007B1B8990001D0F6A5B0208A8DA5B1F018A92F990001C8AD8910208A02 +:202140008DAD8A10208A8DAD8B10208A8DA9009900014C0001A9DD8D8210A90085BE85BF90 +:2021600085C0207BA9206CA1F00F1860ADFE0FC955D005ADFF0FC9AA60AD000EC9EBD00EAA +:20218000AD020EC990D007AD0C0EC902F032ADC60F0A85BEADC70F2A85BFADC80F2AB00F71 +:2021A00085C0ADC90FD008207BA9206CA1F011206880FF4361726420666F726D61743F00A2 +:2021C000AD0B0ED0EAAD0C0EC902D0E3AD110E85C1AD120E4A66C14A66C14A66C185C2AD14 +:2021E0000D0E85C3AD0E0E0A2E0F0EB0C265BE85BEAD0F0E65BF85BF9002E6C0AD110E0D43 +:20220000120EF014AD160E8D240EAD170E8D250EA9008D260E8D270E0E240E2E250E2E2657 +:202220000E2E270EB089AE100E18A5BE6D240E85BEA5BF6D250E85BFA5C06D260E85C0CA6E +:20224000D0E7207BA93860A20086C4A90E85C5E8A00BB1C4290FD00D88B9F010D1C4D00536 +:202260008810F6301018A5C4692085C4D0E2E6C5CA10DD386018A5BE65C185BEA5BF65C222 +:2022800085BF9002E6C0A01BB1C44888B1C438E90285C468E90085C505C4F01A06C426C5BE +:2022A000A6C318A5BE65C485BEA5BF65C585BF9002E6C0CAD0EC1860A00DA90059E0100A1D +:2022C000A207900249120ACAD0F8900249128810EB09016020058420B8A2CDEE10D00160D3 +:2022E000204E80FF53756D0020058420B8A28DEE1060A20A203EA32013A98DED108CEC1013 +:20230000A9008DEB1020E8A22055A190052047A2B017A5BE8DE810A5BF8DE910A5C08DEAB9 +:2023200010A9FF8DEB104CE8A2206880FF496D616765206E6F7420666F756E642100A00A25 +:20234000B94AA399F0108810F76042454542202020204D4D42A6CDBDE4100A30266020726F +:20236000A3BDE01085B8BDE410290185B96038B00118A6CDBDE41010182908B003D01E60D8 +:20238000F02D60204380C972656164206F6E6C7900206880C74E6F20646973630020438064 +:2023A000C76E6F7420666F726D617474656400204380C7616C726561647920666F726D615E +:2023C00074746564002071A3BDE4106ABDE01008AAA90085BE2A4885C08A0A26C085BF8AB3 +:2023E00065BF85BF68690065C085C066BE8A286A66BE4A66BE4A66BE65BF85BFA5C06900C4 +:2024000085C038A5BE091F6DE81085BEA5BF6DE91085BFA5C06DEA1085C06020C5A318AD40 +:20242000971065BE85BEAD961029034865BF85BF9002E6C0AD951085CEAD96104A4A4A4A08 +:20244000290385CFAD941085C3F006E6CED002E6CF18AD971065CEAA6865CFC9039006D01B +:2024600005E021B00160204380FF6F766572666C6F77002075AB201BA420D6A9AD9E10F0E6 +:202480000320708D20E4ABA901602075AB201BA42055A32082AA4C7CA4AD8210C5CDD001D2 +:2024A000602075AB20C5A3207BA9A5CD8D82104CE4ABAD040F18F869018D040FD82075AB52 +:2024C00020C5A32055A32092A94CAAA4A5B4D005A6CD20C8A3A90585B624C93006207BA9EB +:2024E0004CE6A42092A9E6BEE6BED006E6BFD002E6C0C6B6D0E360A5B96AA4B8C898D0018C +:20250000382A2A2A2A2A48291FA8686A29F085B0982901090E85B19829FE09806018205E0C +:20252000A320F7A420A4A5A00FB1B0C9FFF002AA60204380C76E756D626572206E6F74203C +:2025400076616C6964008A48A203BDE010C5B8D00CBDE4102901C5B9D0039DE410CA10EA6D +:2025600068AA60A9C085B72021A5F00A1004A9C8D002A98085B720D4A22046A5A6CDA5B837 +:202580009DE010A5B905B79DE4104CE8A2297E186DE81085BEADE910690085BFADEA106963 +:2025A0000085C060CD8210F0FA8D8210208DA54C7BA9AD8210208DA54C92A9203D8420F73C +:2025C000A485B220A4A54C1FA6A90085B585B685B885B9A91085B0A90E85B1A98085B220B2 +:2025E000A4A54C1FA6C9FFF03E24B7303818A5B0691085B0D016A5B1490185B16AB00DA5A5 +:20260000B26902C9A0F02085B220A4A5E6B8D002E6B9F818A5B5690185B59002E6B6D8A0C1 +:202620000FB1B030C01860A9FF85B93860A9038D60FEAD62FE09038D62FE2077A7A91C8D17 +:202640006EFE602088A7A9042C6DFEF0FB2077A7AD6AFE608E60FE8D60FE8E60FE8D60FECF +:202660008E60FE8D60FE8E60FE8D60FE8E60FE8D60FE8E60FE8D60FE8E60FE8D60FEAD6A10 +:20268000FE600A2A29FD8D60FE09028D60FE2A29FD8D60FE09028D60FE2A29FD8D60FE092C +:2026A000028D60FE2A29FD8D60FE09028D60FE2A29FD8D60FE09028D60FE2A29FD8D60FE90 +:2026C00009028D60FE2A29FD8D60FE09028D60FE2A29FD8D60FE09028D60FE60A002A201FD +:2026E0002043A688D0FA60A200A007BD87102082A6E888D0F620FBA64C54A6A201A0008832 +:20270000F00FA9038E60FE8D60FEAD6AFE2901D0EEA90360A2012043A6C9FED0F960A200F0 +:20272000F002A6C32088A7A000AD9E10D00A205CA791BCC8CAD0F760205CA78DE5FEEAEA8A +:20274000EAC8CAD0F360A2FF8E8210E82088A7A000205CA799000EC8CAD0F660A904E00132 +:20276000F0092C6DFEF0FBAD6AFE602C6DFEF0FB2077A7AD6AFE60AD6BFE29E38D6BFEAD6F +:2027800062FE09028D62FE60AD62FE29FD8D62FEAD6BFE29E309088D6BFEAD6AFE6020DCC7 +:2027A000A6A9FE4C82A620DCA620FBA62066A6A8291FC905D030A2012043A6C9FFD0F9606E +:2027C000AC9E10D009B1BC2082A6C8D0F860A000ADE5FE2082A6C8D0F760A000B9000E2033 +:2027E00082A6C8D0F760982002A1C54D4D4320577269746520726573706F6E736520666124 +:20280000756C7420008D8810A9008D89108D8A108D8B108D8C10A9FF8D87108D8D108D8EC6 +:202820001060203180A9008D9F10A93285C2A00A20DEA6A9402005A8A9958D8D1020E7A637 +:202840002981C901F0034CEEA8A9018DDE10A9482005A8A9018D8B10A9AA8D8C10A9878D41 +:202860008D1020E7A6C901F024A9028DDE10A9412005A820E7A6C90290034CEEA824FF3013 +:202880006DC900D0E9A9028DDE104CD5A82043A62043A62043A62043A6A9772005A820E742 +:2028A000A6A9692005A8A9408D891020E7A6C900D0E7A97A2005A820E7A6C900D03020438E +:2028C000A62940482043A62043A62043A668D005A9028DDE10A9502005A8A9028D8B10206A +:2028E000E7A6D016A9408D9F10203B801860C6C2F0034C2EA8203B8038602002A1FF536563 +:202900007420626C6F636B206C656E206572726F722000A94A2005A82033A9A01020DEA63F +:202920002043A6A84C43A6A958D002A9512005A84CEFAB20E7A6D0034C14A72002A1C54DD5 +:202940004D432052656164206661756C74200020E7A6D0034C9EA72002A1C54D4D43205702 +:2029600072697465206661756C742000203180A9008D9E1085BCA90E85BD60206CA9202B78 +:20298000A92033A9201EA7E6BD201EA720DCA64C3B80206CA92027A9204FA920C0A7E6BD15 +:2029A00020C0A720A6A74C3B8048AD90108D7210AD91108D7310AD74102D75100DD61049FB +:2029C000FF8D9E1038F00D20618DA272A010684820060418686020318020E0A94C3B80601B +:2029E000A6CED004A5CFF0F7A90120A9A9A6CE66BE66C21007E886CED002E6CF06BE202B6F +:202A0000A9A5CFD00EA6CEE003B008A5C3D043E001F03624C2100D2033A9A00084C220DE47 +:202A2000A64C2CAA2033A9201EA7E6BD201EA7E6BD20DCA62023ACA9FE2021ABF0A1A5CF99 +:202A4000D0E2E003B0DE4C0BAA2033A9201EA74C79AA2033A924C21008A00020DEA64C6A0E +:202A6000AAC6CEF005201EA7E6BD2022A79849FFA8C820DEA6A5CED005A00020DEA64CDC0A +:202A8000A660203180208BAA4C3B80A6CED004A5CFF0EEA90020A9A9A6CE66BE6A06BE4840 +:202AA0002027A9681032A9518D88102033A92046A7A00020DEA6A00220DEA6A9588D8810A4 +:202AC000204FA920DAA720C0A720A6A7A9FF2021ABF0AEE6BD2023ACA5CFD02DA6CEF04070 +:202AE000CAD026A9518D88102033A9A00020DEA62046A7A00220DEA6A9588D8810204FA926 +:202B000020C0A720DAA74CA6A7204FA920C0A7E6BD20C0A7E6BD20A6A7A9FE2021ABD0B503 +:202B2000601865CE85CEAAA9FF65CF85CF05CE60203180A9008D9E10A202B5B395BECA109C +:202B4000F9202BA92033A9A90085BCA91085BDA90885C32022A7A0F820DEA6A90885BC8512 +:202B6000C32022A7A0FA20DEA64C3B802005842075AB4CE4ABA209B5BC9D9010CA10F82055 +:202B80002DA62C9F1070082022A8B01220B9AB20D4A2ADEB10F0016020F2A24CA8AB206875 +:202BA00080FF436172643F00A90085B9A20386CD86B82063A5CA10F66020D4A2ADEB10F03A +:202BC0000D2013A9CDED10D006CCEC10D00160A9008D9F10206880FF57726F6E6720636196 +:202BE00072642100A209BD901095BCCA10F860ADDE10C902D015A5C08D8910A5BF8D8A10F2 +:202C0000A5BE8D8B10A9008D8C1060A9008D8910A5C04A8D8A10A5BF6A8D8B10A5BE6A8D02 +:202C20008C1060ADDE10C902D011EE8B10EE8B10D008EE8A10D003EE891060EE8C10F0EDBE +:202C400060A98085B220A9A5A91085B0A90E85B1A9001820CFA3A203B5BE95B3CA10F9A045 +:202C60000FB1B0C9FFF0472030AB18A5B3692085B3A5B4690385B49002E6B5A00BB900101A +:202C800091B08810F818A5B0691085B0D0D1A5B1490185B16AB0C820B2A518A5B26902C9D5 +:202CA000A0F01685B220788D20A9A54C5FACA5B0D00466B190034CB2A560A2008E0E101811 +:202CC00020C2FFF02020C5FFB01BC92AF024C9619006C97BB00249209D0010E8E00CD0E5F8 +:202CE00020C5FF9012C90DD01DA9009D00108E0D10608D0E10F0E9206880FF426164207305 +:202D00007472696E67004CD299A000AE0D10F017B1B0F025C9619006C97BB0024920D900F8 +:202D200010D016C8CAD0E9B1B0F00CAD0D10C90CF005AD0E10F00218603860B005A92020F6 +:202D4000E980A2202095ADA92020E980A00FB1B03025A000B1B0F00820E980C8C00CD0F455 +:202D6000A92020E980C8C00DD0F8AAA00FB1B0D002A2508A4CE980A00D201982A9554CE94C +:202D800080202E84BDE01085B8BDE410290185B9203D84A200A004A5B6209EADA5B5484A05 +:202DA0004A4A4A20A7AD68290FF008A2301869304CE98088D002A2308A4CE980209E804404 +:202DC0005554494C53206279204D617274696E204D6174686572202832303131290DEA60CF +:202DE00020CC99A90085CD20CE8C2063A5A9004CCB8D20978C4C63A5205D8C20D4A2A6CDBB +:202E00008A9DE4104CE8A2A90085B785AA85AB209284B02586A886B885A985B9209284B0B4 +:202E20001F86A885A9E4B8E5B9101B206880FF4261642072616E676500A2FE86A8E886A992 +:202E4000A90085B885B9E6A8D002E6A920BAAC20BBA5A200AD0D10D004CA8E0E10A5B93015 +:202E60002AA5B8C5A8A5B9E5A9B0202009ADB012203BADF818A5AA690185AAA5AB690085CC +:202E8000ABD820788D20EDA54C5DAEA98620F4FFE000F003209680A5ABA200A004209EAD35 +:202EA000A5AA209EAD209E802064697363A5ABD004C6AAF005A97320E980209E8020666FF6 +:202EC000756E64EA4C96804CD29920CB81D0F8A20086A886A986AA86ABA98020A4A5A910C9 +:202EE00085B0A90E85B1A00FB1B0C9FFF03CF8A8100B18A5A8690185A89002E6A918A5AA6D +:202F0000690185AA9002E6ABD818A5B0691085B0D0D4A5B1490185B16AB0CBAD82106902F9 +:202F2000C9A0F00620A4A54CE6AEA004A200A5A9209EADA5A8209EAD209E80206F6620A23D +:202F400000A004A5AB209EADA5AA209EAD209E802064697363A5ABD006A5AAC901F005A97A +:202F60007320E980209E8020667265652028756E666F726D617474656429EA4C968084B3B8 +:202F8000A9FF85B7A90385CDA4B320CB81F00520658C9002A90048AAA93A20EEFF188A695E +:202FA0003020EEFFBDE4101014290185B9BDE01085B820BBA5C9FFF00438203BAD20E7FF2B +:202FC00068C5CDF004690190CD6038201EA51027A900A891B0C8C00FD0F998D00FA900F088 +:202FE00002A90F48201DA5300B68A00F91B020B2A54C63A54C9DA34CAFA320C99B201DA5FF +:203000002055A320BBA5209E804B696C6CEA38203BAD209E80203A20EA20349C0820968054 +:2030200028D006A9F0484CE4AF60A90F4838201EA530B610C22070B0B0242063A5209E8025 +:203040004469736320A2002095AD209E8020696E203AA5CDA200A002209EAD4CE7FF20685F +:2030600080FF4E6F206672656520646973637300A9FF85B720C9A5B00EC9F0F00920EDA588 +:20308000B005C9F0D0F7186020CB81F00AA20ADDAAB0F006CA10F84C038B8A29FEAABDB5CB +:2030A000B048BDB4B048C84C5D8C72526B4B6E4E7555705029B0F9AF34B0E0AFDCAFA001D2 +:2030C000A202203A81A00084C384CFB1B0300320D688206CABA005B1B018690785B220EB1E +:2030E000B0A4B291B0A90060A90060A6CDBDE41010212908D01AC8B1B085B3C953F01AC9B7 +:2031000057F016C94BD0E1BDE4100A100CA91260A91E60A91060A9FF60A5B2C90AD0F7A9B9 +:203120000085B5C8B1B0C950B0E60A85B40A26B50A26B565B485B49002E6B5C8B1B0C90AF5 +:20314000B0CE1865B485B49002E6B5C8B1B0291FF03185CE188871B0C90BB0B4A6CD20C821 +:20316000A318A5BE65B485BEA5BF65B585BF9002E6C0A5B3C94BF00E20D6A9AD9E10F00384 +:2031800020708DA900602082AA4C7BB1A90085A820ADB2A90F85AA20A0B23820C2FF84AB4F +:2031A00018F01F209284B01AC900D0F7E010B0F38A84AB85AA2016B2A4AB20CB8184ABD03B +:2031C000E26066A824A8100520D5B190032016B2C6AA10F060A90985F6A98085F7A4ABB1FB +:2031E000F2C90DF022C922F01EC8C92AF02620208385AE2092B2F00DA6AEE023F0E120206C +:2032000083C5AEF0DA18602092B2F008C920F0F7C90DD0F13860A4AAB1B4F0E948209E8009 +:20322000526F6D2098200281209E80203A20A92820E98068483004A020D002A0539820E9E9 +:203240008068A0200A1002A04C9820E980A92920E980202681205DB22096803860A9078549 +:20326000F6A98085F72092B285AEE6F6A01E2085B2B007202681882085B260C920B002A92A +:203280002020E98088A5F6C5AEB0062092B2D0EB18609848A4AA20B9FFE6F6AA68A88A601C +:2032A000202E84A9AA20519386B484B560BAA9009D070160A6F4BDF00D293F85ADE6AD60C9 +:2032C00020CFB3A900F00520CFB3A9FF85ABA94020CEFFA8A90DC000D01E4C428220D7FF4C +:2032E000B01EC90AF0F728D0084820FAB32026816820E3FF24FF301F25ABC90D084CDDB205 +:203300002820E7FFA9004CCEFF20CFB3A94020CEFFA8F0C620B4B224FF3064A5A9200EB47A +:20332000A5A8200EB4202681A90885ACA20020D7FFB00D81AC200EB4202681C6ACD0EF1841 +:20334000089013A92A20E3FF20E3FF202681A90081ACC6ACD0ED206CB320E7FFA9081865AC +:20336000A885A89002E6A928B09A90ABA90885ACA200A1AC20858420E3FFC6ACD0F26020FA +:2033800046932004B34C7C8D20CFB3A98020CEFF85AB20FAB320268120B4B2A2ACA0FF84B5 +:2033A000AE84B0C884ACA92085AF9820F1FF0884AAA4ABA200F007A1AC20D4FFE6ACA5AC4D +:2033C000C5AAD0F328B0B8A90D20D4FF4C92B3BAA9009D070120F3B3C90DD0034CD299A91A +:2033E0000085A885A948981865F2AAA5F36900A86860C8B1F2C920F0F960F818A5A86901A4 +:2034000085A8A5A9690085A9D8200EB4A5A848202A822016B468202F8120E3FF3860370587 +:203420009605F2050706270668065E052D0520054205A905D105868896981818821820C5E2 +:2034400006A820C50620D4FF4C9C0520C506A820D7FF4C3A0520E0FF6A2095062A4C9E05A2 +:2034600020C506F00B482082056820CEFF4C9E0520C506A8A90020CEFF4C9C0520C506A88A +:20348000A20420C50695FFCAD0F820C50620DAFF209506A203B500209506CA10F84C36006D +:2034A000A200A00020C506990007C8F004C90DD0F3A0076020820520F7FFA97F2CE2FE50A2 +:2034C000FB8DE3FE4C3600A21020C5069501CAD0F820820586008401A00020C50620DDFF03 +:2034E000209506A210B501209506CAD0F8F0D5A20D20C50695FFCAD0F820C506A00020D15B +:20350000FF48A20CB500209506CA10F8684C3A0520C506AA20C50620F4FF2CE2FE50FB8E09 +:20352000E3FE4C360020C506AA20C506A820C50620F4FF499DF0EB6A2095062CE2FE50FBC5 +:203540008CE3FE70D520C506A82CE2FE10FBAEE3FECA300F2CE2FE10FBADE3FE9D2801CA42 +:2035600010F298A228A00120F1FF2CE2FE10FBAEE3FECA300EBC28012CE2FE50FB8CE3FEDF +:20358000CA10F24C3600A20420C5069500CA10F8E8A0008A20F1FF9005A9FF4C9E05A200F5 +:2035A000A97F209506BD0007209506E8C90DD0F54C36002CE2FE50FB8DE3FE602CE6FE501F +:2035C000FB8DE7FE60A5FF386A300F48A90020BC069820BC068A20BC06682CE0FE50FB8D96 +:2035E000E1FE602CE2FE10FBADE3FE60C909D02A9848B1F2C90DD01EA9E9205193A6F498AC +:20360000F014209E800D5455424520484F535420322E33300DEA68A8A909C9FE905CD01B93 +:20362000C000F056A206A91420F4FF2CE0FE10FBADE1FEF04320EEFF4C2BB6A9AD8D2002F9 +:20364000A9068D2102A9168D0202A9008D0302A98E8DE0FEA000B9BCB6990004B91EB49952 +:203660000005B91EB599000688D0EB202104A241BD7BB69516CA10F8A90060A9FF209E06CF +:20368000ADE3FEA900209506A8B1FD209506C8B1FD209506AAD0F7A2FF9A582CE0FE1006D2 +:2036A000ADE1FE20EEFF2CE2FE10F02CE0FE30F0AEE3FE86516C0005008000004C84044CC4 +:2036C000A706C980902BC9C0B01A0940C515D0200878A905209E06A515209E0628A980858D +:2036E000158514600614B006C515F0041860851560087884138612209E06AAA003A5152012 +:203700009E06B112209E068810F8A0188CE0FEBD18058DE0FE4A4A90062CE5FE2CE5FE201F +:203720009E062CE6FE50FBB00DE004D0112014042095064C32004A9005A0888CE0FE28609E +:2037400058B00AD0034C9C05AE8D02F0E0A9FF20060490F920CE040878A90720C704A00082 +:203760008400B1008DE5FEEAEAEAC8D0F528E654D006E655D002E656E601240150D920CEB5 +:2037800004A904A000A2534C0604A98085548501A9202D0680A88453F019AE0780E8BD0027 +:2037A00080D0FABD01808553BD02808554BC0380BD048085568455600000000000000000FD +:2037C0000000000000000000000000000000000000000000000000000000000000000000E9 +:2037E0000000000000000000000000000000000000000000000000000000000000000000C9 +:203800000000000000000000000000000000000000000000000000000000000000000000A8 +:20382000000000000000000000000000000000000000000000000000000000000000000088 +:20384000000000000000000000000000000000000000000000000000000000000000000068 +:20386000000000000000000000000000000000000000000000000000000000000000000048 +:20388000000000000000000000000000000000000000000000000000000000000000000028 +:2038A000000000000000000000000000000000000000000000000000000000000000000008 +:2038C0000000000000000000000000000000000000000000000000000000000000000000E8 +:2038E0000000000000000000000000000000000000000000000000000000000000000000C8 +:203900000000000000000000000000000000000000000000000000000000000000000000A7 +:20392000000000000000000000000000000000000000000000000000000000000000000087 +:20394000000000000000000000000000000000000000000000000000000000000000000067 +:20396000000000000000000000000000000000000000000000000000000000000000000047 +:20398000000000000000000000000000000000000000000000000000000000000000000027 +:2039A000000000000000000000000000000000000000000000000000000000000000000007 +:2039C0000000000000000000000000000000000000000000000000000000000000000000E7 +:2039E0000000000000000000000000000000000000000000000000000000000000000000C7 +:203A00000000000000000000000000000000000000000000000000000000000000000000A6 +:203A2000000000000000000000000000000000000000000000000000000000000000000086 +:203A4000000000000000000000000000000000000000000000000000000000000000000066 +:203A6000000000000000000000000000000000000000000000000000000000000000000046 +:203A8000000000000000000000000000000000000000000000000000000000000000000026 +:203AA000000000000000000000000000000000000000000000000000000000000000000006 +:203AC0000000000000000000000000000000000000000000000000000000000000000000E6 +:203AE0000000000000000000000000000000000000000000000000000000000000000000C6 +:203B00000000000000000000000000000000000000000000000000000000000000000000A5 +:203B2000000000000000000000000000000000000000000000000000000000000000000085 +:203B4000000000000000000000000000000000000000000000000000000000000000000065 +:203B6000000000000000000000000000000000000000000000000000000000000000000045 +:203B8000000000000000000000000000000000000000000000000000000000000000000025 +:203BA000000000000000000000000000000000000000000000000000000000000000000005 +:203BC0000000000000000000000000000000000000000000000000000000000000000000E5 +:203BE0000000000000000000000000000000000000000000000000000000000000000000C5 +:203C00000000000000000000000000000000000000000000000000000000000000000000A4 +:203C2000000000000000000000000000000000000000000000000000000000000000000084 +:203C4000000000000000000000000000000000000000000000000000000000000000000064 +:203C6000000000000000000000000000000000000000000000000000000000000000000044 +:203C8000000000000000000000000000000000000000000000000000000000000000000024 +:203CA000000000000000000000000000000000000000000000000000000000000000000004 +:203CC0000000000000000000000000000000000000000000000000000000000000000000E4 +:203CE0000000000000000000000000000000000000000000000000000000000000000000C4 +:203D00000000000000000000000000000000000000000000000000000000000000000000A3 +:203D2000000000000000000000000000000000000000000000000000000000000000000083 +:203D4000000000000000000000000000000000000000000000000000000000000000000063 +:203D6000000000000000000000000000000000000000000000000000000000000000000043 +:203D8000000000000000000000000000000000000000000000000000000000000000000023 +:203DA000000000000000000000000000000000000000000000000000000000000000000003 +:203DC0000000000000000000000000000000000000000000000000000000000000000000E3 +:203DE0000000000000000000000000000000000000000000000000000000000000000000C3 +:203E00000000000000000000000000000000000000000000000000000000000000000000A2 +:203E2000000000000000000000000000000000000000000000000000000000000000000082 +:203E4000000000000000000000000000000000000000000000000000000000000000000062 +:203E6000000000000000000000000000000000000000000000000000000000000000000042 +:203E8000000000000000000000000000000000000000000000000000000000000000000022 +:203EA000000000000000000000000000000000000000000000000000000000000000000002 +:203EC0000000000000000000000000000000000000000000000000000000000000000000E2 +:203EE0000000000000000000000000000000000000000000000000000000000000000000C2 +:203F00000000000000000000000000000000000000000000000000000000000000000000A1 +:203F2000000000000000000000000000000000000000000000000000000000000000000081 +:203F4000000000000000000000000000000000000000000000000000000000000000000061 +:203F6000000000000000000000000000000000000000000000000000000000000000000041 +:203F8000000000000000000000000000000000000000000000000000000000000000000021 +:203FA000000000000000000000000000000000000000000000000000000000000000000001 +:203FC0000000000000000000000000000000000000000000000000000000000000000000E1 +:203FE0000000000000000000000000000000000000000000000000000000000000000000C1 +:00000001FF diff --git a/cores/bbc/roms/mmfs.rom b/cores/bbc/roms/mmfs.rom new file mode 100644 index 0000000..3e82d45 Binary files /dev/null and b/cores/bbc/roms/mmfs.rom differ diff --git a/cores/bbc/roms/smmc.hex b/cores/bbc/roms/smmc.hex deleted file mode 100644 index 6e950d8..0000000 --- a/cores/bbc/roms/smmc.hex +++ /dev/null @@ -1,514 +0,0 @@ -:020000040000FA -:200000000000004C559482115A44465300302E3930002843296C1E02205B804469736B2054 -:200020009011205B80426164209008205B8046696C652085B36885AE6885AFA5B3489848DB -:20004000A00020DA83B1AE8D01012CDE101025A9028DDE10A9008D0001F019A9028DDE10BA -:20006000A9008D000185B36885AE6885AFA5B3489848A00020DA83B1AE3008F00D209C806D -:200080004C748068A868186CAE00A900AEDE109D0001A9FF8DDE104C0001A92E20E1832C9C -:2000A000DE10101448201C998A48091020179968AA6820E3FF4C1899AEDE109D0001EEDED7 -:2000C00010604820058220CA806848290FC90A900269066930209C80686020EA80CACA20C0 -:2000E000E280B1B09D7210E8C86020ED80B1B095BCE8C860A920A20695C7CA10FB60204D50 -:200100008320F4803013204D8320F480A5BC85F2A5BD85F3A00020BF86A20120C5FFB0DD36 -:2001200085C7C92ED004A920D04DC93AD02120C5FFB01538E9309010C904B00C207E872066 -:20014000C5FFB05CC92EF0034C7483A924D028C92AD01920C5FFB008C92ED032A923D017B9 -:20016000A200A92395C7E8E007D0F96020C5FFB02FC92ED010A5C785CE4C1B8120C5FFB0E8 -:200180001FE007F009C92AD01220C5FFB0D4202280CC66696C656E616D650095C7E8D0DC64 -:2001A0006020E183AD040F204783CD040FF0F1203380C84469736B206368616E67656400E0 -:2001C00020E183B90F0E08297FD00520CB9FF006209C80209A80A206B9080E297F209C80EF -:2001E000C8CA10F420CB9FA920281002A94C209C804CCE9F20CE9F88D0FA604A4A4A4A4A41 -:200200004A2903604A4A4A4A4A600A0A0A0A0A60C8C8C8C8C8C8C8C860888888888888884C -:200220008860000000000000000000000000000000000000000000000000000000000000D6 -:20024000000000000000000000000000000000000000000000000000000000000060A92372 -:20026000D002A9FF8DCF106020FE804C7182200681209682B0E7202B80D66E6F7420666FFE -:20028000756E6400205E8220019A206882200183209D82B0F860204DABA0F8D003ACCE105A -:2002A000201082CC050FB044201082A207B5C7CDCF10F00E20EE8259070EB00229DF297FD7 -:2002C000D00988CA10E78CCE10386088CA10FC30CF204C98B9100E99080EB9100F99080F8B -:2002E000C8CC050F90EE98E9088D050F18604829DFC9419004C95B90013868602CC7103060 -:20030000EC20E18320C0819848A96085B0A91085B1207E83A00220CE9F20358320358320DF -:20032000358368A8B90E0F290320CA80B90F0F20C2804C9A9FA203B9621020C28088CAD077 -:20034000F62011824CCE9F20E1834C4DABADCA1085CEADCB104C7E8720BF86F0F520C5FF92 -:20036000B012C93AF0F738E9309009C904B005207E871860202280CD64726976650020E11E -:20038000839848AAA002A90091B0C8C012D0F9A00220CF83C8C8C00ED0F768AABD0F0E102C -:2003A00006A90AA00E91B0BD0E0FA00420BB83A00C4A4A48290391B068A0084A4A482903AC -:2003C00091B0C903D007A9FF91B0C891B0686020D283BD080F91B0E8C860E6AED002E6AFEA -:2003E00060488A489848A98448A90348A005BABD07014888D0F8A00ABD09019D0B01CA8812 -:20040000D0F6686868A868AA6860BA9D03014C0484488A489848A98448A90948D0CE20B84E -:20042000862047ABA0FF84A8C884AAB9000EC0089003B9F80E209C80C8C00CD0EE206580EF -:200440002028AD040F20C280206580290D447269766520A5CF20CA80A00D20F481206580B8 -:200460004F7074696F6E20AD060F20058220CA802065802028A0030A0AAABD6F85209C8075 -:20048000E88810F6206580290D4469726563746F7279203AADCB1020CA80209A80ADCA10E9 -:2004A000209C80A00620F4812065804C696272617279203AADCD1020CA80209A80ADCC10DA -:2004C000209C80209A9FA000CC050FB017B90F0E4DCA10297FD008B90F0E2980990F0E206E -:2004E000108290E4A00020F6849016A9FF8D82104C9A9F201082CC050FB005B9080E30F391 -:200500006084ABA200B9080E297F9D6010C8E8E008D0F220F684B01F38A206B90E0EFD6051 -:200520001088CA10F6201182B90F0E297FED671090CF201082B0DCA4ABB9080E09809908D9 -:200540000EAD6710C5AAF010A6AA85AAD00A209A9F209A9FA0FFD009A4A8D0F5A00520F4AD -:2005600081C884A8A4AB20CB9F20C0814CE4846F6666004C4F414452554E0045584543B9EA -:200580000E0F20FD8185C418A9FF790C0FB90F0F790D0F85C5B90E0F290365C485C438B9E8 -:2005A000070FE5C548B9060F2903E5C4AAA900C5C268E5C38AE5C66041434345535388D106 -:2005C000324241434B55509CBA54434F4D504143549ABF0A434F50599D266444454C45544F -:2005E0004586FD0144455354524F59870F02444952884D09445249564587740A454E41421E -:200600004C458A3800494E464F8283024C494288510952454E414D458A6C875449544C45E4 -:2006200088A20B5749504586C202B026004255494C449F47014341524493370044554D50BF -:200640009ECF014C4953549E8D01545950459E8601444D4D4393370085B60044465399C5FC -:20066000005554494C5399ED0099F40020B886A2FD8ABA86B6AA9848E8E86848A820BF8642 -:20068000E8BDB8853028CA8886B8E8C8BDB885301651F2295FF0F3CAE8BDB88510FAB1F299 -:2006A000C92ED0D4C8B007B1F220EE8290CA68BDB88548BDB985486086F284F3A00060183F -:2006C0004CC2FF205E8220019A206882B90F0E301220C081206580203A20EA209E9CF00913 -:2006E000209A9F209D82B0E46020A18120D18220B48AACCE102019828CCE104CE086206278 -:200700008220019A20688220FC8220D1824CB48A20BD9B205E8220019A206882B90F0E30B4 -:200720000620C081209A9F209D82B0F02065800D44656C6574652028592F4E29203F20EA05 -:20074000209E9CF0034C9A9F20A181209682B90F0E300C20D182ACCE102019828CCE1020F9 -:200760009D82B0EA20B48A2065800D44656C657465640DEA6020019A205D838DCB10EAEA4B -:20078000EA290385CF60206189206E98207E834CA5ABEAEA206E82206E98207E8384BCA295 -:2007A00000A5C0D006C8C8A202D008B90E0F85C4203F8AB9080F95BEC8E8E008D0F52056F4 -:2007C0008AA4BC20FC824C96AB000000000000000000000020B8862041888CDB102006819F -:2007E0008CDA10209682B022ACDB10ADCC1085CEADCD10207E87200981209682B00C202277 -:2008000080FE636F6D6D616E6400209D8718ADDA10A865F28DDA10A5F369008DDB10AD7676 -:20082000102D77100DD710C9FFF013A5C08D7410A5C18D7510A274A010A9044C06046CC052 -:2008400000A9FF85C0A5F285BCA5F385BD60A200F002A2022060889DCB10A5CE9DCA106097 -:20086000A92485CE20BF86D007A900207E87F030ADCB10207E8720C5FFB010C93AD01A20D0 -:200880005D8320C5FFB019C92EF0EB202280CE6469726563746F72790085CE20C5FF90EBE2 -:2008A000A5CF6020019A204D832047834CA7AE0020C688CA10FAE820C5FFB00720C688E01B -:2008C0000B90F34CB48AE00890049DF80E609D000E60205E8220019A20FE80A20020BF8616 -:2008E000D02386AA209682B0034C7682204F98B90F0E297F05AA990F0E20FC82209D82B02F -:20090000EB90C0A28020C5FFB0D8C94CF0F5202280CF6174747269627574650020E1838AA1 -:20092000C904F01AC902900B202280CB6F7074696F6E00A2FF98F002A2008EC710609848E2 -:20094000204D83204DAB68200B824D060F29304D060F8D060F4CB48A201880C666756C6C00 -:2009600000200681209682900320D182A5C248A5C34838A5C4E5C285C2A5C5E5C385C3AD9D -:200980007A10ED781085C6209D89AD79108D7510AD78108D74106885BF6885BE60A9008554 -:2009A000C4A90285C5AC050FF02DC0F8B056209E854CBC89F0A2201982207F859890F584FD -:2009C000B0AC050FC4B0F00FB9070E990F0EB9070F990F0F88B0EDA20020178AB5C7990885 -:2009E0000EC8E8E008D0F5B5BD8899080FCAD0F720FC829848AC050F2010828C050F20B4ED -:200A00008A68A860203380BE436174616C6F6775652066756C6C00AD761029030A0A45C665 -:200A200029FC45C60A0A4D741029FC4D74100A0A45C429FC45C485C460A9018DC81060A99F -:200A4000008D7510A5C420FF81C903D005A9FF8D75108D741060A9008D7710A5C420FB81ED -:200A6000C903D005A9FF8D77108D76106020628220BF86D0034C069A20FE809848209682C8 -:200A8000B0034C7682204C9884B368A820BF86F0E420FE80209682900B202B80C465786995 -:200AA00073747300A4B3201082A207B5C799070E88CA10F718F8AD040F6901D88D040F4CA9 -:200AC00061ABA9FF209E06ADE3FEA900209506A8B1FD209506C8B1FD209506AAD0F7A2FF58 -:200AE0009A582CE0FE1006ADE1FE20EEFF2CE2FE10F02CE0FE30F0AEE3FE86516C0005003E -:200B00008000004C84044CA706C980902BC9C0B01A0940C515D0200878A905209E06A51572 -:200B2000209E0628A98085158514600614B006C515F0041860851560087884138612209E90 -:200B400006AAA003A515209E06B112209E068810F8A0188CE0FEBD18058DE0FE4A4A90061C -:200B60002CE5FE2CE5FE209E062CE6FE50FBB00DE004D0112014042095064C32004A900566 -:200B8000A0888CE0FE286058B011D0034C9C05A200A0FFA9FD20F4FF8AF0D9A9FF20060443 -:200BA00090F920D204A90720CB04A0008400B1008DE5FEEAEAEAC8D0F5E654D006E655D06C -:200BC00002E656E601240150DC20D204A904A000A2534C0604A98085548501A9202D06800D -:200BE000A88453F019AE0780E8BD0080D0FABD01808553BD02808554BC0380BD04808556C0 -:200C000084556037059605F2050706270668065E052D0520054205A905D10586889698184C -:200C200018821820C506A820C50620D4FF4C9C0520C506A820D7FF4C3A0520E0FF6A209572 -:200C4000062A4C9E0520C506F00B482082056820CEFF4C9E0520C506A8A90020CEFF4C9C4B -:200C60000520C506A8A20420C50695FFCAD0F820C50620DAFF209506A203B500209506CAA7 -:200C800010F84C3600A200A00020C506990007C8F004C90DD0F3A0076020820520F7FFA93B -:200CA0007F2CE2FE50FB8DE3FE4C3600A21020C5069501CAD0F820820586008401A0002037 -:200CC000C50620DDFF209506A210B501209506CAD0F8F0D5A20D20C50695FFCAD0F820C573 -:200CE00006A00020D1FF48A20CB500209506CA10F8684C3A0520C506AA20C50620F4FF2C74 -:200D0000E2FE50FB8EE3FE4C360020C506AA20C506A820C50620F4FF499DF0EB6A209506AB -:200D20002CE2FE50FB8CE3FE70D520C506A82CE2FE10FBAEE3FECA300F2CE2FE10FBADE3C1 -:200D4000FE9D2801CA10F298A228A00120F1FF2CE2FE10FBAEE3FECA300EBC28012CE2FE51 -:200D600050FB8CE3FECA10F24C3600A20420C5069500CA10F8E8A0008A20F1FF9005A9FF16 -:200D80004C9E05A200A97F209506BD0007209506E8C90DD0F54C36002CE2FE50FB8DE3FE96 -:200DA000602CE6FE50FB8DE7FE60A5FF386A300F48A90020BC069820BC068A20BC06682CD4 -:200DC000E0FE50FB8DE1FE602CE2FE10FBADE3FE60000000000000000000000000A211A0C6 -:200DE000156020E183A9774CF4FF20E28DA900186920F0EDA820058ED0F598F0ED207B9025 -:200E000090034CAD9048205190B045B91B1149FF2DC0108DC010B917112960F03320558E61 -:200E2000B917112920F026AEC410B914119D0C0FB915119D0D0FB91611200B825D0E0F2992 -:200E4000305D0E0F9D0E0F20B48AACC210204B91AEC610686020838EA207B90C1195C68877 -:200E600088CAD0F620968290278CC410B90E0FBE0F0FACC210590D112903D0148AD90F11D1 -:200E8000D00E60B90E11297F85CEB917114C7E874CAF81C900D00620E1834CFA8D201184E8 -:200EA00086BC84BD85B424B408200681209682B01A285003A9006008A900A20795BE9D74AB -:200EC00010CA10F8A94085C520618928087003203C98209E8F900EB90C11102624B430223B -:200EE00020998FB0F2ACC210D021203380C0546F6F206D616E792066696C6573206F706568 -:200F00006E00202B80C26F70656E00A9088DC510BD080E990011C8BD080F990011C8E8CED0 -:200F2000C510D0ECA210A900990011C8CAD0F9ADC210A82004826911991311ADC110991B8A -:200F4000110DC0108DC010B9091169FFB90B116900991911B90D11090F690020FD81991A61 -:200F60001128502E3008A980190C11990C11B90911991411B90B11991511B90D1120FD81D3 -:200F8000991611A5CF19171199171198200482091060A920991711D0EA8A484CDD8FA900ED -:200FA0008DC210A90885B598AAA0A084B38A48A90885B2A5B52CC010F01DB9171145CF29F3 -:200FC00003D01ABD080E590011297FD010E8C8C8C6B2D0EF38B0108CC2108DC11038A5B36C -:200FE000E92085B306B51868AAA4B3A5B5B002D0BA60ADC0104820ED8DF007ADC010482043 -:20100000FA8D688DC01060C000F01120E183C9FFF0E9C903B0174A90154CA792201184A8DA -:20102000C8C003B008B9819948B97E99486020E18320A5908CC2100A0A6DC210A8B91011CE -:201040009500B911119501B912119502A900950360488EC6109829E08DC210F01320048221 -:20106000A8A900386A88D0FCACC2102CC010D003683860681860488A4C7D904898C9109088 -:2010800004C9189002A908200A82A868604898488AA820A5909820F892D004A2FFD002A232 -:2010A0000068A86860207B9020519090F7203380DE4368616E6E656C00203380DF454F46AF -:2010C0000020118420A5909820F892D013B917112910D0E5A910203C91AEC610A9FE3860A9 -:2010E000B91711300A20838E204B9138205391B9101185BCB9131185BDA000B1BC48ACC26F -:2011000010A6BCE88A991011D01418B911116901991111B9121169009912112041911868C2 -:201120006018B90F1179111185C5991C11B90D11290379121185C4991D11A980191711D0CA -:2011400005A97F3917119917111860B917112940F03D1808200BB9ACC210B9131185BF208E -:201160008DA0A90085BE85C2A90185C328B017B91C1185C5B91D1185C4208F87ACC210A971 -:20118000BF204391900620219120C687ACC210604CAD904C4198202B80C172656164206F84 -:2011A0006E6C790020E1834CB09120E18320A59048B90C1130E0B90E1130D820838E981803 -:2011C000690420F892D07620588EAEC41038BD070FFD0F0F48BD060FFD0E0F29038DC31044 -:2011E0000A0A0A0A5D0E0F29305D0E0F9D0E0FADC310D91A11D02B68D91911D02684B42088 -:201200002099207690C4B4D003201199A4B420058E203380BF43616E277420657874656E4C -:201220006400689D0D0F991911ADC310991A11A9009D0C0F20B48AEAEAEAACC210B9171146 -:201240003017204B91B91411D00B9820F892D005202191D00438205391B9101185BCB913B2 -:201260001185BD68A00091BCACC210A940203C91E6BCA5BC991011D013204191B91111699C -:2012800001991111B9121169009912119820F8929014A920203C91A202B91011991411C8F1 -:2012A000CA10F68888886020E18320A590205EA1EAEAEAEAEAEA201093B008A90020A49179 -:2012C0004CB692B500991011B501991111B502991211A96F204391B90F117911118DC51045 -:2012E000B90D112903791211D91D11D0B9ADC510D91C11D0B14C3A91AAB91211DD1611D045 -:201300000EB91111DD1511D006B91011DD141160B91411D500B91511F501B91611F5026010 -:20132000A5B348A9FF8DDE102065805375706572204D4D430D0D90034C55A1A900BA9D06E4 -:2013400001A906201580A20DBD49999D1202CA10F720289984B186B0A207A01BB93C999189 -:20136000B0C8B93C9991B0C8A5F491B0C8CAD0EC86CF8C8210A20F202C99209E98A0D4B1B2 -:20138000B0102FA0D5B1B03027208F98A000B1B0C0C09005990010B00399001188D0EFA9DE -:2013A000A0A848A93F20439168991D11E91FD0F16860A9FF91B08DD410208F982024998AF9 -:2013C00049FF8DD710A9248DCA108DCC10A0008CCB108CCD10A0008CC0108CC910888CC807 -:2013E000108CC7108CDE10200AAD4C04940000000000000000000000000000000000000045 -:201400000000000068D034204DABA000A200AD060F200582F02548A243A09920B88620FEA6 -:201420008020968268B01520658046696C65206E6F7420666F756E640D0DEA60C902900EC8 -:20144000F006A241A099D00AA243A099D004A239A0994CF7FFC901D007C017B002A0176017 -:20146000C902D01A48981885B19DF00D690248A90085B0A0D491B0C891B068A86860C903FC -:20148000D01984B320E1834CF7A7F4FF8A3009C932D0EAA97820F4FF4C2093C904D008205B -:2014A000E183A2724C7186C909D01220E1834C94AFA0C90DD0EE98E8A0024CCB99C90AD001 -:2014C0002920E183209E98A0D5B1B0101CA000C0C09005B90010B003B9001191B088D0EF84 -:2014E00020F28FA0D5A90091B060C908D015201184A4F084B0A4F184B1A4EFC07FD04C4C55 -:2015000013B9004CF6A000000000000000000000000000000000000000000000000000001D -:201520000000000000000000000000000000000000000000000000000000000000000000AB -:201540000000000000000000000000C07D902B204D83204783C07EF009A000AD040F91B0E1 -:201560009860A900A891B0C8AD070F91B0C8AD060F290391B0C8A90091B0602011844820EF -:20158000628286B08EDC1084B18CDD10A200A00020EA8020DA80C012D0F968AAE8E008B096 -:2015A00008BD8C9948BD84994860C909B0FB86B5AABD759948BD6C99488AA6B560A9FF9576 -:2015C000029503ADDA109500ADDB109501A90060C909B0FB20E1838E7D108C7E10A8BAA9CD -:2015E000004CD8A0B9AB998DD810B9B4998DD910B9BD994A084A088D7F10205697A00CB100 -:20160000B49960108810F8AD63102D64100DD7101869014CEBA0EA8D8110AD7F10B007A2D2 -:2016200061A01020060428B004286CD810A203BD691095B6CA10F8A2B6AC6010A90028B02A -:201640000320A792202E90A203B5B69D6910CA10F8204897300DAC6010202A96B00DA209B8 -:20166000203C97A205203C97D0EC1808204897A205203C97A00C205697B9601091B48810A9 -:20168000F82860204D83204DABA9958DD810A9968DD910D0BCAC6910CC050FB028B90F0E1B -:2016A00020EE8245CEB00229DF297FF005201082D0E6A907206A9785B0B9080E206A97C80A -:2016C000C6B0D0F5188C6910AD040F8D601060204D83204DABA90C206A97A000B9000E2030 -:2016E0006A97C8C008D0F5B9F80E206A97C8C00CD0F5AD060F200582206A97A5CF4C6A9710 -:20170000206197ADCB100930206A97206197ADCA104C6A97206197ADCD100930206A9720C7 -:201720006197ADCC104C6A9748AD611085B8AD621085B9A200686020E183A201A004FE6048 -:2017400010D004E888D0F760A203A9FF5D65109D6510CA10F560AD7D1085B4AD7E1085B5C6 -:2017600060A901D00520C190B0F62C811010068DE5FE4C379720289781B84C3797208597A8 -:2017800020AA9118602C81101006ADE5FE4C3797202897A1B84C37972CC8103003CEC810CA -:2017A00060205A98207E83A90160203798207E8320D182902420379820DF9720FB975016B8 -:2017C00020379820DF97501120379820FB975009205A98204F98201E9820C388A9016020A5 -:2017E000E183A002B1B09D080FC8B1B09D090FC8B1B00A0A5D0E0F290C101B20E183A006AF -:20180000B1B09D0A0FC8B1B09D0B0FC8B1B06A6A6A5D0E0F29C05D0E0F9D0E0FB86020E1BA -:2018200083A00EB1B0290AF002A9805D0F0E29805D0F0E9D0F0E602064989023B90F0E105C -:2018400022202B80C36C6F636B656400203C9820E183209E8F90214C028F206498B01968C6 -:2018600068A90060200681209682900C98AAADDC1085B0ADDD1085B160A98320F4FF8CD0A1 -:2018800010A98420F4FF9838EDD0108DD11060A20A202C99209E98A0D5A9FF91B06048A6FA -:2018A000F4A90085B0BDF00D85B1686000000000000000000000000000000000000000009E -:2018C000000000000000000000000000000000000000000000000000000000000000000008 -:2018E0000000000000000000000000000000000000000000000000000000000000000000E8 -:2019000000000000006020E183A90FA201A000F025A9C7A200F0F6AAA903D01AA9ECD01224 -:20192000A9C7D00EA9EAD00AA9A8D006A98FD006A9FFA200A0FF4CF4FF4C2E21424F4F54C0 -:201940000D452E21424F4F540D1BFF1EFF21FF24FF27FF2AFF2DFF7B9500079000C19000B8 -:20196000AA9100D09500938E00AA95001B8CD36BD31DE1DC978990878687848D8D97F13C2F -:20198000BC8F9B959385B4BFC7CFA0A9878797979797979712325DCDA2BD878D8D8D8D8DB5 -:2019A0008D8D7454000F1A0F1A6343B77D7D6565CF00148385979797979697979604020328 -:2019C00006070404040498A2FFA00E482065800D44465320302E39300D86B820CB9F2019D7 -:2019E0009A209A9F88D0F468A8A2A04C718698A274A005D0D620BF86F06020C5FF90FBB046 -:201A0000E820BF86D054203380DC53796E7461783A20EA20199A4C8A80A6B8E8BDB8853042 -:201A200006209C804C1B9AE8E886B8BDB88520349A20058220E183290FF01FA8A920209CCE -:201A400080A200BD5B9AF003E8D0F888D0FAE8BD5B9AF006209C804C4E9A60003C667370D8 -:201A60003E003C616673703E00284C29003C737263206472763E003C6465737420647276E1 -:201A80003E003C64657374206472763E203C616673703E003C6F6C64206673703E003C6E62 -:201AA0006577206673703E00283C6469723E2900283C6472763E29003C7469746C653E00E6 -:201AC000205883206580436F6D70616374696E67206472697665208DD2108DD31020CA805E -:201AE000209A9FA00020058E207998204783AC050F84CCA90285CAA90085CBA4CC201982F1 -:201B0000C0F8D03C2065804469736B20636F6D70616374656420EA38AD070FE5CA48AD06F2 -:201B20000F2903E5CB20CA806820C280206580206672656520736563746F72730DA9046082 -:201B400084CC20FC82A4CCB90E0F2930190D0F190C0FF061A90085BE85C2A9FF18790C0FB7 -:201B6000A900790D0F85C6B90E0F0820FD8128690085C7B90F0F85C8B90E0F290385C9C54A -:201B8000CBD014A5C8C5CAD00E1865C685CAA5CB65C785CB4CB59BA5CA990F0FB90E0F297D -:201BA000FC05CB990E0FA90085A885A920B48A20069E204783A4CC2001834CFB9A2CC8109A -:201BC0001075203380BD4E6F7420656E61626C65640020BF86D0034C069A205D838DD21041 -:201BE00020BF86F0F2205D838DD3109848A90085A9ADD310CDD210D006A9FF85A985AA203D -:201C00007998206580436F7079696E672066726F6D20647269766520ADD21020CA80206529 -:201C20008020746F20647269766520ADD31020CA80209A9F68A8186020E18324A9100BA9D7 -:201C400000F00A20E18324A9300160A980C5AAF0F985AA206580496E7365727420EA24AAA6 -:201C6000300B206580736F75726365900F20658064657374696E6174696F6EEA206580203E -:201C80006469736B20616E64206869742061206B6579EA20069920E0FFB0194C9A9F2006DB -:201CA0009920E0FFB00E295FC95908F002A94E209C802860A6B69A604C588920BD9B20D282 -:201CC0009BA90085C985CB85CA85C885A820389CADD21085CF204DABAD070F85C6AD060F9A -:201CE000290385C7AD060F29F08DD81020439CADD31085CF204DABAD060F2903C5C790B85F -:201D0000D007AD070FC5C690AF20069EAD060F48AD070F48204DAB688D070F68290F0DD8DE -:201D2000108D060F4CB48A205E8220D29B20BF86D0034C069A20FE8020389CADD210207EF7 -:201D400087209682B0034C768284AB200183A200B5C79D5810B9080E95C79D5010B9080FDF -:201D600095BD9D4710E8C8E008D0E5A5C320FD8185C5A5C11869FFA5C2690085C6A5C569AC -:201D80000085C7AD4E1085C8AD4D10290385C9A9FF85A820069E20389CADD210207E8720BA -:201DA0004783A207BD581095C7CA10F8A4AB8CCE10209D82B0936020F59D20439CADD31081 -:201DC00085CFA5CE48204783209682900320D1826885CE203F8A20568AA5C420FD8185C6D6 -:201DE000209D89A5C4290348A5C54820F59D6885CA6885CB60A211BD4510B4BC95BC989DD2 -:201E00004510CA10F260208DA0A90085BE85C2A5C6A8CDD110A5C7E9009003ACD11084C344 -:201E2000A5C885C5A5C985C4ADD01085BFADD21085CF20389C200BB920C687ADD31085CF57 -:201E400024A8100720B79DA90085A8A5CA85C5A5CB85C4ADD01085BF20439C200BB9208F80 -:201E600087A5C31865CA85CA9002E6CBA5C31865C885C89002E6C938A5C6E5C385C6B00217 -:201E8000C6C705C7D0896020D79FA900F00520D79FA9FF85ABA9C020CEFFA8A90DC000D04A -:201EA0001E4C768220D7FFB01EC90AF0F728D0084820A29F20CE9F6820E3FF24FF30092521 -:201EC000ABC90D084CA49E28209A9FA9004CCEFF20D79FA9C020CEFFA8F0C6A6F4BDF00D0A -:201EE00085ADE6AD24FF30E3A5A920C280A5A820C28020CE9FA90785ACA20020D7FFB00DC5 -:201F000081AC20C28020CE9FC6AC10EF1808900E2065802A2A20A90081ACC6AC10F2A90703 -:201F200085ACA1ACC97FB004C920B002A92E20E3FFC6AC10ED209A9FA9081865A885A89058 -:201F400002E6A928909EB08320D79FA98020CEFF85AB20A29F20CE9FA6F4BCF00DC884AD51 -:201F6000A2ACA0FF84AE84B0C884AC84AF9820F1FF0884AAA4ABA200F007A1AC20D4FFE6F7 -:201F8000ACA5ACC5AAD0F328B008A90D20D4FF4C529FA97E20F4FF20CB9E48A90D209C804F -:201FA0006860F818A5A8690185A8A5A9690085A9D81820B79FA5A848082005822820C19F2E -:201FC00068AAB002F00820CA80386020CE9F48A920209C80681860BAA9009D070188C8B180 -:201FE000F2C920F0F9C90DD0034C069AA90085A885A948981865F2AAA5F36900A868606DAD -:20200000207BA16885B86885B9200FA04C0001A0008C0001C8F007B1B8990001D0F660A266 -:20202000FFD002A200A0FF8C821085B086B18D020D207BA16885B86885B9200FA0A5B0209D -:2020400069A0A5B1F01BA92F990001C8AE410DBD440D2069A0BD450D2069A0BD460D2069D8 -:20206000A0A9009900014C0001484A4A4A4A2074A068290F186930C93A900269069900019D -:20208000C8602000A0114573636170650048A9FF8D74108D7510686048A5BE8D7210A5BFFD -:2020A0008D7310AD74102D75100DD71049FF8DD61038F00D20C3A0A272A010684820060428 -:2020C00018686048A9C120060490F96860ADD610F005A981200604609D050120E49508ADC6 -:2020E0008110F005A9812006042860F00620C3A018A9FF4C1796C9FE905AD01BC000F054AC -:20210000A206A91420F4FF2CE0FE10FBADE1FEF04120EEFF4C07A1A9AD8D2002A9068D2112 -:2021200002A9168D0202A0008C0302A98E8DE0FEB9038B990004B9038C990005B9038D99CE -:20214000000688D0EB202104A240BDC28A9516CA10F8A90060A9FF8D520D484C3B93B914BD -:2021600011991011B91511991111B9161199121160A2068E40FEE88E40FE60A9764CF4FF18 -:20218000A201A9038E60FE8D60FE8E60FE8D60FE8E60FE8D60FE8E60FE8D60FE8E60FE8D1B -:2021A00060FE8E60FE8D60FE8E60FE8D60FE8E60FE8D60FEAD6AFE600A2A8D60FE09028D10 -:2021C00060FE2A29FD8D60FE09028D60FE2A29FD8D60FE09028D60FE2A29FD8D60FE0902F9 -:2021E0008D60FE2A29FD8D60FE09028D60FE2A29FD8D60FE09028D60FE2A29FD8D60FE094E -:20220000028D60FE2A29FD8D60FE09028D60FE602C400D3038A201A9038E60FE8D60FE8EAB -:2022200060FE8D60FE8E60FE8D60FE8E60FE8D60FE8E60FE8D60FE8E60FE8D60FE8E60FE0D -:202240008D60FE8E60FE8D60FE88D0CD60A9FF8D18FEEAEAEA88D0F7602C400D30368E41D1 -:202260000DA007BD420D20B8A1E888D0F62073A24C8AA1A901A203A00088F0128D60FE8E51 -:2022800060FEAD6AFE2901D0F0A201A90360AD6AFEC900608E410DA008BD420D8D18FEEAD7 -:2022A000EAE888D0F48D18FE2058A2AD18FE10E388D0F54C91A22C400D300AA2012082A128 -:2022C000C9FED0F960A2FF8E18FE2058A2AD18FEC9FED0F3602C400D3015A201ACD610D03F -:2022E000092082A191A0C8D0F860A0004C2DA3A2FF8E18FEACD610D016EAEAEAAD18FE8EE9 -:2023000018FE91A0C8C0FFD0F3AD18FE91A060A0004C5AA32C400D301EA201ACD610D00B18 -:202320002082A191A0C8C6A7D0F660A4A72082A18DE5FE88D0F760A2FF8E18FEACD610D07A -:2023400017C6A7F00DAD18FE8E18FE91A0C8C6A7D0F3AD18FE91A060A4A788F01AEAAD188C -:20236000FE8E18FE8DE5FE2058A22058A2EAEAEA88D0EAEAEAEAEAAD18FE8DE5FE602C4070 -:202380000D300EA000A2012082A199000EC8D0F760A000A2FF8E18FE2058A2AD18FE8E186E -:2023A000FE99000EC8C0FFD0F2AD18FE99000E602C400D300AA0022015A2A9FE4CB8A1A24B -:2023C000FF8E18FE2058A28E18FE2058A2CA8E18FE60A0022C400D301A2015A22073A22023 -:2023E0009CA1A8291FC905D02DA2012082A1C9FFD0F960204DA2A2FF8E18FE2058A2AD18DB -:20240000FEA8291FC905D00EA9FF8E18FE2058A2CD18FED0F56098201FA0C54D4D43205724 -:202420007269746520726573706F6E7365206661756C7420002C400D301AACD610D009B11E -:20244000A020B8A1C8D0F860A000ADE5FE20B8A1C8D0F760ACD610D009B1A08D18FEC8D0E4 -:20246000F860A000ADE5FE8D18FE2058A22058A22058A2C8D0EE602C400D300CA000B900EF -:202480000E20B8A1C8D0F760A000EAB9000E8D18FEC8D0F6609D430DA9009D440D9D450D71 -:2024A0009D460D9D470DA9FF9D420D9D480D9D490DAE030DBDD2A48D400D602CC910301151 -:2024C000A98FA20CA0FF20F4FF8C010DA9FF8DC910608000A9038D62FEA9008D60FEAD6B97 -:2024E000FE29E38D6BFEA91C8D6EFE60AD020DC954D00420D4A4602006A5D0FA2000A0FFC5 -:20250000436172643F002071A1A2FF8E030D20BBA4A200A9402095A4A9958D480DA208A9BB -:20252000412095A420D4A4A93285A6AE040DE002B05A8E030DBDD2A48D400DA00A2010A291 -:20254000A2002059A22981C901D03524FF3031A2082059A2C902B028C900D0EFA200A95036 -:202560002095A4A9028D460DA2002059A2D023A9548D020DAD030D8D040D207BA1A9FF608F -:20258000AE030DE8E00290AAC6A6D09FA9008D020D60201FA0FF53657420626C6F636B20A4 -:2025A0006C656E206572726F722000A951A2002095A4A5A28D460DA5A38D450DA5A48D4415 -:2025C0000D60A2002059A2D00420B6A260201FA0C54D4D432052656164206661756C7420AC -:2025E00000A2002059A2D0034CB0A3201FA0C54D4D43205772697465206661756C742000A4 -:202600002071A1A9008DD61085A0A90E85A1602000A620ABA520C2A520D5A2E6A120D5A298 -:20262000A0022010A24C7BA12000A6A95820ADA520E1A52035A4E6A12035A420D2A34C7B0A -:20264000A1602071A1204BA64C7BA1A6A5F0F2A9012098A0A6A566A266A61001E886A50616 -:20266000A220ABA5A6A5E003B008A5A7D04FE001F04224A6100D20C2A5A00084A62010A2DA -:202680004C8BA620C2A520D5A2E6A120D5A2E6A1A0022010A2EE460DEE460DD008EE450DEC -:2026A000D003EE440DA6A5CACAF09686A5E003B0D24C6AA620C2A520D5A24CE4A620C2A53C -:2026C00024A61008A0002010A24CD5A6C6A5F00520D5A2E6A12014A39849FFA8C82010A268 -:2026E000A5A5D005A0002010A2A0024C10A2602071A120F8A64C7BA1A6A5F0F2A900209863 -:20270000A0A6A566A26A06A248A95820ADA5681041A9FF8D8210A9518D430D20C2A5207E7D -:20272000A3A0002010A2A0022010A2A9588D430D20E1A52077A42035A420D2A3C6A5F0AEBA -:20274000E6A1EE460DEE460DD008EE450DD003EE440DA6A5F044CAD02BA9FF8D8210A95141 -:202760008D430D20C2A5A0002010A2207EA3A0022010A2A9588D430D20E1A52035A42077BA -:20278000A44CD2A320E1A52035A4E6A12035A4E6A120D2A3C6A5C6A5D0A860A951A2082027 -:2027A00095A4A5A28D4E0DA5A38D4D0DA5A48D4C0D602071A1A20820C4A5A95F85A0A90DAB -:2027C00085A1A90885A72014A3A0F82010A2A96785A0A90885A72014A3A0FA2010A218AD9B -:2027E0004E0D69208D4E0DAD4D0D69038D4D0D9003EE4C0D4C7BA12006A5F0B5A97A20F4CA -:20280000FF8A300DC965F004C942D0A5A97820F4FF8E520D4C2093AD050DC954D017AD06BA -:202820000D4D090D4D070D4D0A0D4D080D4D0B0DC9FFD00160A208B5A148CAD0FAA9008599 -:20284000A285A385A4200FA6A9DD8D8210206BA8F029A9008D060D8D070D8D080DA9FF8DFE -:20286000090D8D0A0D8D0B0D4C99A9ADFE0FC955D005ADFF0FC9AA604CA9A9ADC60F0A8581 -:20288000A2ADC70F2A85A3ADC80F2AB0EB85A4ADC90FD0E4200FA6206BA8D0DCAD0B0ED0CC -:2028A000D7AD0C0EC902D0D0AD110E85A5AD120E4A66A54A66A54A66A585A6AD0D0E85A72E -:2028C000AD0E0E0A2E0F0EB0AF65A285A2AD0F0E65A385A39002E6A40E160E2E170EB0986A -:2028E000AE100E18A5A26D160E85A2A5A36D170E85A39002E6A4CAD0EA200FA6A90085A8A8 -:20290000A90E85A9A00BB1A8290FD010A000B1A8D9C2A9D007C8C00BF020D0F218A5A8696F -:202920002085A8D0DF2000A0FF496D616765206E6F7420666F756E64210018A5A265A5853D -:20294000A2A5A365A685A39002E6A4A01BB1A84888B1A838E90285A868E90085A905A8F095 -:202960001A06A826A9A6A718A5A265A885A2A5A365A985A39002E6A4CAD0ECA5A28D060DD9 -:2029800049FF8D090DA5A38D070D49FF8D0A0DA5A48D080D49FF8D0B0DA9548D050DA20061 -:2029A0006895A2E8E008D0F8602000A0FF556E7265636F676E6973656420666F726D617432 -:2029C000210042454542202020204D4D4208AA2002AA85B248201EAA8AE5B0AA682002AA8A -:2029E00048201EAAA5B2E5B00A0A0A0A85B28A05B2AA6828900B488AF8186956AA68690228 -:202A0000D860A00084B1A0A084B0A005C5B0900438E5B03826B146B088D0F1A5B160480A64 -:202A20000A0A85B0680A1865B085B03860E0FFF035BD100D303049FFDD180DD024BD0C0D8F -:202A400049FFDD140DD01ABD1C0DC954F0292000A0C94469736B2072656164206F6E6C7978 -:202A600000A9FF9D100D2000A0C74E6F206469736B00A9549D1C0D60A9009D1C0D60BD1026 -:202A80000D30E36ABD0C0D08AAA90085A22A4885A48A0A26A485A38A65A385A36869006543 -:202AA000A485A466A28A286A66A24A66A24A66A265A385A3A5A4690085A42017A838A5A210 -:202AC000091F6D060D85A2A5A36D070D85A3A5A46D080D85A460A5BE85A0A5BF85A1A6CF5B -:202AE000207EAA18A5C565A285A2A5C429034865A385A39002E6A4A5C385A5A5C44A4A4ADC -:202B00004A2903D01EA5C285A7F004E6A5F01418A5C565A5AA686900C9039006D017E021EA -:202B2000B013602000A0FF426C6F636B20746F6F20626967002000A0FF4469736B206F76B5 -:202B40006572666C6F7700204D8320588320ECA4A6CF8E200D207EAA200FA6A5CF8D82106B -:202B60006020ECA4A6CF202DAA207EAA4C28A60848A0FF8C8210C89899000E99000FC8D023 -:202B8000F7A9038D060FA9208D070F20ECA468282087AA4C28A620ECA420D6AA2042A62061 -:202BA000CDA0A9016020ECA420D6AAA6CF202DAA20EFA620CDA0A90160A8C898D001382A5B -:202BC0002A2A2A2A48291FA868091F6A6020B9AB488A4898482098AC686A68AA68A8B00431 -:202BE000B9000E60B9000F6008488D5F0DA9002A8D600D8E610DA203EC610DF015BD0C0D9A -:202C0000CD5F0DD00DBD100DCD600DD005A9FF9D100DCA10E3AE610D68286008489D0C0D84 -:202C200049FF9D140DA9002A9D100D49FF9D180D682820E8AB20CDAB3008F0034C72AA4C3D -:202C400078AAA8A9FF9D100DC8D01A2000A0C74469736B206E756D626572206E6F742076D4 -:202C6000616C6964002000A0C74469736B206E6F7420666F726D617474656400297E482042 -:202C800017A818686D060D85A2AD070D690085A3AD080D690085A46029FE0980CD8210F049 -:202CA000F68D82104820ECA468207CAC4C0FA68D8210207CAC4C0FA620ECA4AD8210207C63 -:202CC000AC4C28A6AD8210207CAC4C28A620B8ACA20320D9ACCA10FA60BD100D302B49FF0E -:202CE000DD180DD018BD0C0D49FFDD140DD00EBD100D6ABD0C0D20CDABF00B1007A9FF9DE7 -:202D0000100DD002A9549D1C0D60A9FFA21F9D200DCAD0FA8E040DA9008D020D8D050D8DCA -:202D2000200DA98020A1ACA200AD520DC942F016BD100D304349FFDD180DD00ABD0C0D4981 -:202D4000FFDD140DF016BD000E9D0C0D49FF9D140DBD040E9D100D49FF9D180D8AF01EA816 -:202D600088BD100D3017D9100DD008BD0C0DD90C0DF0058810EB3005A9FF9D100DE8E00439 -:202D8000D0A74CD0AC08488D530DA9002A8D540D6828084820CDA98E550D8D560D682820F0 -:202DA000B9AB29F085F2982901090E85F39829FE09808D520D209CAC4C19AEA9008D550D87 -:202DC0008D560D8D530D8D540DA91085F2A90E85F3A9808D520D209CAC4C19AEC9FFF04140 -:202DE00018A5F2691085F2D018A5F3490185F36AB00FAD520D6902C9A0F0268D520D209C2B -:202E0000ACEE530DD003EE540DF818AD550D69018D550D9003EE560DD8A00FB1F230BD180B -:202E200060A9FF8D540D386020ECA4A9808D520D20AFACA91085F2A90E85F32017A818ADC1 -:202E4000060D692085A2AD070D690085A3AD080D690085A4209BA7A00FB1F2C9FFF0392044 -:202E6000B2A7A00BB95F0D91F28810F818A5F2691085F2D0E2A5F3490185F36AB0D920C494 -:202E8000AC18AD520D6902C9A0F0188D520D24FF301220AFAC4C57AEA5F2D00466F3900312 -:202EA00020C4AC604C82A0A20BA90020C6889D5F0DCA10F7E820C5FFB00A20C6889D5F0D19 -:202EC000E00B90F020B48AAE8210BD100D6ABD0C0D20B9AB29F048984829FE098020A1ACED -:202EE00068182901690E85F36885F2A00BB95F0D91F28810F84CB8AC44494EB3C0124442E1 -:202F00004F4F54B3B50244434154B3C604444449534B53B57601444C4F434BB5BC02445555 -:202F20004E4C4F434BB5C0024446524545B4B000444B494C4CB5E30344524553544F524566 -:202F4000B62603444E4557B67B0144464F524DB61E03444F4E424F4F54B74952445245435E -:202F60004154AE270044524F4DB7B086444D4F4445B764074453574150B79A004441424F57 -:202F80005554AFFA0087D600445554494C53AFCB00AFBD00A2A0B1F2C90DD01698E8A00204 -:202FA00020CB9920FFB12020445554494C53004CE7FF984820718668A8A28D4C29B0C8B1A2 -:202FC000F2C90DF006C920F0F0D0F36020E7FF20FFB144465320302E39300020E7FFA20005 -:202FE000A90E86B585BFA200A92020EEFF20EEFF20C3B220E7FFC6BFD0EE6020FFB144556F -:2030000054494C53206279204D617274696E204D617468657220283139204E6F76203230E6 -:20302000303829004CE7FFA2FD9848E8E86848A8206BB0E8BDF8AE302886B5CA88E8C8BD4E -:20304000F8AE301651F2295FF0F3CAE8BDF8AE10FAB1F2C92ED0D4C8B007B1F220EE829037 -:20306000CA68BDF8AE48BDF9AE4860B1F2C90DF008C8F007C920F0F31888604CB0B29848DD -:20308000A9008D550D8D560D206BB0B062B1F2C90DF05C38E9303057C90AB05348AD550D91 -:2030A0000A482E560DAE560D0A2E560D0A2E560D8D550D686D550D8D550D8A6D560DAA6865 -:2030C0006D550D8D550D8A69008D560DC902B01FC8F01CB1F2C90DF004C920D0B6AE550DF5 -:2030E000AD560DF004E8F007CA68AD560D186068A8A900AA3860A90D8D5D0DA2008E5E0DF0 -:20310000206BB0B049C922D004C88D5D0DB1F2C90DF02CC920D00B9052AD5D0DC922D028C8 -:20312000A920C922F019C92AF031C9619006C97BB00249209D5F0DC8E8E00CD0D0B1F2CDEA -:203140005D0DD027C90DF006C8206BB0901D8E5C0DE00CF005A9009D5F0D608D5E0DAD5DA6 -:203160000DC90DF0E3C8B1F24C3FB14CB0B2A000AE5C0DF017B1F2F025C9619006C97BB01A -:20318000024920D95F0DD016C8CAD0E9B1F2F00CAD5C0DC90CF005AD5E0DF00218603860B5 -:2031A000B005A92020EEFFA220A004AD560D20E1B1AD550D20E1B1A92020EEFFA000B1F282 -:2031C000F00820EEFFC8C00CD0F4A92020EEFFC8C00DD0F8AAA00FB1F2D002A2508A4CEEDB -:2031E000FF484A4A4A4A20EAB168290FF008A2301869304CEEFF88D002A2308A4CEEFFA2C0 -:20320000006885A06885A1A000F007B1A0F00B2021B2E6A0D0F5E6A1D0F1A5A148A5A0480F -:2032200060E000D0034CEEFF9D0001E86008101C2243494F58283C6472763E29003C646EAE -:203240006F3E2F3C6473703E003C646E6F3E0028283C66726F6D20646E6F3E29203C746FCF -:2032600020646E6F3E2920283C616473703E29003C6472763E003C6673703E00283C6D6F2A -:2032800064653E2900283C726F6D3E2900484A4A4A4A2098B268290FA8F014A9202021B203 -:2032A000B92CB2A8B92DB2F0062021B2C8D0F560A2008E0001E82001B21A53796E746178D4 -:2032C0003A2000A4B5B9F8AE30062021B2C8D0F5C8C8B9F8AEC884B5208DB2E000F008A956 -:2032E000009D00014C0001604CB0B2206BB0B017207EB0B0BB48206BB06890B4D0268A8DDE -:203300005B0DC904B01E60A5CF60206BB0B0A1207EB0B09C48206BB068909560206BB0B0F5 -:203320008F4C75B32000A0CD426164206472697665002000A0D64469736B206E6F742066A4 -:203340006F756E6400206BB0B09EA9FF205DB308E004B0332860206BB0B08DA5CF8D5B0D1E -:20336000207EB0B02648206BB0B01568D0B6E004B0B28E5B0D207EB0B01148206BB090078E -:20338000686A8AAE5B0D60684CB0B220F6B020BBADAD5C0DF0F2AD5E0DD0EDAD540D30925A -:2033A000206EB1900620E0AD4C9BB3AD540D6AAD530DAE5B0D60201CB3A6CF201BAC4C0758 -:2033C000942056B34C1BACA9008D570D8D580D207EB0B02D8E590D8E530D8D5A0D8D540DA2 -:2033E000207EB0B0258E590D8D5A0DEC530DED540D101F2000A0FF4261642072616E676506 -:2034000000A2FE8E590DE88E5A0DA9008D530D8D540DEE590DD003EE5A0D20F6B0AD540D67 -:203420006AAD530D2085ADA200AD5C0DD004CA8E5E0DAD540D3033AD530DCD590DAD540DB5 -:20344000ED5A0DB025206EB1B01620A0B1F818AD570D69018D570DAD580D69008D580DD80C -:2034600024FF304720E0AD4C32B4A98620F4FFE000F00320E7FFAD580DA200A00420E1B1AE -:20348000AD570D20E1B120FFB1206469736B00AD580DD005CE570DF005A97320EEFF20FF78 -:2034A000B120666F756E64004CE7FF4C82A04CB0B2206BB090F8A2008E570D8E580D8E59A0 -:2034C0000D8E5A0DA980209CACA91085F2A90E85F3A00FB1F2C9FFF042F8A8100E18AD57D4 -:2034E0000D69018D570D9003EE580D18AD590D69018D590D9003EE5A0DD818A5F269108589 -:20350000F2D0CEA5F3490185F36AB0C5AD82106902C9A0F006209CAC4CD1B4A004A200ADAD -:20352000580D20E1B1AD570D20E1B120FFB1206F662000A200A004AD5A0D20E1B1AD590DAD -:2035400020E1B120FFB1206469736B00AD5A0DD007AD590DC901F005A97320EEFF20FFB168 -:2035600020667265652028756E666F726D617474656429004CE7FF20EBB2A2048E5B0DA242 -:2035800000B006AAE88E5B0DCA8A48A220A00220E1B1A93A20EEFF68AA48BD100D300F6A6E -:2035A000BD0C0D2085ADC9FFF0043820A0B120E7FF68AAE8EC5B0D90D0604CB0B2A900F023 -:2035C00002A90F48201CB320CDAB300E68B00599000E900399000F4CCDACC9FFF0034C65F4 -:2035E000AC4C4BAC20BD9B200AB36A088A4820CDAB30E768282085AD20FFB14B696C6C0056 -:203600003820A0B120FFB1203A2000209E9C0820E7FF28D009A00FA9F091F24CCDAC60A9B5 -:20362000002029B64C6FABA9018D5F0D200AB36A088A4820CDAB1026AAE8F03D9829F0859E -:20364000F2A00E9001C884F3A00F9891F2AD5F0DD0068891F28810FB20CDAC6828602000FA -:20366000A0FF4469736B20616C726561647920666F726D6174746564004C4BAC20EBB28DAB -:203680005B0D20E0B60848A90F91F288A90091F28810FB20B8AC68280848206FAB68280804 -:2036A00048AE5B0D201BAC20FFB14469736B2000682820CDA98E550DA200A00420E1B1AD8F -:2036C000550D20E1B120FFB120696E2064726976652000AD5B0DA200A00220E1B14CE7FF78 -:2036E000A91085F2A90E85F3A9808D520D20A1ACA9008D530D8D540DA00FB1F2100CC9FF2F -:20370000F036AD540D6AAD530D60EE530DD003EE540D18A5F2691085F2D0DFA5F349018579 -:20372000F32901D0D518AD520D6902C9A0F0098D520D20A1AC4CF8B62000A0FF4E6F206681 -:20374000726565206469736B73002045B308488A48A98020A1AC68AA689D000E6829019DCB -:20376000040E4CB8AC206BB0A200B00B207EB0B016C900F002A2018E040D20E28DA2FFA905 -:20378000618D520D4C17AD2000A0FF42616420647269766572206D6F646500A21EBC020D0A -:2037A000BD210D9D020D989D210DCA10F08E821060A90085A620C2FFF06BB1F2C8C920F071 -:2037C000F9B1F288C920D023B1F238E930301CC90A9014E907C90A9012C910900AE920C988 -:2037E0000A9008C910B004C8C885A6A5F485A79848A024B9E7B899520D8810F7A20F205274 -:203800000D68A886A68A10142000A0FF4E6F2053696465776179732052414D0020628218B0 -:2038200020C2FFD0034CB0B220FE8098207182B90E0F48290385A1B90F0F85A0684A4A294C -:2038400003F0044903D016B90C0FD011B90D0F300C85A5A205C940F0150ACAD0F82000A03E -:20386000FF42616420524F4D2073697A650046A5A6CF207EAA18A5A265A085A2A5A365A1D8 -:2038800085A3A90065A485A4A01CB9CBB899520D8810F7A5A68D530DA5A78D690D20ECA46F -:2038A000A9FF8D8210200FA620520D18A5A2690285A29006E6A3D002E6A3EE5E0DEE5E0DD0 -:2038C000EE640DEE640DC6A5D0DB60A9008D30FEA000B9000E990080B9000F99008188D096 -:2038E000F1A9008D30FE608E30FEADFFBFA849FF8DFFBF984DFFBF8CFFBFC9FFD004C6A6BC -:203900003003CA10E2A5A78D30FE6048A5CF8D200D6860A000B1B03007290385CF8D200DA1 -:20392000A005B1B018690785BE2037B9A4BEB002A90091B0A90060C8B1B0AA293F85BFC957 -:203940003AD02BA5BEC909D013C8B1B0C923D00CC8B1B02920F002A9028D200D1860A91E21 -:203960003860A9103860A9123860A9FF3860A5CF6A8A900249C02A900C2AB0E2AD200D2943 -:20398000020901D0082A90DAAD200D29028D200DAA86C0BD100D30CAA5BFC913F00BC90B1D -:2039A000D0BABD1C0DC954D0BDA5BEC90AD0BB20ECA4A90085C5C8B1B0C950B0A10A85C4A3 -:2039C0000A26C50A26C565C485C49002E6C5C8B1B0C90AB0621865C485C49002E6C5C8B100 -:2039E000B0291F85A5F0461865C4AAA90065C5C9039006D042E021B03EA6C0BD100D6ABDE7 -:203A00000C0D2087AA18A5A265C485A2A5A365C585A39002E6A4A00084A7C8B1B085A0C8F6 -:203A2000B1B085A1A5BFC913F00520ABAB18602042A620CDA01860A91E3860544553532011 -:203A4000544553532054455353205445535320544553532054455353205445535320544593 -:203A6000535320544553532054455353205445535320544553532054455353205445535366 -:203A8000205445535320544553532054455353205445535320544553532054455353205478 -:203AA000455353205445535320544553532054455353205445535320544553532054455334 -:203AC000532054455353205445535320544553532054455353205445535320544553532039 -:203AE0005445535320544553532054455353205445535320544553532054455353205445F3 -:203B00005353205445535320544553532054455353205445535320544553532054455353C5 -:203B20002054455353205445535320544553532054455353205445535320544553532054D7 -:203B4000455353205445535320544553532054455353205445535320544553532054455393 -:203B6000532054455353205445535320544553532054455353205445535320544553532098 -:203B8000544553532054455353205445535320544553532054455353205445535320544552 -:203BA000535320544553532054455353205445535320544553532054455353205445535325 -:203BC000205445535320544553532054455353205445535320544553532054455353205437 -:203BE0004553532054455353205445535320544553532054455353205445535320544553F3 -:203C00005320544553532054455353205445535320544553532054455353205445535320F7 -:203C20005445535320544553532054455353205445535320544553532054455353205445B1 -:203C4000535320544553532054455353205445535320544553532054455353205445535384 -:203C6000205445535320544553532054455353205445535320544553532054455353205496 -:203C8000455353205445535320544553532054455353205445535320544553532054455352 -:203CA000532054455353205445535320544553532054455353205445535320544553532057 -:203CC000544553532054455353205445535320544553532054455353205445535320544511 -:203CE0005353205445535320544553532054455353205445535320544553532054455353E4 -:203D00002054455353205445535320544553532054455353205445535320544553532054F5 -:203D20004553532054455353205445535320544553532054455353205445535320544553B1 -:203D40005320544553532054455353205445535320544553532054455353205445535320B6 -:203D6000544553532054455353205445535320544553532054455353205445535320544570 -:203D8000535320544553532054455353205445535320544553532054455353205445535343 -:203DA000205445535320544553532054455353205445535320544553532054455353205455 -:203DC000455353205445535320544553532054455353205445535320544553532054455311 -:203DE000532054455353205445535320544553532054455353205445535320544553532016 -:203E00005445535320544553532054455353205445535320544553532054455353205445CF -:203E20005353205445535320544553532054455353205445535320544553532054455353A2 -:203E40002054455353205445535320544553532054455353205445535320544553532054B4 -:203E6000455353205445535320544553532054455353205445535320544553532054455370 -:203E8000532054455353205445535320544553532054455353205445535320544553532075 -:203EA00054455353205445535320544553532054455353205445535320544553532054452F -:203EC000535320544553532054455353205445535320544553532054455353205445535302 -:203EE000205445535320544553532054455353205445535320544553532054455353205414 -:203F00004553532054455353205445535320544553532054455353205445535320544553CF -:203F20005320544553532054455353205445535320544553532054455353205445535320D4 -:203F400054455353205445535320544553532054455353205445535320544553532054458E -:203F6000535320544553532054455353205445535320544553532054455353205445535361 -:203F8000205445535320544553532054455353205445535320544553532054455353205473 -:203FA00045535320544553532054455353205445535320544553532054455353205445532F -:203FC000532054455353205445535320544553532054455353205445535320544553532034 -:203FE0005445535320544553532054455353205445535320544553532054455353205445EE -:00000001FF diff --git a/cores/bbc/roms/smmc.rom b/cores/bbc/roms/smmc.rom deleted file mode 100644 index 9b4e952..0000000 Binary files a/cores/bbc/roms/smmc.rom and /dev/null differ diff --git a/cores/bbc/rtl/ALU.v b/cores/bbc/rtl/ALU.v deleted file mode 100755 index 8d05fc0..0000000 --- a/cores/bbc/rtl/ALU.v +++ /dev/null @@ -1,108 +0,0 @@ -/* - * ALU. - * - * AI and BI are 8 bit inputs. Result in OUT. - * CI is Carry In. - * CO is Carry Out. - * - * op[3:0] is defined as follows: - * - * 0011 AI + BI - * 0111 AI - BI - * 1011 AI + AI - * 1100 AI | BI - * 1101 AI & BI - * 1110 AI ^ BI - * 1111 AI - * - */ - -module ALU( clk, op, right, AI, BI, CI, CO, BCD, OUT, V, Z, N, HC, RDY ); - input clk; - input right; - input [3:0] op; // operation - input [7:0] AI; - input [7:0] BI; - input CI; - input BCD; // BCD style carry - output [7:0] OUT; - output CO; - output V; - output Z; - output N; - output HC; - input RDY; - -reg [7:0] OUT; -reg CO; -wire V; -wire Z; -reg N; -reg HC; - -reg AI7; -reg BI7; -reg [8:0] temp_logic; -reg [7:0] temp_BI; -reg [4:0] temp_l; -reg [4:0] temp_h; -wire [8:0] temp = { temp_h, temp_l[3:0] }; -wire adder_CI = (right | (op[3:2] == 2'b11)) ? 0 : CI; - -// calculate the logic operations. The 'case' can be done in 1 LUT per -// bit. The 'right' shift is a simple mux that can be implemented by -// F5MUX. -always @* begin - case( op[1:0] ) - 2'b00: temp_logic = AI | BI; - 2'b01: temp_logic = AI & BI; - 2'b10: temp_logic = AI ^ BI; - 2'b11: temp_logic = AI; - endcase - - if( right ) - temp_logic = { AI[0], CI, AI[7:1] }; -end - -// Add logic result to BI input. This only makes sense when logic = AI. -// This stage can be done in 1 LUT per bit, using carry chain logic. -always @* begin - case( op[3:2] ) - 2'b00: temp_BI = BI; // A+B - 2'b01: temp_BI = ~BI; // A-B - 2'b10: temp_BI = temp_logic; // A+A - 2'b11: temp_BI = 0; // A+0 - endcase -end - -// HC9 is the half carry bit when doing BCD add -wire HC9 = BCD & (temp_l[3:1] >= 3'd5); - -// CO9 is the carry-out bit when doing BCD add -wire CO9 = BCD & (temp_h[3:1] >= 3'd5); - -// combined half carry bit -wire temp_HC = temp_l[4] | HC9; - -// perform the addition as 2 separate nibble, so we get -// access to the half carry flag -always @* begin - temp_l = temp_logic[3:0] + temp_BI[3:0] + adder_CI; - temp_h = temp_logic[8:4] + temp_BI[7:4] + temp_HC; -end - -// calculate the flags -always @(posedge clk) - if( RDY ) begin - AI7 <= AI[7]; - BI7 <= temp_BI[7]; - OUT <= temp[7:0]; - CO <= temp[8] | CO9; - N <= temp[7]; - HC <= temp_HC; - end - -assign V = AI7 ^ BI7 ^ CO ^ N; -assign Z = ~|OUT; - -endmodule diff --git a/cores/bbc/rtl/T65/T65.qip b/cores/bbc/rtl/T65/T65.qip new file mode 100644 index 0000000..a5ea77b --- /dev/null +++ b/cores/bbc/rtl/T65/T65.qip @@ -0,0 +1,4 @@ +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "T65_Pack.vhd"] +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "T65_MCode.vhd"] +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "T65_ALU.vhd"] +set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "T65.vhd"] diff --git a/cores/bbc/rtl/T65/T65.vhd b/cores/bbc/rtl/T65/T65.vhd new file mode 100755 index 0000000..b9fa335 --- /dev/null +++ b/cores/bbc/rtl/T65/T65.vhd @@ -0,0 +1,668 @@ +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- Ver 313 WoS January 2015 +-- Fixed issue that NMI has to be first if issued the same time as a BRK instruction is latched in +-- Now all Lorenz CPU tests on FPGAARCADE C64 core (sources used: SVN version 1021) are OK! :D :D :D +-- This is just a starting point to go for optimizations and detailed fixes (the Lorenz test can't find) +-- +-- Ver 312 WoS January 2015 +-- Undoc opcode timing fixes for $B3 (LAX iy) and $BB (LAS ay) +-- Added comments in MCode section to find handling of individual opcodes more easily +-- All "basic" Lorenz instruction test (individual functional checks, CPUTIMING check) work now with +-- actual FPGAARCADE C64 core (sources used: SVN version 1021). +-- +-- Ver 305, 306, 307, 308, 309, 310, 311 WoS January 2015 +-- Undoc opcode fixes (now all Lorenz test on instruction functionality working, except timing issues on $B3 and $BB): +-- SAX opcode +-- SHA opcode +-- SHX opcode +-- SHY opcode +-- SHS opcode +-- LAS opcode +-- alternate SBC opcode +-- fixed NOP with immediate param (caused Lorenz trap test to fail) +-- IRQ and NMI timing fixes (in conjuction with branches) +-- +-- Ver 304 WoS December 2014 +-- Undoc opcode fixes: +-- ARR opcode +-- ANE/XAA opcode +-- Corrected issue with NMI/IRQ prio (when asserted the same time) +-- +-- Ver 303 ost(ML) July 2014 +-- (Sorry for some scratchpad comments that may make little sense) +-- Mods and some 6502 undocumented instructions. +-- Not correct opcodes acc. to Lorenz tests (incomplete list): +-- NOPN (nop) +-- NOPZX (nop + byte 172) +-- NOPAX (nop + word da ... da: byte 0) +-- ASOZ (byte $07 + byte 172) +-- +-- Ver 303,302 WoS April 2014 +-- Bugfixes for NMI from foft +-- Bugfix for BRK command (and its special flag) +-- +-- Ver 300,301 WoS January 2014 +-- More merging +-- Bugfixes by ehenciak added, started tidyup *bust* +-- +-- MikeJ March 2005 +-- Latest version from www.fpgaarcade.com (original www.opencores.org) +-- **** +-- +-- 65xx compatible microprocessor core +-- +-- FPGAARCADE SVN: $Id: T65.vhd 1347 2015-05-27 20:07:34Z wolfgang.scherr $ +-- +-- Copyright (c) 2002...2015 +-- Daniel Wallner (jesus opencores org) +-- Mike Johnson (mikej fpgaarcade com) +-- Wolfgang Scherr (WoS pin4 at> +-- Morten Leikvoll () +-- +-- 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(s), 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. +-- +-- ----- IMPORTANT NOTES ----- +-- +-- Limitations: +-- 65C02 and 65C816 modes are incomplete (and definitely untested after all 6502 undoc fixes) +-- 65C02 supported : inc, dec, phx, plx, phy, ply +-- 65D02 missing : bra, ora, lda, cmp, sbc, tsb*2, trb*2, stz*2, bit*2, wai, stp, jmp, bbr*8, bbs*8 +-- Some interface signals behave incorrect +-- NMI interrupt handling not nice, needs further rework (to cycle-based encoding). +-- +-- Usage: +-- The enable signal allows clock gating / throttling without using the ready signal. +-- Set it to constant '1' when using the Clk input as the CPU clock directly. +-- +-- TAKE CARE you route the DO signal back to the DI signal while R_W_n='0', +-- otherwise some undocumented opcodes won't work correctly. +-- EXAMPLE: +-- CPU : entity work.T65 +-- port map ( +-- R_W_n => cpu_rwn_s, +-- [....all other ports....] +-- DI => cpu_din_s, +-- DO => cpu_dout_s +-- ); +-- cpu_din_s <= cpu_dout_s when cpu_rwn_s='0' else +-- [....other sources from peripherals and memories...] +-- +-- ----- IMPORTANT NOTES ----- +-- + +library IEEE; + use IEEE.std_logic_1164.all; + use IEEE.numeric_std.all; + use work.T65_Pack.all; + +entity T65 is + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 + Res_n : in std_logic; + Enable : in std_logic; + Clk : in std_logic; + Rdy : in std_logic; + Abort_n : in std_logic; + IRQ_n : in std_logic; + NMI_n : in std_logic; + SO_n : in std_logic; + R_W_n : out std_logic; + Sync : out std_logic; + EF : out std_logic; + MF : out std_logic; + XF : out std_logic; + ML_n : out std_logic; + VP_n : out std_logic; + VDA : out std_logic; + VPA : out std_logic; + A : out std_logic_vector(23 downto 0); + DI : in std_logic_vector(7 downto 0); + DO : out std_logic_vector(7 downto 0); + -- 6502 registers (MSB) PC, SP, P, Y, X, A (LSB) + Regs : out std_logic_vector(63 downto 0); + DEBUG : out T_t65_dbg + ); +end T65; + +architecture rtl of T65 is + + -- Registers + signal ABC, X, Y : std_logic_vector(15 downto 0); + signal P, AD, DL : std_logic_vector(7 downto 0) := x"00"; + signal PwithB : std_logic_vector(7 downto 0);--ML:New way to push P with correct B state to stack + signal BAH : std_logic_vector(7 downto 0); + signal BAL : std_logic_vector(8 downto 0); + signal PBR : std_logic_vector(7 downto 0); + signal DBR : std_logic_vector(7 downto 0); + signal PC : unsigned(15 downto 0); + signal S : unsigned(15 downto 0); + signal EF_i : std_logic; + signal MF_i : std_logic; + signal XF_i : std_logic; + + signal IR : std_logic_vector(7 downto 0); + signal MCycle : std_logic_vector(2 downto 0); + + signal Mode_r : std_logic_vector(1 downto 0); + signal ALU_Op_r : T_ALU_Op; + signal Write_Data_r : T_Write_Data; + signal Set_Addr_To_r : T_Set_Addr_To; + signal PCAdder : unsigned(8 downto 0); + + signal RstCycle : std_logic; + signal IRQCycle : std_logic; + signal NMICycle : std_logic; + + signal SO_n_o : std_logic; + signal IRQ_n_o : std_logic; + signal NMI_n_o : std_logic; + signal NMIAct : std_logic; + + signal Break : std_logic; + + -- ALU signals + signal BusA : std_logic_vector(7 downto 0); + signal BusA_r : std_logic_vector(7 downto 0); + signal BusB : std_logic_vector(7 downto 0); + signal BusB_r : std_logic_vector(7 downto 0); + signal ALU_Q : std_logic_vector(7 downto 0); + signal P_Out : std_logic_vector(7 downto 0); + + -- Micro code outputs + signal LCycle : std_logic_vector(2 downto 0); + signal ALU_Op : T_ALU_Op; + signal Set_BusA_To : T_Set_BusA_To; + signal Set_Addr_To : T_Set_Addr_To; + signal Write_Data : T_Write_Data; + signal Jump : std_logic_vector(1 downto 0); + signal BAAdd : std_logic_vector(1 downto 0); + signal BreakAtNA : std_logic; + signal ADAdd : std_logic; + signal AddY : std_logic; + signal PCAdd : std_logic; + signal Inc_S : std_logic; + signal Dec_S : std_logic; + signal LDA : std_logic; + signal LDP : std_logic; + signal LDX : std_logic; + signal LDY : std_logic; + signal LDS : std_logic; + signal LDDI : std_logic; + signal LDALU : std_logic; + signal LDAD : std_logic; + signal LDBAL : std_logic; + signal LDBAH : std_logic; + signal SaveP : std_logic; + signal Write : std_logic; + + signal Res_n_i : std_logic; + signal Res_n_d : std_logic; + + signal really_rdy : std_logic; + signal WRn_i : std_logic; + + signal NMI_entered : std_logic; + +begin + -- gate Rdy with read/write to make an "OK, it's really OK to stop the processor + really_rdy <= Rdy or not(WRn_i); + Sync <= '1' when MCycle = "000" else '0'; + EF <= EF_i; + MF <= MF_i; + XF <= XF_i; + R_W_n <= WRn_i; + ML_n <= '0' when IR(7 downto 6) /= "10" and IR(2 downto 1) = "11" and MCycle(2 downto 1) /= "00" else '1'; + VP_n <= '0' when IRQCycle = '1' and (MCycle = "101" or MCycle = "110") else '1'; + VDA <= '1' when Set_Addr_To_r /= Set_Addr_To_PBR else '0'; + VPA <= '1' when Jump(1) = '0' else '0'; + + -- debugging signals + DEBUG.I <= IR; + DEBUG.A <= ABC(7 downto 0); + DEBUG.X <= X(7 downto 0); + DEBUG.Y <= Y(7 downto 0); + DEBUG.S <= std_logic_vector(S(7 downto 0)); + DEBUG.P <= P; + + Regs <= std_logic_vector(PC) & std_logic_vector(S)& P & Y(7 downto 0) & X(7 downto 0) & ABC(7 downto 0); + + mcode : entity work.T65_MCode + port map( +--inputs + Mode => Mode_r, + IR => IR, + MCycle => MCycle, + P => P, +--outputs + LCycle => LCycle, + ALU_Op => ALU_Op, + Set_BusA_To => Set_BusA_To, + Set_Addr_To => Set_Addr_To, + Write_Data => Write_Data, + Jump => Jump, + BAAdd => BAAdd, + BreakAtNA => BreakAtNA, + ADAdd => ADAdd, + AddY => AddY, + PCAdd => PCAdd, + Inc_S => Inc_S, + Dec_S => Dec_S, + LDA => LDA, + LDP => LDP, + LDX => LDX, + LDY => LDY, + LDS => LDS, + LDDI => LDDI, + LDALU => LDALU, + LDAD => LDAD, + LDBAL => LDBAL, + LDBAH => LDBAH, + SaveP => SaveP, + Write => Write + ); + + alu : entity work.T65_ALU + port map( + Mode => Mode_r, + Op => ALU_Op_r, + BusA => BusA_r, + BusB => BusB, + P_In => P, + P_Out => P_Out, + Q => ALU_Q + ); + + -- the 65xx design requires at least two clock cycles before + -- starting its reset sequence (according to datasheet) + process (Res_n, Clk) + begin + if Res_n = '0' then + Res_n_i <= '0'; + Res_n_d <= '0'; + elsif Clk'event and Clk = '1' then + Res_n_i <= Res_n_d; + Res_n_d <= '1'; + end if; + end process; + + process (Res_n_i, Clk) + begin + if Res_n_i = '0' then + PC <= (others => '0'); -- Program Counter + IR <= "00000000"; + S <= (others => '0'); -- Dummy + PBR <= (others => '0'); + DBR <= (others => '0'); + + Mode_r <= (others => '0'); + ALU_Op_r <= ALU_OP_BIT; + Write_Data_r <= Write_Data_DL; + Set_Addr_To_r <= Set_Addr_To_PBR; + + WRn_i <= '1'; + EF_i <= '1'; + MF_i <= '1'; + XF_i <= '1'; + + elsif Clk'event and Clk = '1' then + if (Enable = '1') then + if (really_rdy = '1') then + WRn_i <= not Write or RstCycle; + + PBR <= (others => '1'); -- Dummy + DBR <= (others => '1'); -- Dummy + EF_i <= '0'; -- Dummy + MF_i <= '0'; -- Dummy + XF_i <= '0'; -- Dummy + + if MCycle = "000" then + Mode_r <= Mode; + + if IRQCycle = '0' and NMICycle = '0' then + PC <= PC + 1; + end if; + + if IRQCycle = '1' or NMICycle = '1' then + IR <= "00000000"; + else + IR <= DI; + end if; + + if LDS = '1' then -- LAS won't work properly if not limited to machine cycle 0 + S(7 downto 0) <= unsigned(ALU_Q); + end if; + end if; + + ALU_Op_r <= ALU_Op; + Write_Data_r <= Write_Data; + if Break = '1' then + Set_Addr_To_r <= Set_Addr_To_PBR; + else + Set_Addr_To_r <= Set_Addr_To; + end if; + + if Inc_S = '1' then + S <= S + 1; + end if; + if Dec_S = '1' and RstCycle = '0' then + S <= S - 1; + end if; + + if IR = "00000000" and MCycle = "001" and IRQCycle = '0' and NMICycle = '0' then + PC <= PC + 1; + end if; + -- + -- jump control logic + -- + case Jump is + when "01" => + PC <= PC + 1; + when "10" => + PC <= unsigned(DI & DL); + when "11" => + if PCAdder(8) = '1' then + if DL(7) = '0' then + PC(15 downto 8) <= PC(15 downto 8) + 1; + else + PC(15 downto 8) <= PC(15 downto 8) - 1; + end if; + end if; + PC(7 downto 0) <= PCAdder(7 downto 0); + when others => null; + end case; + end if; + end if; + end if; + end process; + + PCAdder <= resize(PC(7 downto 0),9) + resize(unsigned(DL(7) & DL),9) when PCAdd = '1' + else "0" & PC(7 downto 0); + + process (Res_n_i, Clk) + variable tmpP:std_logic_vector(7 downto 0);--Lets try to handle loading P at mcycle=0 and set/clk flags at same cycle + begin + if Res_n_i = '0' then + P <= x"00"; -- ensure we have nothing set on reset + elsif Clk'event and Clk = '1' then + tmpP:=P; + if (Enable = '1') then + if (really_rdy = '1') then + if MCycle = "000" then + if LDA = '1' then + ABC(7 downto 0) <= ALU_Q; + end if; + if LDX = '1' then + X(7 downto 0) <= ALU_Q; + end if; + if LDY = '1' then + Y(7 downto 0) <= ALU_Q; + end if; + if (LDA or LDX or LDY) = '1' then + tmpP:=P_Out; + end if; + end if; + if SaveP = '1' then + tmpP:=P_Out; + end if; + if LDP = '1' then + tmpP:=ALU_Q; + end if; + if IR(4 downto 0) = "11000" then + case IR(7 downto 5) is + when "000" =>--0x18(clc) + tmpP(Flag_C) := '0'; + when "001" =>--0x38(sec) + tmpP(Flag_C) := '1'; + when "010" =>--0x58(cli) + tmpP(Flag_I) := '0'; + when "011" =>--0x78(sei) + tmpP(Flag_I) := '1'; + when "101" =>--0xb8(clv) + tmpP(Flag_V) := '0'; + when "110" =>--0xd8(cld) + tmpP(Flag_D) := '0'; + when "111" =>--0xf8(sed) + tmpP(Flag_D) := '1'; + when others => + end case; + end if; + tmpP(Flag_B) := '1'; + if IR = "00000000" and MCycle = "100" and RstCycle = '0' then + --This should happen after P has been pushed to stack + tmpP(Flag_I) := '1'; + end if; + if SO_n_o = '1' and SO_n = '0' then + tmpP(Flag_V) := '1'; + end if; + if RstCycle = '1' then + tmpP(Flag_I) := '1'; + tmpP(Flag_D) := '0'; + end if; + tmpP(Flag_1) := '1'; + + P<=tmpP;--new way + + SO_n_o <= SO_n; + if IR(4 downto 0)/="10000" or Jump/="01" then -- delay interrupts during branches (checked with Lorenz test and real 6510), not best way yet, though - but works... + IRQ_n_o <= IRQ_n; + end if; + end if; + -- detect nmi even if not rdy + if IR(4 downto 0)/="10000" or Jump/="01" then -- delay interrupts during branches (checked with Lorenz test and real 6510) not best way yet, though - but works... + NMI_n_o <= NMI_n; + end if; + end if; + end if; + end process; + +--------------------------------------------------------------------------- +-- +-- Buses +-- +--------------------------------------------------------------------------- + + process (Res_n_i, Clk) + begin + if Res_n_i = '0' then + BusA_r <= (others => '0'); + BusB <= (others => '0'); + BusB_r <= (others => '0'); + AD <= (others => '0'); + BAL <= (others => '0'); + BAH <= (others => '0'); + DL <= (others => '0'); + elsif Clk'event and Clk = '1' then + if (Enable = '1') then + NMI_entered <= '0'; + if (really_rdy = '1') then + BusA_r <= BusA; + BusB <= DI; + + -- not really nice, but no better way found yet ! + if Set_Addr_To_r = Set_Addr_To_PBR or Set_Addr_To_r = Set_Addr_To_ZPG then + BusB_r <= std_logic_vector(unsigned(DI(7 downto 0)) + 1); -- required for SHA + end if; + + case BAAdd is + when "01" => + -- BA Inc + AD <= std_logic_vector(unsigned(AD) + 1); + BAL <= std_logic_vector(unsigned(BAL) + 1); + when "10" => + -- BA Add + BAL <= std_logic_vector(resize(unsigned(BAL(7 downto 0)),9) + resize(unsigned(BusA),9)); + when "11" => + -- BA Adj + if BAL(8) = '1' then + BAH <= std_logic_vector(unsigned(BAH) + 1); + end if; + when others => + end case; + + -- modified to use Y register as well + if ADAdd = '1' then + if (AddY = '1') then + AD <= std_logic_vector(unsigned(AD) + unsigned(Y(7 downto 0))); + else + AD <= std_logic_vector(unsigned(AD) + unsigned(X(7 downto 0))); + end if; + end if; + + if IR = "00000000" then + BAL <= (others => '1'); + BAH <= (others => '1'); + if RstCycle = '1' then + BAL(2 downto 0) <= "100"; + elsif NMICycle = '1' or (NMIAct = '1' and MCycle="100") or NMI_entered='1' then + BAL(2 downto 0) <= "010"; + if MCycle="100" then + NMI_entered <= '1'; + end if; + else + BAL(2 downto 0) <= "110"; + end if; + if Set_addr_To_r = Set_Addr_To_BA then + BAL(0) <= '1'; + end if; + end if; + + if LDDI = '1' then + DL <= DI; + end if; + if LDALU = '1' then + DL <= ALU_Q; + end if; + if LDAD = '1' then + AD <= DI; + end if; + if LDBAL = '1' then + BAL(7 downto 0) <= DI; + end if; + if LDBAH = '1' then + BAH <= DI; + end if; + end if; + end if; + end if; + end process; + + Break <= (BreakAtNA and not BAL(8)) or (PCAdd and not PCAdder(8)); + + with Set_BusA_To select + BusA <= + DI when Set_BusA_To_DI, + ABC(7 downto 0) when Set_BusA_To_ABC, + X(7 downto 0) when Set_BusA_To_X, + Y(7 downto 0) when Set_BusA_To_Y, + std_logic_vector(S(7 downto 0)) when Set_BusA_To_S, + P when Set_BusA_To_P, + ABC(7 downto 0) and DI when Set_BusA_To_DA, + (ABC(7 downto 0) or x"ee") and DI when Set_BusA_To_DAO,--ee for OAL instruction. constant may be different on other platforms.TODO:Move to generics + (ABC(7 downto 0) or x"ee") and DI and X(7 downto 0) when Set_BusA_To_DAX,--XAA, ee for OAL instruction. constant may be different on other platforms.TODO:Move to generics + ABC(7 downto 0) and X(7 downto 0) when Set_BusA_To_AAX,--SAX, SHA + (others => '-') when Set_BusA_To_DONTCARE;--Can probably remove this + + with Set_Addr_To_r select + A <= + "0000000000000001" & std_logic_vector(S(7 downto 0)) when Set_Addr_To_SP, + DBR & "00000000" & AD when Set_Addr_To_ZPG, + "00000000" & BAH & BAL(7 downto 0) when Set_Addr_To_BA, + PBR & std_logic_vector(PC(15 downto 8)) & std_logic_vector(PCAdder(7 downto 0)) when Set_Addr_To_PBR; + + -- This is the P that gets pushed on stack with correct B flag. I'm not sure if NMI also clears B, but I guess it does. + PwithB<=(P and x"ef") when (IRQCycle='1' or NMICycle='1') else P; + + with Write_Data_r select + DO <= + DL when Write_Data_DL, + ABC(7 downto 0) when Write_Data_ABC, + X(7 downto 0) when Write_Data_X, + Y(7 downto 0) when Write_Data_Y, + std_logic_vector(S(7 downto 0)) when Write_Data_S, + PwithB when Write_Data_P, + std_logic_vector(PC(7 downto 0)) when Write_Data_PCL, + std_logic_vector(PC(15 downto 8)) when Write_Data_PCH, + ABC(7 downto 0) and X(7 downto 0) when Write_Data_AX, + ABC(7 downto 0) and X(7 downto 0) and BusB_r(7 downto 0) when Write_Data_AXB, -- no better way found yet... + X(7 downto 0) and BusB_r(7 downto 0) when Write_Data_XB, -- no better way found yet... + Y(7 downto 0) and BusB_r(7 downto 0) when Write_Data_YB, -- no better way found yet... + (others=>'-') when Write_Data_DONTCARE;--Can probably remove this + + +------------------------------------------------------------------------- +-- +-- Main state machine +-- +------------------------------------------------------------------------- + + process (Res_n_i, Clk) + begin + if Res_n_i = '0' then + MCycle <= "001"; + RstCycle <= '1'; + IRQCycle <= '0'; + NMICycle <= '0'; + NMIAct <= '0'; + elsif Clk'event and Clk = '1' then + if (Enable = '1') then + if (really_rdy = '1') then + if MCycle = LCycle or Break = '1' then + MCycle <= "000"; + RstCycle <= '0'; + IRQCycle <= '0'; + NMICycle <= '0'; + if NMIAct = '1' and IR/=x"00" then -- delay NMI further if we just executed a BRK + NMICycle <= '1'; + NMIAct <= '0'; -- reset NMI edge detector if we start processing the NMI + elsif IRQ_n_o = '0' and P(Flag_I) = '0' then + IRQCycle <= '1'; + end if; + else + MCycle <= std_logic_vector(unsigned(MCycle) + 1); + end if; + end if; + --detect NMI even if not rdy + if NMI_n_o = '1' and (NMI_n = '0' and (IR(4 downto 0)/="10000" or Jump/="01")) then -- branches have influence on NMI start (not best way yet, though - but works...) + NMIAct <= '1'; + end if; + -- we entered NMI during BRK instruction + if NMI_entered='1' then + NMIAct <= '0'; + end if; + end if; + end if; + end process; + +end; diff --git a/cores/bbc/rtl/T65/T65_ALU.vhd b/cores/bbc/rtl/T65/T65_ALU.vhd new file mode 100755 index 0000000..c076ab0 --- /dev/null +++ b/cores/bbc/rtl/T65/T65_ALU.vhd @@ -0,0 +1,293 @@ +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- See list of changes in T65 top file (T65.vhd)... +-- +-- **** +-- 65xx compatible microprocessor core +-- +-- FPGAARCADE SVN: $Id: T65_ALU.vhd 1234 2015-02-28 20:14:50Z wolfgang.scherr $ +-- +-- Copyright (c) 2002...2015 +-- Daniel Wallner (jesus opencores org) +-- Mike Johnson (mikej fpgaarcade com) +-- Wolfgang Scherr (WoS pin4 at> +-- Morten Leikvoll () +-- +-- 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(s), 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. +-- +-- Limitations : +-- See in T65 top file (T65.vhd)... + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use work.T65_Pack.all; + +entity T65_ALU is + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 + Op : in T_ALU_OP; + BusA : in std_logic_vector(7 downto 0); + BusB : in std_logic_vector(7 downto 0); + P_In : in std_logic_vector(7 downto 0); + P_Out : out std_logic_vector(7 downto 0); + Q : out std_logic_vector(7 downto 0) + ); +end T65_ALU; + +architecture rtl of T65_ALU is + + -- AddSub variables (temporary signals) + signal ADC_Z : std_logic; + signal ADC_C : std_logic; + signal ADC_V : std_logic; + signal ADC_N : std_logic; + signal ADC_Q : std_logic_vector(7 downto 0); + signal SBC_Z : std_logic; + signal SBC_C : std_logic; + signal SBC_V : std_logic; + signal SBC_N : std_logic; + signal SBC_Q : std_logic_vector(7 downto 0); + signal SBX_Q : std_logic_vector(7 downto 0); + +begin + + process (P_In, BusA, BusB) + variable AL : unsigned(6 downto 0); + variable AH : unsigned(6 downto 0); + variable C : std_logic; + begin + AL := resize(unsigned(BusA(3 downto 0) & P_In(Flag_C)), 7) + resize(unsigned(BusB(3 downto 0) & "1"), 7); + AH := resize(unsigned(BusA(7 downto 4) & AL(5)), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7); + +-- pragma translate_off + if is_x(std_logic_vector(AL)) then AL := "0000000"; end if; + if is_x(std_logic_vector(AH)) then AH := "0000000"; end if; +-- pragma translate_on + + if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then + ADC_Z <= '1'; + else + ADC_Z <= '0'; + end if; + + if AL(5 downto 1) > 9 and P_In(Flag_D) = '1' then + AL(6 downto 1) := AL(6 downto 1) + 6; + end if; + + C := AL(6) or AL(5); + AH := resize(unsigned(BusA(7 downto 4) & C), 7) + resize(unsigned(BusB(7 downto 4) & "1"), 7); + + ADC_N <= AH(4); + ADC_V <= (AH(4) xor BusA(7)) and not (BusA(7) xor BusB(7)); + +-- pragma translate_off + if is_x(std_logic_vector(AH)) then AH := "0000000"; end if; +-- pragma translate_on + + if AH(5 downto 1) > 9 and P_In(Flag_D) = '1' then + AH(6 downto 1) := AH(6 downto 1) + 6; + end if; + + ADC_C <= AH(6) or AH(5); + + ADC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); + end process; + + process (Op, P_In, BusA, BusB) + variable AL : unsigned(6 downto 0); + variable AH : unsigned(5 downto 0); + variable C : std_logic; + variable CT : std_logic; + begin + CT:='0'; + if( Op=ALU_OP_AND or --"0001" These OpCodes used to have LSB set + Op=ALU_OP_ADC or --"0011" + Op=ALU_OP_EQ2 or --"0101" + Op=ALU_OP_SBC or --"0111" + Op=ALU_OP_ROL or --"1001" + Op=ALU_OP_ROR or --"1011" +-- Op=ALU_OP_EQ3 or --"1101" + Op=ALU_OP_INC --"1111" + ) then + CT:='1'; + end if; + + C := P_In(Flag_C) or not CT;--was: or not Op(0); + AL := resize(unsigned(BusA(3 downto 0) & C), 7) - resize(unsigned(BusB(3 downto 0) & "1"), 6); + AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(5)), 6); + + -- pragma translate_off + if is_x(std_logic_vector(AL)) then AL := "0000000"; end if; + if is_x(std_logic_vector(AH)) then AH := "000000"; end if; + -- pragma translate_on + + if AL(4 downto 1) = 0 and AH(4 downto 1) = 0 then + SBC_Z <= '1'; + else + SBC_Z <= '0'; + end if; + + SBC_C <= not AH(5); + SBC_V <= (AH(4) xor BusA(7)) and (BusA(7) xor BusB(7)); + SBC_N <= AH(4); + + SBX_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); + + if P_In(Flag_D) = '1' then + if AL(5) = '1' then + AL(5 downto 1) := AL(5 downto 1) - 6; + end if; + AH := resize(unsigned(BusA(7 downto 4) & "0"), 6) - resize(unsigned(BusB(7 downto 4) & AL(6)), 6); + if AH(5) = '1' then + AH(5 downto 1) := AH(5 downto 1) - 6; + end if; + end if; + + SBC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); + end process; + + process (Op, P_In, BusA, BusB, + ADC_Z, ADC_C, ADC_V, ADC_N, ADC_Q, + SBC_Z, SBC_C, SBC_V, SBC_N, SBC_Q, + SBX_Q) + variable Q_t : std_logic_vector(7 downto 0); + variable Q2_t : std_logic_vector(7 downto 0); + begin + -- ORA, AND, EOR, ADC, NOP, LD, CMP, SBC + -- ASL, ROL, LSR, ROR, BIT, LD, DEC, INC + P_Out <= P_In; + Q_t := BusA; + Q2_t := BusA; + case Op is + when ALU_OP_OR=> + Q_t := BusA or BusB; + when ALU_OP_AND=> + Q_t := BusA and BusB; + when ALU_OP_EOR=> + Q_t := BusA xor BusB; + when ALU_OP_ADC=> + P_Out(Flag_V) <= ADC_V; + P_Out(Flag_C) <= ADC_C; + Q_t := ADC_Q; + when ALU_OP_CMP=> + P_Out(Flag_C) <= SBC_C; + when ALU_OP_SAX=> + P_Out(Flag_C) <= SBC_C; + Q_t := SBX_Q; -- undoc: subtract (A & X) - (immediate) + when ALU_OP_SBC=> + P_Out(Flag_V) <= SBC_V; + P_Out(Flag_C) <= SBC_C; + Q_t := SBC_Q; -- undoc: subtract (A & X) - (immediate), then decimal correction + when ALU_OP_ASL=> + Q_t := BusA(6 downto 0) & "0"; + P_Out(Flag_C) <= BusA(7); + when ALU_OP_ROL=> + Q_t := BusA(6 downto 0) & P_In(Flag_C); + P_Out(Flag_C) <= BusA(7); + when ALU_OP_LSR=> + Q_t := "0" & BusA(7 downto 1); + P_Out(Flag_C) <= BusA(0); + when ALU_OP_ROR=> + Q_t := P_In(Flag_C) & BusA(7 downto 1); + P_Out(Flag_C) <= BusA(0); + when ALU_OP_ARR=> + Q_t := P_In(Flag_C) & (BusA(7 downto 1) and BusB(7 downto 1)); + P_Out(Flag_V) <= Q_t(5) xor Q_t(6); + Q2_t := Q_t; + if P_In(Flag_D)='1' then + if (BusA(3 downto 0) and BusB(3 downto 0)) > "0100" then + Q2_t(3 downto 0) := std_logic_vector(unsigned(Q_t(3 downto 0)) + x"6"); + end if; + if (BusA(7 downto 4) and BusB(7 downto 4)) > "0100" then + Q2_t(7 downto 4) := std_logic_vector(unsigned(Q_t(7 downto 4)) + x"6"); + P_Out(Flag_C) <= '1'; + else + P_Out(Flag_C) <= '0'; + end if; + else + P_Out(Flag_C) <= Q_t(6); + end if; + when ALU_OP_BIT=> + P_Out(Flag_V) <= BusB(6); + when ALU_OP_DEC=> + Q_t := std_logic_vector(unsigned(BusA) - 1); + when ALU_OP_INC=> + Q_t := std_logic_vector(unsigned(BusA) + 1); + when others => + null; + --EQ1,EQ2,EQ3 passes BusA to Q_t and P_in to P_out + end case; + + case Op is + when ALU_OP_ADC=> + P_Out(Flag_N) <= ADC_N; + P_Out(Flag_Z) <= ADC_Z; + when ALU_OP_CMP|ALU_OP_SBC|ALU_OP_SAX=> + P_Out(Flag_N) <= SBC_N; + P_Out(Flag_Z) <= SBC_Z; + when ALU_OP_EQ1=>--dont touch P + when ALU_OP_BIT=> + P_Out(Flag_N) <= BusB(7); + if (BusA and BusB) = "00000000" then + P_Out(Flag_Z) <= '1'; + else + P_Out(Flag_Z) <= '0'; + end if; + when ALU_OP_ANC=> + P_Out(Flag_N) <= Q_t(7); + P_Out(Flag_C) <= Q_t(7); + if Q_t = "00000000" then + P_Out(Flag_Z) <= '1'; + else + P_Out(Flag_Z) <= '0'; + end if; + when others => + P_Out(Flag_N) <= Q_t(7); + if Q_t = "00000000" then + P_Out(Flag_Z) <= '1'; + else + P_Out(Flag_Z) <= '0'; + end if; + end case; + + if Op=ALU_OP_ARR then + -- handled above in ARR code + Q <= Q2_t; + else + Q <= Q_t; + end if; + end process; + +end; diff --git a/cores/bbc/rtl/T65/T65_MCode.vhd b/cores/bbc/rtl/T65/T65_MCode.vhd new file mode 100755 index 0000000..867e0b8 --- /dev/null +++ b/cores/bbc/rtl/T65/T65_MCode.vhd @@ -0,0 +1,1239 @@ +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- See list of changes in T65 top file (T65.vhd)... +-- +-- **** +-- 65xx compatible microprocessor core +-- +-- FPGAARCADE SVN: $Id: T65_MCode.vhd 1234 2015-02-28 20:14:50Z wolfgang.scherr $ +-- +-- Copyright (c) 2002...2015 +-- Daniel Wallner (jesus opencores org) +-- Mike Johnson (mikej fpgaarcade com) +-- Wolfgang Scherr (WoS pin4 at> +-- Morten Leikvoll () +-- +-- 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(s), 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. +-- +-- Limitations : +-- See in T65 top file (T65.vhd)... + +library IEEE; +use IEEE.std_logic_1164.all; +use IEEE.numeric_std.all; +use ieee.std_logic_unsigned.all; +use work.T65_Pack.all; + +entity T65_MCode is + port( + Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65816 + IR : in std_logic_vector(7 downto 0); + MCycle : in T_Lcycle; + P : in std_logic_vector(7 downto 0); + LCycle : out T_Lcycle; + ALU_Op : out T_ALU_Op; + Set_BusA_To : out T_Set_BusA_To; -- DI,A,X,Y,S,P,DA,DAO,DAX,AAX + Set_Addr_To : out T_Set_Addr_To; -- PC Adder,S,AD,BA + Write_Data : out T_Write_Data; -- DL,A,X,Y,S,P,PCL,PCH,AX,AXB,XB,YB + Jump : out std_logic_vector(1 downto 0); -- PC,++,DIDL,Rel + BAAdd : out std_logic_vector(1 downto 0); -- None,DB Inc,BA Add,BA Adj + BreakAtNA : out std_logic; + ADAdd : out std_logic; + AddY : out std_logic; + PCAdd : out std_logic; + Inc_S : out std_logic; + Dec_S : out std_logic; + LDA : out std_logic; + LDP : out std_logic; + LDX : out std_logic; + LDY : out std_logic; + LDS : out std_logic; + LDDI : out std_logic; + LDALU : out std_logic; + LDAD : out std_logic; + LDBAL : out std_logic; + LDBAH : out std_logic; + SaveP : out std_logic; + Write : out std_logic + ); +end T65_MCode; + +architecture rtl of T65_MCode is + + signal Branch : std_logic; + signal ALUmore:std_logic; + +begin + + with IR(7 downto 5) select + Branch <= not P(Flag_N) when "000", + P(Flag_N) when "001", + not P(Flag_V) when "010", + P(Flag_V) when "011", + not P(Flag_C) when "100", + P(Flag_C) when "101", + not P(Flag_Z) when "110", + P(Flag_Z) when others; + + process (IR, MCycle, P, Branch, Mode) + begin + lCycle <= Cycle_1; + Set_BusA_To <= Set_BusA_To_ABC; + Set_Addr_To <= Set_Addr_To_PBR; + Write_Data <= Write_Data_DL; + Jump <= (others => '0'); + BAAdd <= "00"; + BreakAtNA <= '0'; + ADAdd <= '0'; + PCAdd <= '0'; + Inc_S <= '0'; + Dec_S <= '0'; + LDA <= '0'; + LDP <= '0'; + LDX <= '0'; + LDY <= '0'; + LDS <= '0'; + LDDI <= '0'; + LDALU <= '0'; + LDAD <= '0'; + LDBAL <= '0'; + LDBAH <= '0'; + SaveP <= '0'; + Write <= '0'; + AddY <= '0'; + ALUmore <= '0'; + + case IR(7 downto 5) is + when "100" => -- covers $8x,$9x + case IR(1 downto 0) is + when "00" => -- IR: $80,$84,$88,$8C,$90,$94,$98,$9C + Set_BusA_To <= Set_BusA_To_Y; + if IR(4 downto 2)="111" then -- SYA ($9C) + Write_Data <= Write_Data_YB; + else + Write_Data <= Write_Data_Y; + end if; + when "10" => -- IR: $82,$86,$8A,$8E,$92,$96,$9A,$9E + Set_BusA_To <= Set_BusA_To_X; + if IR(4 downto 2)="111" then -- SXA ($9E) + Write_Data <= Write_Data_XB; + else + Write_Data <= Write_Data_X; + end if; + when "11" => -- IR: $83,$87,$8B,$8F,$93,$97,$9B,$9F + if IR(4 downto 2)="110" then -- SHS ($9B) + Set_BusA_To <= Set_BusA_To_AAX; + LDS <= '1'; + else + Set_BusA_To <= Set_BusA_To_ABC; + end if; + if IR(4 downto 2)="111" or IR(4 downto 2)="110" or IR(4 downto 2)="100" then -- SHA ($9F, $93), SHS ($9B) + Write_Data <= Write_Data_AXB; + else + Write_Data <= Write_Data_AX; + end if; + when others => -- IR: $81,$85,$89,$8D,$91,$95,$99,$9D + Write_Data <= Write_Data_ABC; + end case; + when "101" => -- covers $Ax,$Bx + Set_BusA_To <= Set_BusA_To_DI; + case IR(1 downto 0) is + when "00" => -- IR: $A0,$A4,$A8,$AC,$B0,$B4,$B8,$BC + if IR(4) /= '1' or IR(2) /= '0' then--only for $A0,$A4,$A8,$AC or $B4,$BC + LDY <= '1'; + end if; + when "01" => -- IR: $A1,$A5,$A9,$AD,$B1,$B5,$B9,$BD + LDA <= '1'; + when "10" => -- IR: $A2,$A6,$AA,$AE,$B2,$B6,$BA,$BE + LDX <= '1'; + when others => -- IR: $A3,$A7,$AB,$AF,$B3,$B7,$BB,$BF (undoc) + LDX <= '1'; + LDA <= '1'; + if IR(4 downto 2)="110" then -- LAS (BB) + Set_BusA_To <= Set_BusA_To_S; + LDS <= '1'; + end if; + end case; + when "110" => -- covers $Cx,$Dx + case IR(1 downto 0) is + when "00" => -- IR: $C0,$C4,$C8,$CC,$D0,$D4,$D8,$DC + if IR(4) = '0' then--only for $Cx + LDY <= '1'; + end if; + Set_BusA_To <= Set_BusA_To_Y; + when others => -- IR: $C1,$C5,$C9,$CD,$D1,$D5,$D9,$DD, $C2,$C6,$CA,$CE,$D2,$D6,$DA,$DE, $C3,$C7,$CB,$CF,$D3,$D7,$DB,$DF + Set_BusA_To <= Set_BusA_To_ABC; + end case; + when "111" => -- covers $Ex,$Fx + case IR(1 downto 0) is + when "00" => -- IR: $E0,$E4,$E8,$EC,$F0,$F4,$F8,$FC + if IR(4) = '0' then -- only $Ex + LDX <= '1'; + end if; + Set_BusA_To <= Set_BusA_To_X; + when others => -- IR: $E1,$E5,$E9,$ED,$F1,$F5,$F9,$FD, $E2,$E6,$EA,$EE,$F2,$F6,$FA,$FE, $E3,$E7,$EB,$EF,$F3,$F7,$FB,$FF + Set_BusA_To <= Set_BusA_To_ABC; + end case; + when others => + end case; + + if IR(7 downto 6) /= "10" and IR(1) = '1' and (mode="00" or IR(0)='0') then--covers $0x-$7x, $Cx-$Fx x=2,3,6,7,A,B,E,F, for 6502 undocs + if IR=x"eb" then + Set_BusA_To <= Set_BusA_To_ABC; -- alternate SBC ($EB) + else + Set_BusA_To <= Set_BusA_To_DI; + end if; + end if; + + case IR(4 downto 0) is + -- IR: $00,$20,$40,$60,$80,$A0,$C0,$E0 + -- $08,$28,$48,$68,$88,$A8,$C8,$E8 + -- $0A,$2A,$4A,$6A,$8A,$AA,$CA,$EA + -- $18,$38,$58,$78,$98,$B8,$D8,$F8 + -- $1A,$3A,$5A,$7A,$9A,$BA,$DA,$FA + when "00000" | "01000" | "01010" | "11000" | "11010" => + -- Implied + case IR is + when x"00" => + -- BRK ($00) + lCycle <= Cycle_6; + case MCycle is + when Cycle_1 => + Set_Addr_To <= Set_Addr_To_SP; + Write_Data <= Write_Data_PCH; + Write <= '1'; + when Cycle_2 => + Dec_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + Write_Data <= Write_Data_PCL; + Write <= '1'; + when Cycle_3 => + Dec_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + Write_Data <= Write_Data_P; + Write <= '1'; + when Cycle_4 => + Dec_S <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_5 => + LDDI <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_6 => + Jump <= "10"; + when others => + end case; + when x"20" => -- JSR ($20) + lCycle <= Cycle_5; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDDI <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_2 => + Set_Addr_To <= Set_Addr_To_SP; + Write_Data <= Write_Data_PCH; + Write <= '1'; + when Cycle_3 => + Dec_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + Write_Data <= Write_Data_PCL; + Write <= '1'; + when Cycle_4 => + Dec_S <= '1'; + when Cycle_5 => + Jump <= "10"; + when others => + end case; + when x"40" => -- RTI ($40) + lCycle <= Cycle_5; + case MCycle is + when Cycle_1 => + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_2 => + Inc_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_3 => + Inc_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + Set_BusA_To <= Set_BusA_To_DI; + when Cycle_4 => + LDP <= '1'; + Inc_S <= '1'; + LDDI <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_5 => + Jump <= "10"; + when others => + end case; + when x"60" => -- RTS ($60) + lCycle <= Cycle_5; + case MCycle is + when Cycle_1 => + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_2 => + Inc_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_3 => + Inc_S <= '1'; + LDDI <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + when Cycle_4 => + Jump <= "10"; + when Cycle_5 => + Jump <= "01"; + when others => + end case; + when x"08" | x"48" | x"5a" | x"da" => -- PHP, PHA, PHY*, PHX* ($08,$48,$5A,$DA) + lCycle <= Cycle_2; + if Mode = "00" and IR(1) = '1' then--2 cycle nop + lCycle <= Cycle_1; + end if; + case MCycle is + when Cycle_1 => + if mode/="00" or IR(1)='0' then --wrong on 6502 + Write <= '1'; + case IR(7 downto 4) is + when "0000" => + Write_Data <= Write_Data_P; + when "0100" => + Write_Data <= Write_Data_ABC; + when "0101" => + if Mode /= "00" then + Write_Data <= Write_Data_Y; + else + Write <= '0'; + end if; + when "1101" => + if Mode /= "00" then + Write_Data <= Write_Data_X; + else + Write <= '0'; + end if; + when others => + end case; + Set_Addr_To <= Set_Addr_To_SP; + end if; + when Cycle_2 => + Dec_S <= '1'; + when others => + end case; + when x"28" | x"68" | x"7a" | x"fa" => -- PLP, PLA, PLY*, PLX* ($28,$68,$7A,$FA) + lCycle <= Cycle_3; + if Mode = "00" and IR(1) = '1' then--2 cycle nop + lCycle <= Cycle_1; + end if; + case IR(7 downto 4) is + when "0010" =>--plp + LDP <= '1'; + when "0110" =>--pla + LDA <= '1'; + when "0111" =>--ply not for 6502 + if Mode /= "00" then + LDY <= '1'; + end if; + when "1111" =>--plx not for 6502 + if Mode /= "00" then + LDX <= '1'; + end if; + when others => + end case; + case MCycle is + when Cycle_sync => + if Mode /= "00" or IR(1) = '0' then--wrong on 6502 + SaveP <= '1'; + end if; + when Cycle_1 => + if Mode /= "00" or IR(1) = '0' then--wrong on 6502 + Set_Addr_To <= Set_Addr_To_SP; + LDP <= '0'; + end if; + when Cycle_2 => + Inc_S <= '1'; + Set_Addr_To <= Set_Addr_To_SP; + LDP <= '0'; + when Cycle_3 => + Set_BusA_To <= Set_BusA_To_DI; + when others => + end case; + when x"a0" | x"c0" | x"e0" => -- LDY, CPY, CPX ($A0,$C0,$E0) + -- Immediate + case MCycle is + when Cycle_sync => + when Cycle_1 => + Jump <= "01"; + when others => + end case; + when x"88" => -- DEY ($88) + LDY <= '1'; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Set_BusA_To <= Set_BusA_To_Y; + when others => + end case; + when x"ca" => -- DEX ($CA) + LDX <= '1'; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Set_BusA_To <= Set_BusA_To_X; + when others => + end case; + when x"1a" | x"3a" => -- INC*, DEC* ($1A,$3A) + if Mode /= "00" then + LDA <= '1'; -- A + else + lCycle <= Cycle_1;--undoc 2 cycle nop + end if; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Set_BusA_To <= Set_BusA_To_S; + when others => + end case; + when x"0a" | x"2a" | x"4a" | x"6a" => -- ASL, ROL, LSR, ROR ($0A,$2A,$4A,$6A) + LDA <= '1'; -- A + Set_BusA_To <= Set_BusA_To_ABC; + case MCycle is + when Cycle_sync => + when Cycle_1 => + when others => + end case; + when x"8a" | x"98" => -- TYA, TXA ($8A,$98) + LDA <= '1'; + case MCycle is + when Cycle_sync => + when Cycle_1 => + when others => + end case; + when x"aa" | x"a8" => -- TAX, TAY ($AA,$A8) + case MCycle is + when Cycle_sync => + when Cycle_1 => + Set_BusA_To <= Set_BusA_To_ABC; + when others => + end case; + when x"9a" => -- TXS ($9A) + LDS <= '1'; -- will be set only in Cycle_sync + when x"ba" => -- TSX ($BA) + LDX <= '1'; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Set_BusA_To <= Set_BusA_To_S; + when others => + end case; + when x"80" => -- undoc: NOP imm2 ($80) + case MCycle is + when Cycle_sync => + when Cycle_1 => + Jump <= "01"; + when others => + end case; + when others => -- others ($0A,$EA, $18,$38,$58,$78,$B8,$C8,$D8,$E8,$F8) + case MCycle is + when Cycle_sync => + when others => + end case; + end case; + + -- IR: $01,$21,$41,$61,$81,$A1,$C1,$E1 + -- $03,$23,$43,$63,$83,$A3,$C3,$E3 + when "00001" | "00011" => + -- Zero Page Indexed Indirect (d,x) + lCycle <= Cycle_5; + if IR(7 downto 6) /= "10" then -- ($01,$21,$41,$61,$C1,$E1,$03,$23,$43,$63,$C3,$E3) + LDA <= '1'; + if Mode="00" and IR(1)='1' then + lCycle <= Cycle_7; + end if; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + ADAdd <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_3 => + BAAdd <= "01"; + LDBAL <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_4 => + LDBAH <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_5=> + if Mode="00" and IR(1)='1' and IR(7 downto 6)/="10" then + Set_Addr_To <= Set_Addr_To_BA; + Write <= '1'; + LDDI<='1'; + end if; + when Cycle_6=> + Write <= '1'; + LDALU<='1'; + SaveP<='1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_7 => + ALUmore <= '1'; + Set_BusA_To <= Set_BusA_To_ABC; + when others => + end case; + + -- IR: $09,$29,$49,$69,$89,$A9,$C9,$E9 + when "01001" => + -- Immediate + if IR(7 downto 5)/="100" then -- all except undoc. NOP imm2 (not $89) + LDA <= '1'; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + when others => + end case; + + -- IR: $0B,$2B,$4B,$6B,$8B,$AB,$CB,$EB + when "01011" => + if Mode="00" then + -- Immediate undoc for 6500 + case IR(7 downto 5) is + when "010"|"011"|"000"|"001" =>--ALR,ARR + Set_BusA_To<=Set_BusA_To_DA; + LDA <= '1'; + when "100" =>--XAA + Set_BusA_To<=Set_BusA_To_DAX; + LDA <= '1'; + when "110" =>--SAX (SBX) + Set_BusA_To<=Set_BusA_To_AAX; + LDX <= '1'; + when "101" =>--OAL + Set_BusA_To<=Set_BusA_To_DAO; + LDA <= '1'; + when others=> + LDA <= '1'; + end case; + case MCycle is + when Cycle_1 => + Jump <= "01"; + when others => + end case; + end if; + + -- IR: $02,$22,$42,$62,$82,$A2,$C2,$E2 + -- $12,$32,$52,$72,$92,$B2,$D2,$F2 + when "00010" | "10010" => + -- Immediate, SKB, KIL + case MCycle is + when Cycle_sync => + when Cycle_1 => + if IR = "10100010" then + -- LDX ($A2) + Jump <= "01"; + LDX <= '1'; -- Moved, Lorenz test showed X changing on SKB (NOPx) + elsif IR(7 downto 4)="1000" or IR(7 downto 4)="1100" or IR(7 downto 4)="1110" then + -- undoc: NOP imm2 + Jump <= "01"; + else + -- KIL !!! + end if; + when others => + end case; + + -- IR: $04,$24,$44,$64,$84,$A4,$C4,$E4 + when "00100" => + -- Zero Page + lCycle <= Cycle_2; + case MCycle is + when Cycle_sync => + if IR(7 downto 5) = "001" then--24=BIT zpg + SaveP <= '1'; + end if; + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + if IR(7 downto 5) = "100" then--84=sty zpg (the only write in this group) + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + when others => + end case; + + -- IR: $05,$25,$45,$65,$85,$A5,$C5,$E5 + -- $06,$26,$46,$66,$86,$A6,$C6,$E6 + -- $07,$27,$47,$67,$87,$A7,$C7,$E7 + when "00101" | "00110" | "00111" => + -- Zero Page + if IR(7 downto 6) /= "10" and IR(1) = '1' and (mode="00" or IR(0)='0') then--covers 0x-7x,cx-fx x=2,3,6,7,a,b,e,f, for 6502 undocs + -- Read-Modify-Write + lCycle <= Cycle_4; + if Mode="00" and IR(0)='1' then + LDA<='1'; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + LDDI <= '1'; + if Mode="00" then--The old 6500 writes back what is just read, before changing. The 65c does another read + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_3 => + LDALU <= '1'; + SaveP <= '1'; + Write <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_4 => + if Mode="00" and IR(0)='1' then + Set_BusA_To<=Set_BusA_To_ABC; + ALUmore <= '1'; -- For undoc DCP/DCM support + LDDI <= '1'; -- requires DIN to reflect DOUT! + end if; + when others => + end case; + else + lCycle <= Cycle_2; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + end if; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + if IR(7 downto 5) = "100" then + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + when others => + end case; + end if; + + -- IR: $0C,$2C,$4C,$6C,$8C,$AC,$CC,$EC + when "01100" => + -- Absolute + if IR(7 downto 6) = "01" and IR(4 downto 0) = "01100" then -- JMP ($4C,$6C) + if IR(5) = '0' then + lCycle <= Cycle_2; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDDI <= '1'; + when Cycle_2 => + Jump <= "10"; + when others => + end case; + else + lCycle <= Cycle_4; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDDI <= '1'; + LDBAL <= '1'; + when Cycle_2 => + LDBAH <= '1'; + if Mode /= "00" then + Jump <= "10"; + end if; + if Mode = "00" then + Set_Addr_To <= Set_Addr_To_BA; + end if; + when Cycle_3 => + LDDI <= '1'; + if Mode = "00" then + Set_Addr_To <= Set_Addr_To_BA; + BAAdd <= "01"; -- DB Inc + else + Jump <= "01"; + end if; + when Cycle_4 => + Jump <= "10"; + when others => + end case; + end if; + else + lCycle <= Cycle_3; + case MCycle is + when Cycle_sync => + if IR(7 downto 5) = "001" then--2c-BIT + SaveP <= '1'; + end if; + when Cycle_1 => + Jump <= "01"; + LDBAL <= '1'; + when Cycle_2 => + Jump <= "01"; + LDBAH <= '1'; + if IR(7 downto 5) = "100" then--80, sty, the only write in this group + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_3 => + when others => + end case; + end if; + + -- IR: $0D,$2D,$4D,$6D,$8D,$AD,$CD,$ED + -- $0E,$2E,$4E,$6E,$8E,$AE,$CE,$EE + -- $0F,$2F,$4F,$6F,$8F,$AF,$CF,$EF + when "01101" | "01110" | "01111" => + -- Absolute + if IR(7 downto 6) /= "10" and IR(1) = '1' and (mode="00" or IR(0)='0') then -- ($0E,$2E,$4E,$6E,$CE,$EE, $0F,$2F,$4F,$6F,$CF,$EF) + -- Read-Modify-Write + lCycle <= Cycle_5; + if Mode="00" and IR(0) = '1' then + LDA <= '1'; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDBAL <= '1'; + when Cycle_2 => + Jump <= "01"; + LDBAH <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_3 => + LDDI <= '1'; + if Mode="00" then--The old 6500 writes back what is just read, before changing. The 65c does another read + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_4 => + Write <= '1'; + LDALU <= '1'; + SaveP <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_5 => + if Mode="00" and IR(0)='1' then + ALUmore <= '1'; -- For undoc DCP/DCM support + Set_BusA_To<=Set_BusA_To_ABC; + end if; + when others => + end case; + else + lCycle <= Cycle_3; + if IR(7 downto 6) /= "10" then -- all but $8D, $8E, $8F, $AD, $AE, $AF ($AD does set LDA in an earlier case statement) + LDA <= '1'; + end if; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Jump <= "01"; + LDBAL <= '1'; + when Cycle_2 => + Jump <= "01"; + LDBAH <= '1'; + if IR(7 downto 5) = "100" then--8d + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_3 => + when others => + end case; + end if; + + -- IR: $10,$30,$50,$70,$90,$B0,$D0,$F0 + when "10000" => + -- Relative + -- This circuit dictates when the last + -- microcycle occurs for the branch depending on + -- whether or not the branch is taken and if a page + -- is crossed... + if (Branch = '1') then + lCycle <= Cycle_3; -- We're done @ T3 if branching...upper + -- level logic will stop at T2 if no page cross + -- (See the Break signal) + else + lCycle <= Cycle_1; + end if; + -- This decodes the current microcycle and takes the + -- proper course of action... + case MCycle is + -- On the T1 microcycle, increment the program counter + -- and instruct the upper level logic to fetch the offset + -- from the Din bus and store it in the data latches. This + -- will be the last microcycle if the branch isn't taken. + when Cycle_1 => + Jump <= "01"; -- Increments the PC by one (PC will now be PC+2) + -- from microcycle T0. + LDDI <= '1'; -- Tells logic in top level (T65.vhd) to route + -- the Din bus to the memory data latch (DL) + -- so that the branch offset is fetched. + -- In microcycle T2, tell the logic in the top level to + -- add the offset. If the most significant byte of the + -- program counter (i.e. the current "page") does not need + -- updating, we are done here...the Break signal at the + -- T65.vhd level takes care of that... + when Cycle_2 => + Jump <= "11"; -- Tell the PC Jump logic to use relative mode. + PCAdd <= '1'; -- This tells the PC adder to update itself with + -- the current offset recently fetched from + -- memory. + -- The following is microcycle T3 : + -- The program counter should be completely updated + -- on this cycle after the page cross is detected. + -- We don't need to do anything here... + when Cycle_3 => + when others => null; -- Do nothing. + end case; + + -- IR: $11,$31,$51,$71,$91,$B1,$D1,$F1 + -- $13,$33,$53,$73,$93,$B3,$D3,$F3 + when "10001" | "10011" => + lCycle <= Cycle_5; + if IR(7 downto 6) /= "10" then -- ($11,$31,$51,$71,$D1,$F1,$13,$33,$53,$73,$D3,$F3) + LDA <= '1'; + if Mode="00" and IR(1)='1' then + lCycle <= Cycle_7; + end if; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + LDBAL <= '1'; + BAAdd <= "01"; -- DB Inc + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_3 => + Set_BusA_To <= Set_BusA_To_Y; + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_4 => + BAAdd <= "11"; -- BA Adj + if IR(7 downto 5) = "100" then + Write <= '1'; + elsif IR(1)='0' or IR=x"B3" then -- Dont do this on $x3, except undoc LAXiy $B3 (says real CPU and Lorenz tests) + BreakAtNA <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_5 => + if Mode="00" and IR(1)='1' and IR(7 downto 6)/="10" then + Set_Addr_To <= Set_Addr_To_BA; + LDDI<='1'; + Write <= '1'; + end if; + when Cycle_6 => + LDALU<='1'; + SaveP<='1'; + Write <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_7 => + ALUmore <= '1'; + Set_BusA_To<=Set_BusA_To_ABC; + when others => + end case; + + -- IR: $14,$34,$54,$74,$94,$B4,$D4,$F4 + -- $15,$35,$55,$75,$95,$B5,$D5,$F5 + -- $16,$36,$56,$76,$96,$B6,$D6,$F6 + -- $17,$37,$57,$77,$97,$B7,$D7,$F7 + when "10100" | "10101" | "10110" | "10111" => + -- Zero Page, X + if IR(7 downto 6) /= "10" and IR(1) = '1' and (Mode="00" or IR(0)='0') then -- ($16,$36,$56,$76,$D6,$F6, $17,$37,$57,$77,$D7,$F7) + -- Read-Modify-Write + if Mode="00" and IR(0)='1' then + LDA<='1'; + end if; + lCycle <= Cycle_5; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + ADAdd <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_3 => + LDDI <= '1'; + if Mode="00" then -- The old 6500 writes back what is just read, before changing. The 65c does another read + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_4 => + LDALU <= '1'; + SaveP <= '1'; + Write <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + if Mode="00" and IR(0)='1' then + LDDI<='1'; + end if; + when Cycle_5 => + if Mode="00" and IR(0)='1' then + ALUmore <= '1'; -- For undoc DCP/DCM support + Set_BusA_To<=Set_BusA_To_ABC; + end if; + when others => + end case; + else + lCycle <= Cycle_3; + if IR(7 downto 6) /= "10" and IR(0)='1' then -- dont LDA on undoc skip + LDA <= '1'; + end if; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Jump <= "01"; + LDAD <= '1'; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_2 => + ADAdd <= '1'; + -- Added this check for Y reg. use, added undocs + if (IR(3 downto 1) = "011") then -- ($16,$36,$56,$76,$96,$B6,$D6,$F6,$17,$37,$57,$77,$97,$B7,$D7,$F7) + AddY <= '1'; + end if; + if IR(7 downto 5) = "100" then -- ($14,$34,$15,$35,$16,$36,$17,$37) the only write instruction + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_ZPG; + when Cycle_3 => null; + when others => + end case; + end if; + + -- IR: $19,$39,$59,$79,$99,$B9,$D9,$F9 + -- $1B,$3B,$5B,$7B,$9B,$BB,$DB,$FB + when "11001" | "11011" => + -- Absolute Y + lCycle <= Cycle_4; + if IR(7 downto 6) /= "10" then + LDA <= '1'; + if Mode="00" and IR(1)='1' then + lCycle <= Cycle_6; + end if; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDBAL <= '1'; + when Cycle_2 => + Jump <= "01"; + Set_BusA_To <= Set_BusA_To_Y; + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_3 => + BAAdd <= "11"; -- BA adj + if IR(7 downto 5) = "100" then--99/9b + Write <= '1'; + elsif IR(1)='0' or IR=x"BB" then -- Dont do this on $xB, except undoc $BB (says real CPU and Lorenz tests) + BreakAtNA <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_4 => -- just for undoc + if Mode="00" and IR(1)='1' and IR(7 downto 6)/="10" then + Set_Addr_To <= Set_Addr_To_BA; + LDDI<='1'; + Write <= '1'; + end if; + when Cycle_5 => + Write <= '1'; + LDALU<='1'; + Set_Addr_To <= Set_Addr_To_BA; + SaveP<='1'; + when Cycle_6 => + ALUmore <= '1'; + Set_BusA_To <= Set_BusA_To_ABC; + when others => + end case; + + -- IR: $1C,$3C,$5C,$7C,$9C,$BC,$DC,$FC + -- $1D,$3D,$5D,$7D,$9D,$BD,$DD,$FD + -- $1E,$3E,$5E,$7E,$9E,$BE,$DE,$FE + -- $1F,$3F,$5F,$7F,$9F,$BF,$DF,$FF + when "11100" | "11101" | "11110" | "11111" => + -- Absolute X + if IR(7 downto 6) /= "10" and IR(1) = '1' and (Mode="00" or IR(0)='0') then -- ($1E,$3E,$5E,$7E,$DE,$FE, $1F,$3F,$5F,$7F,$DF,$FF) + -- Read-Modify-Write + lCycle <= Cycle_6; + if Mode="00" and IR(0)='1' then + LDA <= '1'; + end if; + case MCycle is + when Cycle_1 => + Jump <= "01"; + LDBAL <= '1'; + when Cycle_2 => + Jump <= "01"; + Set_BusA_To <= Set_BusA_To_X; + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_3 => + BAAdd <= "11"; -- BA adj + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_4 => + LDDI <= '1'; + if Mode="00" then--The old 6500 writes back what is just read, before changing. The 65c does another read + Write <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_5 => + LDALU <= '1'; + SaveP <= '1'; + Write <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_6 => + if Mode="00" and IR(0)='1' then + ALUmore <= '1'; + Set_BusA_To <= Set_BusA_To_ABC; + end if; + when others => + end case; + else -- ($1C,$3C,$5C,$7C,$9C,$BC,$DC,$FC, $1D,$3D,$5D,$7D,$9D,$BD,$DD,$FD, $9E,$BE,$9F,$BF) + lCycle <= Cycle_4;--Or 3 if not page crossing + if IR(7 downto 6) /= "10" then + if Mode/="00" or IR(4)='0' or IR(1 downto 0)/="00" then + LDA <= '1'; + end if; + end if; + case MCycle is + when Cycle_sync => + when Cycle_1 => + Jump <= "01"; + LDBAL <= '1'; + when Cycle_2 => + Jump <= "01"; + -- special case $BE which uses Y reg as index!! + if(IR(7 downto 6)="10" and IR(4 downto 1)="1111") then + Set_BusA_To <= Set_BusA_To_Y; + else + Set_BusA_To <= Set_BusA_To_X; + end if; + BAAdd <= "10"; -- BA Add + LDBAH <= '1'; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_3 => + BAAdd <= "11"; -- BA adj + if IR(7 downto 5) = "100" then -- ($9E,$9F) + Write <= '1'; + else + BreakAtNA <= '1'; + end if; + Set_Addr_To <= Set_Addr_To_BA; + when Cycle_4 => + when others => + end case; + end if; + when others => + end case; + end process; + + process (IR, MCycle, Mode,ALUmore) + begin + -- ORA, AND, EOR, ADC, NOP, LD, CMP, SBC + -- ASL, ROL, LSR, ROR, BIT, LD, DEC, INC + case IR(1 downto 0) is + when "00" => + case IR(4 downto 2) is + -- IR: $00,$20,$40,$60,$80,$A0,$C0,$E0 + -- $04,$24,$44,$64,$84,$A4,$C4,$E4 + -- $0C,$2C,$4C,$6C,$8C,$AC,$CC,$EC + when "000" | "001" | "011" => + case IR(7 downto 5) is + when "110" | "111" => -- CP ($C0,$C4,$CC,$E0,$E4,$EC) + ALU_Op <= ALU_OP_CMP; + when "101" => -- LD ($A0,$A4,$AC) + ALU_Op <= ALU_OP_EQ2; + when "001" => -- BIT ($20,$24,$2C - $20 is ignored, as its a jmp) + ALU_Op <= ALU_OP_BIT; + when others => -- other, NOP/ST ($x0,$x4,$xC) + ALU_Op <= ALU_OP_EQ1; + end case; + + -- IR: $08,$28,$48,$68,$88,$A8,$C8,$E8 + when "010" => + case IR(7 downto 5) is + when "111" | "110" => -- IN ($C8,$E8) + ALU_Op <= ALU_OP_INC; + when "100" => -- DEY ($88) + ALU_Op <= ALU_OP_DEC; + when others => -- LD + ALU_Op <= ALU_OP_EQ2; + end case; + + -- IR: $18,$38,$58,$78,$98,$B8,$D8,$F8 + when "110" => + case IR(7 downto 5) is + when "100" => -- TYA ($98) + ALU_Op <= ALU_OP_EQ2; + when others => + ALU_Op <= ALU_OP_EQ1; + end case; + + -- IR: $10,$30,$50,$70,$90,$B0,$D0,$F0 + -- $14,$34,$54,$74,$94,$B4,$D4,$F4 + -- $1C,$3C,$5C,$7C,$9C,$BC,$DC,$FC + when others => + case IR(7 downto 5) is + when "101" => -- LD ($B0,$B4,$BC) + ALU_Op <= ALU_OP_EQ2; + when others => + ALU_Op <= ALU_OP_EQ1; + end case; + end case; + + when "01" => -- OR + case(to_integer(unsigned(IR(7 downto 5)))) is + when 0=> -- IR: $01,$05,$09,$0D,$11,$15,$19,$1D + ALU_Op<=ALU_OP_OR; + when 1=> -- IR: $21,$25,$29,$2D,$31,$35,$39,$3D + ALU_Op<=ALU_OP_AND; + when 2=> -- IR: $41,$45,$49,$4D,$51,$55,$59,$5D + ALU_Op<=ALU_OP_EOR; + when 3=> -- IR: $61,$65,$69,$6D,$71,$75,$79,$7D + ALU_Op<=ALU_OP_ADC; + when 4=>-- IR: $81,$85,$89,$8D,$91,$95,$99,$9D + ALU_Op<=ALU_OP_EQ1; -- STA + when 5=> -- IR: $A1,$A5,$A9,$AD,$B1,$B5,$B9,$BD + ALU_Op<=ALU_OP_EQ2; -- LDA + when 6=> -- IR: $C1,$C5,$C9,$CD,$D1,$D5,$D9,$DD + ALU_Op<=ALU_OP_CMP; + when others=> -- IR: $E1,$E5,$E9,$ED,$F1,$F5,$F9,$FD + ALU_Op<=ALU_OP_SBC; + end case; + + when "10" => + case(to_integer(unsigned(IR(7 downto 5)))) is + when 0=> -- IR: $02,$06,$0A,$0E,$12,$16,$1A,$1E + ALU_Op<=ALU_OP_ASL; + if IR(4 downto 2) = "110" and Mode/="00" then -- 00011010,$1A -> INC acc, not on 6502 + ALU_Op <= ALU_OP_INC; + end if; + when 1=> -- IR: $22,$26,$2A,$2E,$32,$36,$3A,$3E + ALU_Op<=ALU_OP_ROL; + if IR(4 downto 2) = "110" and Mode/="00" then -- 00111010,$3A -> DEC acc, not on 6502 + ALU_Op <= ALU_OP_DEC; + end if; + when 2=> -- IR: $42,$46,$4A,$4E,$52,$56,$5A,$5E + ALU_Op<=ALU_OP_LSR; + when 3=> -- IR: $62,$66,$6A,$6E,$72,$76,$7A,$7E + ALU_Op<=ALU_OP_ROR; + when 4=> -- IR: $82,$86,$8A,$8E,$92,$96,$9A,$9E + ALU_Op<=ALU_OP_BIT; + if IR(4 downto 2) = "010" then -- 10001010, $8A -> TXA + ALU_Op <= ALU_OP_EQ2; + else -- 100xxx10, $82,$86,$8E,$92,$96,$9A,$9E + ALU_Op <= ALU_OP_EQ1; + end if; + when 5=> -- IR: $A2,$A6,$AA,$AE,$B2,$B6,$BA,$BE + ALU_Op<=ALU_OP_EQ2; -- LDX + when 6=> -- IR: $C2,$C6,$CA,$CE,$D2,$D6,$DA,$DE + ALU_Op<=ALU_OP_DEC; + when others=> -- IR: $E2,$E6,$EA,$EE,$F2,$F6,$FA,$FE + ALU_Op<=ALU_OP_INC; + end case; + + when others => -- "11" undoc double alu ops + case(to_integer(unsigned(IR(7 downto 5)))) is + -- IR: $A3,$A7,$AB,$AF,$B3,$B7,$BB,$BF + when 5 => + if IR=x"bb" then--LAS + ALU_Op <= ALU_OP_AND; + else + ALU_Op <= ALU_OP_EQ2; + end if; + + -- IR: $03,$07,$0B,$0F,$13,$17,$1B,$1F + -- $23,$27,$2B,$2F,$33,$37,$3B,$3F + -- $43,$47,$4B,$4F,$53,$57,$5B,$5F + -- $63,$67,$6B,$6F,$73,$77,$7B,$7F + -- $83,$87,$8B,$8F,$93,$97,$9B,$9F + -- $C3,$C7,$CB,$CF,$D3,$D7,$DB,$DF + -- $E3,$E7,$EB,$EF,$F3,$F7,$FB,$FF + when others => + if IR=x"6b" then -- ARR + ALU_Op<=ALU_OP_ARR; + elsif IR=x"8b" then -- ARR + ALU_Op<=ALU_OP_XAA; -- we can't use the bit operation as we don't set all flags... + elsif IR=x"0b" or IR=x"2b" then -- ANC + ALU_Op<=ALU_OP_ANC; + elsif IR=x"eb" then -- alternate SBC + ALU_Op<=ALU_OP_SBC; + elsif ALUmore='1' then + case(to_integer(unsigned(IR(7 downto 5)))) is + when 0=> + ALU_Op<=ALU_OP_OR; + when 1=> + ALU_Op<=ALU_OP_AND; + when 2=> + ALU_Op<=ALU_OP_EOR; + when 3=> + ALU_Op<=ALU_OP_ADC; + when 4=> + ALU_Op<=ALU_OP_EQ1; -- STA + when 5=> + ALU_Op<=ALU_OP_EQ2; -- LDA + when 6=> + ALU_Op<=ALU_OP_CMP; + when others=> + ALU_Op<=ALU_OP_SBC; + end case; + else + case(to_integer(unsigned(IR(7 downto 5)))) is + when 0=> + ALU_Op<=ALU_OP_ASL; + when 1=> + ALU_Op<=ALU_OP_ROL; + when 2=> + ALU_Op<=ALU_OP_LSR; + when 3=> + ALU_Op<=ALU_OP_ROR; + when 4=> + ALU_Op<=ALU_OP_BIT; + when 5=> + ALU_Op<=ALU_OP_EQ2; -- LDX + when 6=> + ALU_Op<=ALU_OP_DEC; + if IR(4 downto 2)="010" then -- $6B + ALU_Op<=ALU_OP_SAX; -- special SAX (SBX) case + end if; + when others=> + ALU_Op<=ALU_OP_INC; + end case; + end if; + end case; + end case; + end process; + +end; diff --git a/cores/bbc/rtl/T65/T65_Pack.vhd b/cores/bbc/rtl/T65/T65_Pack.vhd new file mode 100755 index 0000000..f56c343 --- /dev/null +++ b/cores/bbc/rtl/T65/T65_Pack.vhd @@ -0,0 +1,180 @@ +-- **** +-- T65(b) core. In an effort to merge and maintain bug fixes .... +-- +-- See list of changes in T65 top file (T65.vhd)... +-- +-- **** +-- 65xx compatible microprocessor core +-- +-- FPGAARCADE SVN: $Id: T65_Pack.vhd 1234 2015-02-28 20:14:50Z wolfgang.scherr $ +-- +-- Copyright (c) 2002...2015 +-- Daniel Wallner (jesus opencores org) +-- Mike Johnson (mikej fpgaarcade com) +-- Wolfgang Scherr (WoS pin4 at> +-- Morten Leikvoll () +-- +-- 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(s), 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. +-- +-- Limitations : +-- See in T65 top file (T65.vhd)... + +library IEEE; +use IEEE.std_logic_1164.all; + +package T65_Pack is + + constant Flag_C : integer := 0; + constant Flag_Z : integer := 1; + constant Flag_I : integer := 2; + constant Flag_D : integer := 3; + constant Flag_B : integer := 4; + constant Flag_1 : integer := 5; + constant Flag_V : integer := 6; + constant Flag_N : integer := 7; + + subtype T_Lcycle is std_logic_vector(2 downto 0); + constant Cycle_sync :T_Lcycle:="000"; + constant Cycle_1 :T_Lcycle:="001"; + constant Cycle_2 :T_Lcycle:="010"; + constant Cycle_3 :T_Lcycle:="011"; + constant Cycle_4 :T_Lcycle:="100"; + constant Cycle_5 :T_Lcycle:="101"; + constant Cycle_6 :T_Lcycle:="110"; + constant Cycle_7 :T_Lcycle:="111"; + + function CycleNext(c:T_Lcycle) return T_Lcycle; + + type T_Set_BusA_To is + ( + Set_BusA_To_DI, + Set_BusA_To_ABC, + Set_BusA_To_X, + Set_BusA_To_Y, + Set_BusA_To_S, + Set_BusA_To_P, + Set_BusA_To_DA, + Set_BusA_To_DAO, + Set_BusA_To_DAX, + Set_BusA_To_AAX, + Set_BusA_To_DONTCARE + ); + + type T_Set_Addr_To is + ( + Set_Addr_To_PBR, + Set_Addr_To_SP, + Set_Addr_To_ZPG, + Set_Addr_To_BA + ); + + type T_Write_Data is + ( + Write_Data_DL, + Write_Data_ABC, + Write_Data_X, + Write_Data_Y, + Write_Data_S, + Write_Data_P, + Write_Data_PCL, + Write_Data_PCH, + Write_Data_AX, + Write_Data_AXB, + Write_Data_XB, + Write_Data_YB, + Write_Data_DONTCARE + ); + + type T_ALU_OP is + ( + ALU_OP_OR, --"0000" + ALU_OP_AND, --"0001" + ALU_OP_EOR, --"0010" + ALU_OP_ADC, --"0011" + ALU_OP_EQ1, --"0100" EQ1 does not change N,Z flags, EQ2/3 does. + ALU_OP_EQ2, --"0101" Not sure yet whats the difference between EQ2&3. They seem to do the same ALU op + ALU_OP_CMP, --"0110" + ALU_OP_SBC, --"0111" + ALU_OP_ASL, --"1000" + ALU_OP_ROL, --"1001" + ALU_OP_LSR, --"1010" + ALU_OP_ROR, --"1011" + ALU_OP_BIT, --"1100" +-- ALU_OP_EQ3, --"1101" + ALU_OP_DEC, --"1110" + ALU_OP_INC, --"1111" + ALU_OP_ARR, + ALU_OP_ANC, + ALU_OP_SAX, + ALU_OP_XAA +-- ALU_OP_UNDEF--"----"--may be replaced with any? + ); + + type T_t65_dbg is record + I : std_logic_vector(7 downto 0); -- instruction + A : std_logic_vector(7 downto 0); -- A reg + X : std_logic_vector(7 downto 0); -- X reg + Y : std_logic_vector(7 downto 0); -- Y reg + S : std_logic_vector(7 downto 0); -- stack pointer + P : std_logic_vector(7 downto 0); -- processor flags + end record; + +end; + +package body T65_Pack is + + function CycleNext(c:T_Lcycle) return T_Lcycle is + begin + case(c) is + when Cycle_sync=> + return Cycle_1; + when Cycle_1=> + return Cycle_2; + when Cycle_2=> + return Cycle_3; + when Cycle_3=> + return Cycle_4; + when Cycle_4=> + return Cycle_5; + when Cycle_5=> + return Cycle_6; + when Cycle_6=> + return Cycle_7; + when Cycle_7=> + return Cycle_sync; + when others=> + return Cycle_sync; + end case; + end CycleNext; + +end T65_Pack; diff --git a/cores/bbc/rtl/bbc.v b/cores/bbc/rtl/bbc.v index e5aea27..be67b15 100644 --- a/cores/bbc/rtl/bbc.v +++ b/cores/bbc/rtl/bbc.v @@ -38,11 +38,11 @@ module bbc( // externally pressed "shift" key for autoboot input SHIFT, - - // expose pins required for mmc - output [7:0] user_via_pb_out, - input user_via_cb1_in, - input user_via_cb2_in, + + output SDSS, + output SDCLK, + output SDMOSI, + input SDMISO, // analog joystick input input [1:0] joy_but, @@ -115,7 +115,6 @@ wire cpu_we; wire [23:0] cpu_a; wire [7:0] cpu_di; -reg [7:0] cpu_di_r; wire [7:0] cpu_do; // CRTC signals @@ -176,7 +175,8 @@ wire [7:0] sound_di; wire [7:0] sound_ao; // System VIA signals -wire [7:0] sys_via_do; +wire [7:0] sys_via_do; +reg [7:0] sys_via_do_r; wire sys_via_do_oe_n; wire sys_via_irq_n; wire sys_via_ca1_in; @@ -197,7 +197,8 @@ wire [7:0] sys_via_pb_out; wire [7:0] sys_via_pb_oe_n; // User VIA signals -wire [7:0] user_via_do; +wire [7:0] user_via_do; +reg [7:0] user_via_do_r; wire user_via_do_oe_n; wire user_via_irq_n; reg user_via_ca1_in; @@ -207,16 +208,28 @@ wire user_via_ca2_oe_n; wire [7:0] user_via_pa_in; wire [7:0] user_via_pa_out; wire [7:0] user_via_pa_oe_n; -//TH wire user_via_cb1_in; +wire user_via_cb1_in; wire user_via_cb1_out; wire user_via_cb1_oe_n; -//TH wire user_via_cb2_in; +wire user_via_cb2_in; wire user_via_cb2_out; wire user_via_cb2_oe_n; wire [7:0] user_via_pb_in; -//TH wire [7:0] user_via_pb_out; +wire [7:0] user_via_pb_out; wire [7:0] user_via_pb_oe_n; +// MMC +// SDCLK is driven from either PB1 or CB1 depending on the SR Mode +wire sdclk_int = ~user_via_pb_oe_n[1] ? user_via_pb_out[1] : + (~user_via_cb1_oe_n ? user_via_cb1_out : 1); +assign SDCLK = sdclk_int; +assign user_via_cb1_in = sdclk_int; +// SDMOSI is always driven from PB0 +assign SDMOSI = ~user_via_pb_oe_n[0] ? user_via_pb_out[0] : 1; +// SDMISO is always read from CB2 +assign user_via_cb2_in = SDMISO; +assign SDSS = 0; + // calulation for display address reg [3:0] process_3_aa; @@ -270,65 +283,62 @@ address_decode ADDRDECODE( .mhz1_enable(mhz1_enable) ); -/*input clk; // CPU clock -input reset; // reset signal -output reg [15:0] AB; // address bus -input [7:0] DI; // data in, read bus -output [7:0] DO; // data out, write bus -output WE; // write enable -input IRQ; // interrupt request -input NMI; // non-maskable interrupt request -input RDY; // Ready signal. Pauses CPU when RDY=0 -*/ - -cpu CPU ( - .clk ( CLK32M_I ), - .reset ( ~reset_n ), +T65 CPU ( + .Mode (CPU_MODE), + .Res_n (reset_n), + .Enable (cpu_clken), + .Clk (CLK32M_I), + .Rdy (cpu_clken), + .Abort_n(cpu_abort_n), + .NMI_n (cpu_nmi_n), + .IRQ_n (cpu_irq_n), + .SO_n (cpu_so_n), + .R_W_n (cpu_r_nw), - .IRQ ( ~cpu_irq_n ), - .NMI ( ~cpu_nmi_n ), - - .WE ( cpu_we ), - .AB ( cpu_a[15:0] ), - .DI ( cpu_di_r ), - .DO ( cpu_do ), - .RDY ( cpu_clken ) + .DI (cpu_di), + .DO (cpu_do), + .A (cpu_a) ); -assign cpu_r_nw = ~cpu_we; - m6522 SYS_VIA ( // System VIA is reset by power on reset only - .ENA_4(mhz4_clken), - .CLK(CLK32M_I), + .I_RS(cpu_a[3:0]), .I_DATA(cpu_do), .O_DATA(sys_via_do), .O_DATA_OE_L(sys_via_do_oe_n), + .I_RW_L(cpu_r_nw), .I_CS1(sys_via_enable), .I_CS2_L(1'b 0), // nCS2(1'b 0), .O_IRQ_L(sys_via_irq_n), - .I_P2_H(mhz1_clken), - .RESET_L(reset_n), - + .I_CA1(sys_via_ca1_in), .I_CA2(sys_via_ca2_in), .O_CA2(sys_via_ca2_out), .O_CA2_OE_L(sys_via_ca2_oe_n), + .I_PA(sys_via_pa_in), .O_PA(sys_via_pa_out), .O_PA_OE_L(sys_via_pa_oe_n), + .I_CB1(sys_via_cb1_in), .O_CB1(sys_via_cb1_out), .O_CB1_OE_L(sys_via_cb1_oe_n), + .I_CB2(sys_via_cb2_in), .O_CB2(sys_via_cb2_out), .O_CB2_OE_L(sys_via_cb2_oe_n), + .I_PB(sys_via_pb_in), .O_PB(sys_via_pb_out), - .O_PB_OE_L(sys_via_pb_oe_n) + .O_PB_OE_L(sys_via_pb_oe_n), + + .I_P2_H(mhz1_clken), + .RESET_L(reset_n), + .ENA_4(mhz4_clken), + .CLK(CLK32M_I) ); m6522 USER_VIA ( @@ -482,12 +492,19 @@ saa5050 TELETEXT ( initial begin : via_init - //user_via_cb1_in = 1'b 0; - user_via_ca2_in = 1'b 0; - user_via_ca1_in = 1'b 0; - user_via_ca2_in = 1'b 0; - crtc_lpstb = 1'b 0; - + user_via_ca1_in = 1'b 0; + user_via_ca2_in = 1'b 0; + crtc_lpstb = 1'b 0; + +end + +// This is needed as in v003 of the 6522 data out is only valid while I_P2_H is asserted +// I_P2_H is driven from mhz1_clken +always @(posedge CLK32M_I) begin + if (mhz1_clken) begin + user_via_do_r <= user_via_do; + sys_via_do_r <= sys_via_do; + end end // rom select latch @@ -519,11 +536,6 @@ always @(posedge CLK32M_I) begin end - // retard DI by one cpu clock cycle - if (cpu_clken === 1'b1) begin - cpu_di_r <= cpu_di; - end - end end @@ -619,8 +631,8 @@ assign cpu_di = ram_enable === 1'b 1 ? MEM_DI : mos_enable === 1'b 1 ? MEM_DI : crtc_enable === 1'b 1 ? crtc_do : acia_enable === 1'b 1 ? 8'b 00000010 : - sys_via_enable === 1'b 1 ? sys_via_do : - user_via_enable === 1'b 1 ? user_via_do : + sys_via_enable === 1'b 1 ? sys_via_do_r : + user_via_enable === 1'b 1 ? user_via_do_r : adc_enable === 1'b 1 ? adc_do : //tube_enable === 1'b 1 ? tube_do : //adlc_enable === 1'b 1 ? bbcddr_out : diff --git a/cores/bbc/rtl/cpu.v b/cores/bbc/rtl/cpu.v deleted file mode 100755 index 6081128..0000000 --- a/cores/bbc/rtl/cpu.v +++ /dev/null @@ -1,1225 +0,0 @@ -/* - * verilog model of 6502 CPU. - * - * (C) Arlet Ottens, - * - * Feel free to use this code in any project (commercial or not), as long as you - * keep this message, and the copyright notice. This code is provided "as is", - * without any warranties of any kind. - * - */ - -/* - * Note that not all 6502 interface signals are supported (yet). The goal - * is to create an Acorn Atom model, and the Atom didn't use all signals on - * the main board. - * - * The data bus is implemented as separate read/write buses. Combine them - * on the output pads if external memory is required. - */ - -module cpu( clk, reset, AB, DI, DO, WE, IRQ, NMI, RDY ); - -input clk; // CPU clock -input reset; // reset signal -output reg [15:0] AB; // address bus -input [7:0] DI; // data in, read bus -output [7:0] DO; // data out, write bus -output WE; // write enable -input IRQ; // interrupt request -input NMI; // non-maskable interrupt request -input RDY; // Ready signal. Pauses CPU when RDY=0 - -/* - * internal signals - */ - -reg [15:0] PC; // Program Counter -reg [7:0] ABL; // Address Bus Register LSB -reg [7:0] ABH; // Address Bus Register MSB -wire [7:0] ADD; // Adder Hold Register (registered in ALU) - -reg [7:0] DIHOLD; // Hold for Data In -reg DIHOLD_valid; // -wire [7:0] DIMUX; // - -reg [7:0] IRHOLD; // Hold for Instruction register -reg IRHOLD_valid; // Valid instruction in IRHOLD - -reg [7:0] AXYS[3:0]; // A, X, Y and S register file - -reg C = 0; // carry flag (init at zero to avoid X's in ALU sim) -reg Z = 0; // zero flag -reg I = 0; // interrupt flag -reg D = 0; // decimal flag -reg V = 0; // overflow flag -reg N = 0; // negative flag -wire AZ; // ALU Zero flag -wire AV; // ALU overflow flag -wire AN; // ALU negative flag -wire HC; // ALU half carry - -reg [7:0] AI; // ALU Input A -reg [7:0] BI; // ALU Input B -wire [7:0] DI; // Data In -wire [7:0] IR; // Instruction register -reg [7:0] DO; // Data Out -reg WE; // Write Enable -reg CI; // Carry In -wire CO; // Carry Out -wire [7:0] PCH = PC[15:8]; -wire [7:0] PCL = PC[7:0]; - -reg NMI_edge = 0; // captured NMI edge - -reg [1:0] regsel; // Select A, X, Y or S register -wire [7:0] regfile = AXYS[regsel]; // Selected register output - -parameter - SEL_A = 2'd0, - SEL_S = 2'd1, - SEL_X = 2'd2, - SEL_Y = 2'd3; - -/* - * define some signals for watching in simulator output - */ - - -`ifdef SIM -wire [7:0] A = AXYS[SEL_A]; // Accumulator -wire [7:0] X = AXYS[SEL_X]; // X register -wire [7:0] Y = AXYS[SEL_Y]; // Y register -wire [7:0] S = AXYS[SEL_S]; // Stack pointer -`endif - -wire [7:0] P = { N, V, 2'b11, D, I, Z, C }; - -/* - * instruction decoder/sequencer - */ - -reg [5:0] state; - -/* - * control signals - */ - -reg PC_inc; // Increment PC -reg [15:0] PC_temp; // intermediate value of PC - -reg [1:0] src_reg; // source register index -reg [1:0] dst_reg; // destination register index - -reg index_y; // if set, then Y is index reg rather than X -reg load_reg; // loading a register (A, X, Y, S) in this instruction -reg inc; // increment -reg write_back; // set if memory is read/modified/written -reg load_only; // LDA/LDX/LDY instruction -reg store; // doing store (STA/STX/STY) -reg adc_sbc; // doing ADC/SBC -reg compare; // doing CMP/CPY/CPX -reg shift; // doing shift/rotate instruction -reg rotate; // doing rotate (no shift) -reg backwards; // backwards branch -reg cond_true; // branch condition is true -reg [2:0] cond_code; // condition code bits from instruction -reg shift_right; // Instruction ALU shift/rotate right -reg alu_shift_right; // Current cycle shift right enable -reg [3:0] op; // Main ALU operation for instruction -reg [3:0] alu_op; // Current cycle ALU operation -reg adc_bcd; // ALU should do BCD style carry -reg adj_bcd; // results should be BCD adjusted - -/* - * some flip flops to remember we're doing special instructions. These - * get loaded at the DECODE state, and used later - */ -reg bit_ins; // doing BIT instruction -reg plp; // doing PLP instruction -reg php; // doing PHP instruction -reg clc; // clear carry -reg sec; // set carry -reg cld; // clear decimal -reg sed; // set decimal -reg cli; // clear interrupt -reg sei; // set interrupt -reg clv; // clear overflow -reg brk; // doing BRK - -reg res; // in reset - -/* - * ALU operations - */ - -parameter - OP_OR = 4'b1100, - OP_AND = 4'b1101, - OP_EOR = 4'b1110, - OP_ADD = 4'b0011, - OP_SUB = 4'b0111, - OP_ROL = 4'b1011, - OP_A = 4'b1111; - -/* - * Microcode state machine. Basically, every addressing mode has its own - * path through the state machine. Additional information, such as the - * operation, source and destination registers are decoded in parallel, and - * kept in separate flops. - */ - -parameter - ABS0 = 6'd0, // ABS - fetch LSB - ABS1 = 6'd1, // ABS - fetch MSB - ABSX0 = 6'd2, // ABS, X - fetch LSB and send to ALU (+X) - ABSX1 = 6'd3, // ABS, X - fetch MSB and send to ALU (+Carry) - ABSX2 = 6'd4, // ABS, X - Wait for ALU (only if needed) - BRA0 = 6'd5, // Branch - fetch offset and send to ALU (+PC[7:0]) - BRA1 = 6'd6, // Branch - fetch opcode, and send PC[15:8] to ALU - BRA2 = 6'd7, // Branch - fetch opcode (if page boundary crossed) - BRK0 = 6'd8, // BRK/IRQ - push PCH, send S to ALU (-1) - BRK1 = 6'd9, // BRK/IRQ - push PCL, send S to ALU (-1) - BRK2 = 6'd10, // BRK/IRQ - push P, send S to ALU (-1) - BRK3 = 6'd11, // BRK/IRQ - write S, and fetch @ fffe - DECODE = 6'd12, // IR is valid, decode instruction, and write prev reg - FETCH = 6'd13, // fetch next opcode, and perform prev ALU op - INDX0 = 6'd14, // (ZP,X) - fetch ZP address, and send to ALU (+X) - INDX1 = 6'd15, // (ZP,X) - fetch LSB at ZP+X, calculate ZP+X+1 - INDX2 = 6'd16, // (ZP,X) - fetch MSB at ZP+X+1 - INDX3 = 6'd17, // (ZP,X) - fetch data - INDY0 = 6'd18, // (ZP),Y - fetch ZP address, and send ZP to ALU (+1) - INDY1 = 6'd19, // (ZP),Y - fetch at ZP+1, and send LSB to ALU (+Y) - INDY2 = 6'd20, // (ZP),Y - fetch data, and send MSB to ALU (+Carry) - INDY3 = 6'd21, // (ZP),Y) - fetch data (if page boundary crossed) - JMP0 = 6'd22, // JMP - fetch PCL and hold - JMP1 = 6'd23, // JMP - fetch PCH - JMPI0 = 6'd24, // JMP IND - fetch LSB and send to ALU for delay (+0) - JMPI1 = 6'd25, // JMP IND - fetch MSB, proceed with JMP0 state - JSR0 = 6'd26, // JSR - push PCH, save LSB, send S to ALU (-1) - JSR1 = 6'd27, // JSR - push PCL, send S to ALU (-1) - JSR2 = 6'd28, // JSR - write S - JSR3 = 6'd29, // JSR - fetch MSB - PULL0 = 6'd30, // PLP/PLA - save next op in IRHOLD, send S to ALU (+1) - PULL1 = 6'd31, // PLP/PLA - fetch data from stack, write S - PULL2 = 6'd32, // PLP/PLA - prefetch op, but don't increment PC - PUSH0 = 6'd33, // PHP/PHA - send A to ALU (+0) - PUSH1 = 6'd34, // PHP/PHA - write A/P, send S to ALU (-1) - READ = 6'd35, // Read memory for read/modify/write (INC, DEC, shift) - REG = 6'd36, // Read register for reg-reg transfers - RTI0 = 6'd37, // RTI - send S to ALU (+1) - RTI1 = 6'd38, // RTI - read P from stack - RTI2 = 6'd39, // RTI - read PCL from stack - RTI3 = 6'd40, // RTI - read PCH from stack - RTI4 = 6'd41, // RTI - read PCH from stack - RTS0 = 6'd42, // RTS - send S to ALU (+1) - RTS1 = 6'd43, // RTS - read PCL from stack - RTS2 = 6'd44, // RTS - write PCL to ALU, read PCH - RTS3 = 6'd45, // RTS - load PC and increment - WRITE = 6'd46, // Write memory for read/modify/write - ZP0 = 6'd47, // Z-page - fetch ZP address - ZPX0 = 6'd48, // ZP, X - fetch ZP, and send to ALU (+X) - ZPX1 = 6'd49; // ZP, X - load from memory - -`ifdef SIM - -/* - * easy to read names in simulator output - */ -reg [8*6-1:0] statename; - -always @* - case( state ) - DECODE: statename = "DECODE"; - REG: statename = "REG"; - ZP0: statename = "ZP0"; - ZPX0: statename = "ZPX0"; - ZPX1: statename = "ZPX1"; - ABS0: statename = "ABS0"; - ABS1: statename = "ABS1"; - ABSX0: statename = "ABSX0"; - ABSX1: statename = "ABSX1"; - ABSX2: statename = "ABSX2"; - INDX0: statename = "INDX0"; - INDX1: statename = "INDX1"; - INDX2: statename = "INDX2"; - INDX3: statename = "INDX3"; - INDY0: statename = "INDY0"; - INDY1: statename = "INDY1"; - INDY2: statename = "INDY2"; - INDY3: statename = "INDY3"; - READ: statename = "READ"; - WRITE: statename = "WRITE"; - FETCH: statename = "FETCH"; - PUSH0: statename = "PUSH0"; - PUSH1: statename = "PUSH1"; - PULL0: statename = "PULL0"; - PULL1: statename = "PULL1"; - PULL2: statename = "PULL2"; - JSR0: statename = "JSR0"; - JSR1: statename = "JSR1"; - JSR2: statename = "JSR2"; - JSR3: statename = "JSR3"; - RTI0: statename = "RTI0"; - RTI1: statename = "RTI1"; - RTI2: statename = "RTI2"; - RTI3: statename = "RTI3"; - RTI4: statename = "RTI4"; - RTS0: statename = "RTS0"; - RTS1: statename = "RTS1"; - RTS2: statename = "RTS2"; - RTS3: statename = "RTS3"; - BRK0: statename = "BRK0"; - BRK1: statename = "BRK1"; - BRK2: statename = "BRK2"; - BRK3: statename = "BRK3"; - BRA0: statename = "BRA0"; - BRA1: statename = "BRA1"; - BRA2: statename = "BRA2"; - JMP0: statename = "JMP0"; - JMP1: statename = "JMP1"; - JMPI0: statename = "JMPI0"; - JMPI1: statename = "JMPI1"; - endcase - -//always @( PC ) -// $display( "%t, PC:%04x IR:%02x A:%02x X:%02x Y:%02x S:%02x C:%d Z:%d V:%d N:%d P:%02x", $time, PC, IR, A, X, Y, S, C, Z, V, N, P ); - -`endif - - - -/* - * Program Counter Increment/Load. First calculate the base value in - * PC_temp. - */ -always @* - case( state ) - DECODE: if( (~I & IRQ) | NMI_edge ) - PC_temp = { ABH, ABL }; - else - PC_temp = PC; - - - JMP1, - JMPI1, - JSR3, - RTS3, - RTI4: PC_temp = { DIMUX, ADD }; - - BRA1: PC_temp = { ABH, ADD }; - - BRA2: PC_temp = { ADD, PCL }; - - BRK2: PC_temp = res ? 16'hfffc : - NMI_edge ? 16'hfffa : 16'hfffe; - - default: PC_temp = PC; - endcase - -/* - * Determine wether we need PC_temp, or PC_temp + 1 - */ -always @* - case( state ) - DECODE: if( (~I & IRQ) | NMI_edge ) - PC_inc = 0; - else - PC_inc = 1; - - ABS0, - ABSX0, - FETCH, - BRA0, - BRA2, - BRK3, - JMPI1, - JMP1, - RTI4, - RTS3: PC_inc = 1; - - BRA1: PC_inc = CO ^~ backwards; - - default: PC_inc = 0; - endcase - -/* - * Set new PC - */ -always @(posedge clk) - if( RDY ) - PC <= PC_temp + PC_inc; - -/* - * Address Generator - */ - -parameter - ZEROPAGE = 8'h00, - STACKPAGE = 8'h01; - -always @* - case( state ) - ABSX1, - INDX3, - INDY2, - JMP1, - JMPI1, - RTI4, - ABS1: AB = { DIMUX, ADD }; - - BRA2, - INDY3, - ABSX2: AB = { ADD, ABL }; - - BRA1: AB = { ABH, ADD }; - - JSR0, - PUSH1, - RTS0, - RTI0, - BRK0: AB = { STACKPAGE, regfile }; - - BRK1, - JSR1, - PULL1, - RTS1, - RTS2, - RTI1, - RTI2, - RTI3, - BRK2: AB = { STACKPAGE, ADD }; - - INDY1, - INDX1, - ZPX1, - INDX2: AB = { ZEROPAGE, ADD }; - - ZP0, - INDY0: AB = { ZEROPAGE, DIMUX }; - - REG, - READ, - WRITE: AB = { ABH, ABL }; - - default: AB = PC; - endcase - -/* - * ABH/ABL pair is used for registering previous address bus state. - * This can be used to keep the current address, freeing up the original - * source of the address, such as the ALU or DI. - */ -always @(posedge clk) - if( state != PUSH0 && state != PUSH1 && RDY && - state != PULL0 && state != PULL1 && state != PULL2 ) - begin - ABL <= AB[7:0]; - ABH <= AB[15:8]; - end - -/* - * Data Out MUX - */ -always @* - case( state ) - WRITE: DO = ADD; - - JSR0, - BRK0: DO = PCH; - - JSR1, - BRK1: DO = PCL; - - PUSH1: DO = php ? P : ADD; - - BRK2: DO = (IRQ | NMI_edge) ? (P & 8'b1110_1111) : P; - - default: DO = regfile; - endcase - -/* - * Write Enable Generator - */ - -always @* - case( state ) - BRK0, // writing to stack or memory - BRK1, - BRK2, - JSR0, - JSR1, - PUSH1, - WRITE: WE = 1; - - INDX3, // only if doing a STA, STX or STY - INDY3, - ABSX2, - ABS1, - ZPX1, - ZP0: WE = store; - - default: WE = 0; - endcase - -/* - * register file, contains A, X, Y and S (stack pointer) registers. At each - * cycle only 1 of those registers needs to be accessed, so they combined - * in a small memory, saving resources. - */ - -reg write_register; // set when register file is written - -always @* - case( state ) - DECODE: write_register = load_reg & ~plp; - - PULL1, - RTS2, - RTI3, - BRK3, - JSR0, - JSR2 : write_register = 1; - - default: write_register = 0; - endcase - -/* - * BCD adjust logic - */ - -always @(posedge clk) - adj_bcd <= adc_sbc & D; // '1' when doing a BCD instruction - -reg [3:0] ADJL; -reg [3:0] ADJH; - -// adjustment term to be added to ADD[3:0] based on the following -// adj_bcd: '1' if doing ADC/SBC with D=1 -// adc_bcd: '1' if doing ADC with D=1 -// HC : half carry bit from ALU -always @* begin - casex( {adj_bcd, adc_bcd, HC} ) - 3'b0xx: ADJL = 4'd0; // no BCD instruction - 3'b100: ADJL = 4'd10; // SBC, and digital borrow - 3'b101: ADJL = 4'd0; // SBC, but no borrow - 3'b110: ADJL = 4'd0; // ADC, but no carry - 3'b111: ADJL = 4'd6; // ADC, and decimal/digital carry - endcase -end - -// adjustment term to be added to ADD[7:4] based on the following -// adj_bcd: '1' if doing ADC/SBC with D=1 -// adc_bcd: '1' if doing ADC with D=1 -// CO : carry out bit from ALU -always @* begin - casex( {adj_bcd, adc_bcd, CO} ) - 3'b0xx: ADJH = 4'd0; // no BCD instruction - 3'b100: ADJH = 4'd10; // SBC, and digital borrow - 3'b101: ADJH = 4'd0; // SBC, but no borrow - 3'b110: ADJH = 4'd0; // ADC, but no carry - 3'b111: ADJH = 4'd6; // ADC, and decimal/digital carry - endcase -end - -/* - * write to a register. Usually this is the (BCD corrected) output of the - * ALU, but in case of the JSR0 we use the S register to temporarily store - * the PCL. This is possible, because the S register itself is stored in - * the ALU during those cycles. - */ -always @(posedge clk) - if( write_register & RDY ) - AXYS[regsel] <= (state == JSR0) ? DIMUX : { ADD[7:4] + ADJH, ADD[3:0] + ADJL }; - -/* - * register select logic. This determines which of the A, X, Y or - * S registers will be accessed. - */ - -always @* - case( state ) - INDY1, - INDX0, - ZPX0, - ABSX0 : regsel = index_y ? SEL_Y : SEL_X; - - - DECODE : regsel = dst_reg; - - BRK0, - BRK3, - JSR0, - JSR2, - PULL0, - PULL1, - PUSH1, - RTI0, - RTI3, - RTS0, - RTS2 : regsel = SEL_S; - - default: regsel = src_reg; - endcase - -/* - * ALU - */ - -ALU ALU( .clk(clk), - .op(alu_op), - .right(alu_shift_right), - .AI(AI), - .BI(BI), - .CI(CI), - .BCD(adc_bcd & (state == FETCH)), - .CO(CO), - .OUT(ADD), - .V(AV), - .Z(AZ), - .N(AN), - .HC(HC), - .RDY(RDY) ); - -/* - * Select current ALU operation - */ - -always @* - case( state ) - READ: alu_op = op; - - BRA1: alu_op = backwards ? OP_SUB : OP_ADD; - - FETCH, - REG : alu_op = op; - - DECODE, - ABS1: alu_op = 1'bx; - - PUSH1, - BRK0, - BRK1, - BRK2, - JSR0, - JSR1: alu_op = OP_SUB; - - default: alu_op = OP_ADD; - endcase - -/* - * Determine shift right signal to ALU - */ - -always @* - if( state == FETCH || state == REG || state == READ ) - alu_shift_right = shift_right; - else - alu_shift_right = 0; - -/* - * Sign extend branch offset. - */ - -always @(posedge clk) - if( RDY ) - backwards <= DIMUX[7]; - -/* - * ALU A Input MUX - */ - -always @* - case( state ) - JSR1, - RTS1, - RTI1, - RTI2, - BRK1, - BRK2, - INDX1: AI = ADD; - - REG, - ZPX0, - INDX0, - ABSX0, - RTI0, - RTS0, - JSR0, - JSR2, - BRK0, - PULL0, - INDY1, - PUSH0, - PUSH1: AI = regfile; - - BRA0, - READ: AI = DIMUX; - - BRA1: AI = ABH; // don't use PCH in case we're - - FETCH: AI = load_only ? 0 : regfile; - - DECODE, - ABS1: AI = 8'hxx; // don't care - - default: AI = 0; - endcase - - -/* - * ALU B Input mux - */ - -always @* - case( state ) - BRA1, - JSR1, - RTS1, - RTI0, - RTI1, - RTI2, - INDX1, - READ, - REG, - JSR0, - JSR2, - BRK0, - BRK1, - BRK2, - PUSH0, - PUSH1, - PULL0, - RTS0: BI = 8'h00; - - BRA0: BI = PCL; - - DECODE, - ABS1: BI = 8'hxx; - - default: BI = DIMUX; - endcase - -/* - * ALU CI (carry in) mux - */ - -always @* - case( state ) - INDY2, - BRA1, - ABSX1: CI = CO; - - DECODE, - ABS1: CI = 1'bx; - - READ, - REG: CI = rotate ? C : - shift ? 0 : inc; - - FETCH: CI = rotate ? C : - compare ? 1 : - (shift | load_only) ? 0 : C; - - PULL0, - RTI0, - RTI1, - RTI2, - RTS0, - RTS1, - INDY0, - INDX1: CI = 1; - - default: CI = 0; - endcase - -/* - * Processor Status Register update - * - */ - -/* - * Update C flag when doing ADC/SBC, shift/rotate, compare - */ -always @(posedge clk ) - if( shift && state == WRITE ) - C <= CO; - else if( state == RTI2 ) - C <= DIMUX[0]; - else if( ~write_back && state == DECODE ) begin - if( adc_sbc | shift | compare ) - C <= CO; - else if( plp ) - C <= ADD[0]; - else begin - if( sec ) C <= 1; - if( clc ) C <= 0; - end - end - -/* - * Update Z, N flags when writing A, X, Y, Memory, or when doing compare - */ - -always @(posedge clk) - if( state == WRITE ) - Z <= AZ; - else if( state == RTI2 ) - Z <= DIMUX[1]; - else if( state == DECODE ) begin - if( plp ) - Z <= ADD[1]; - else if( (load_reg & (regsel != SEL_S)) | compare | bit_ins ) - Z <= AZ; - end - -always @(posedge clk) - if( state == WRITE ) - N <= AN; - else if( state == RTI2 ) - N <= DIMUX[7]; - else if( state == DECODE ) begin - if( plp ) - N <= ADD[7]; - else if( (load_reg & (regsel != SEL_S)) | compare ) - N <= AN; - end else if( state == FETCH && bit_ins ) - N <= DIMUX[7]; - -/* - * Update I flag - */ - -always @(posedge clk) - if( state == BRK3 ) - I <= 1; - else if( state == RTI2 ) - I <= DIMUX[2]; - else if( state == REG ) begin - if( sei ) I <= 1; - if( cli ) I <= 0; - end else if( state == DECODE ) - if( plp ) I <= ADD[2]; - -/* - * Update D flag - */ -always @(posedge clk ) - if( state == RTI2 ) - D <= DIMUX[3]; - else if( state == DECODE ) begin - if( sed ) D <= 1; - if( cld ) D <= 0; - if( plp ) D <= ADD[3]; - end - -/* - * Update V flag - */ -always @(posedge clk ) - if( state == RTI2 ) - V <= DIMUX[6]; - else if( state == DECODE ) begin - if( adc_sbc ) V <= AV; - if( clv ) V <= 0; - if( plp ) V <= ADD[6]; - end else if( state == FETCH && bit_ins ) - V <= DIMUX[6]; - -/* - * Instruction decoder - */ - -/* - * IR register/mux. Hold previous DI value in IRHOLD in PULL0 and PUSH0 - * states. In these states, the IR has been prefetched, and there is no - * time to read the IR again before the next decode. - */ - -reg RDY1 = 1; - -always @(posedge clk ) - RDY1 <= RDY; - -always @(posedge clk ) - if( ~RDY && RDY1 ) - DIHOLD <= DI; - -always @(posedge clk ) - if( reset ) - IRHOLD_valid <= 0; - else if( RDY ) begin - if( state == PULL0 || state == PUSH0 ) begin - IRHOLD <= DIMUX; - IRHOLD_valid <= 1; - end else if( state == DECODE ) - IRHOLD_valid <= 0; - end - -assign IR = (IRQ & ~I) | NMI_edge ? 8'h00 : - IRHOLD_valid ? IRHOLD : DIMUX; - -assign DIMUX = ~RDY1 ? DIHOLD : DI; - -/* - * Microcode state machine - */ -always @(posedge clk or posedge reset) - if( reset ) - state <= BRK0; - else if( RDY ) case( state ) - DECODE : - casex ( IR ) - 8'b0000_0000: state <= BRK0; - 8'b0010_0000: state <= JSR0; - 8'b0010_1100: state <= ABS0; // BIT abs - 8'b0100_0000: state <= RTI0; // - 8'b0100_1100: state <= JMP0; - 8'b0110_0000: state <= RTS0; - 8'b0110_1100: state <= JMPI0; - 8'b0x00_1000: state <= PUSH0; - 8'b0x10_1000: state <= PULL0; - 8'b0xx1_1000: state <= REG; // CLC, SEC, CLI, SEI - 8'b1xx0_00x0: state <= FETCH; // IMM - 8'b1xx0_1100: state <= ABS0; // X/Y abs - 8'b1xxx_1000: state <= REG; // DEY, TYA, ... - 8'bxxx0_0001: state <= INDX0; - 8'bxxx0_01xx: state <= ZP0; - 8'bxxx0_1001: state <= FETCH; // IMM - 8'bxxx0_1101: state <= ABS0; // even E column - 8'bxxx0_1110: state <= ABS0; // even E column - 8'bxxx1_0000: state <= BRA0; // odd 0 column - 8'bxxx1_0001: state <= INDY0; // odd 1 column - 8'bxxx1_01xx: state <= ZPX0; // odd 4,5,6,7 columns - 8'bxxx1_1001: state <= ABSX0; // odd 9 column - 8'bxxx1_11xx: state <= ABSX0; // odd C, D, E, F columns - 8'bxxxx_1010: state <= REG; // A, TXA, ... NOP - endcase - - ZP0 : state <= write_back ? READ : FETCH; - - ZPX0 : state <= ZPX1; - ZPX1 : state <= write_back ? READ : FETCH; - - ABS0 : state <= ABS1; - ABS1 : state <= write_back ? READ : FETCH; - - ABSX0 : state <= ABSX1; - ABSX1 : state <= (CO | store | write_back) ? ABSX2 : FETCH; - ABSX2 : state <= write_back ? READ : FETCH; - - INDX0 : state <= INDX1; - INDX1 : state <= INDX2; - INDX2 : state <= INDX3; - INDX3 : state <= FETCH; - - INDY0 : state <= INDY1; - INDY1 : state <= INDY2; - INDY2 : state <= (CO | store) ? INDY3 : FETCH; - INDY3 : state <= FETCH; - - READ : state <= WRITE; - WRITE : state <= FETCH; - FETCH : state <= DECODE; - - REG : state <= DECODE; - - PUSH0 : state <= PUSH1; - PUSH1 : state <= DECODE; - - PULL0 : state <= PULL1; - PULL1 : state <= PULL2; - PULL2 : state <= DECODE; - - JSR0 : state <= JSR1; - JSR1 : state <= JSR2; - JSR2 : state <= JSR3; - JSR3 : state <= FETCH; - - RTI0 : state <= RTI1; - RTI1 : state <= RTI2; - RTI2 : state <= RTI3; - RTI3 : state <= RTI4; - RTI4 : state <= DECODE; - - RTS0 : state <= RTS1; - RTS1 : state <= RTS2; - RTS2 : state <= RTS3; - RTS3 : state <= FETCH; - - BRA0 : state <= cond_true ? BRA1 : DECODE; - BRA1 : state <= (CO ^ backwards) ? BRA2 : DECODE; - BRA2 : state <= DECODE; - - JMP0 : state <= JMP1; - JMP1 : state <= DECODE; - - JMPI0 : state <= JMPI1; - JMPI1 : state <= JMP0; - - BRK0 : state <= BRK1; - BRK1 : state <= BRK2; - BRK2 : state <= BRK3; - BRK3 : state <= JMP0; - - endcase - -/* - * Additional control signals - */ - -always @(posedge clk) - if( reset ) - res <= 1; - else if( state == DECODE ) - res <= 0; - -always @(posedge clk) - if( state == DECODE && RDY ) - casex( IR ) - 8'b0xx01010, // ASLA, ROLA, LSRA, RORA - 8'b0xxxxx01, // ORA, AND, EOR, ADC - 8'b100x10x0, // DEY, TYA, TXA, TXS - 8'b1010xxx0, // LDA/LDX/LDY - 8'b10111010, // TSX - 8'b1011x1x0, // LDX/LDY - 8'b11001010, // DEX - 8'b1x1xxx01, // LDA, SBC - 8'bxxx01000: // DEY, TAY, INY, INX - load_reg <= 1; - - default: load_reg <= 0; - endcase - -always @(posedge clk) - if( state == DECODE && RDY ) - casex( IR ) - 8'b1110_1000, // INX - 8'b1100_1010, // DEX - 8'b101x_xx10: // LDX, TAX, TSX - dst_reg <= SEL_X; - - 8'b0x00_1000, // PHP, PHA - 8'b1001_1010: // TXS - dst_reg <= SEL_S; - - 8'b1x00_1000, // DEY, DEX - 8'b101x_x100, // LDY - 8'b1010_x000: // LDY #imm, TAY - dst_reg <= SEL_Y; - - default: dst_reg <= SEL_A; - endcase - -always @(posedge clk) - if( state == DECODE && RDY ) - casex( IR ) - 8'b1011_1010: // TSX - src_reg <= SEL_S; - - 8'b100x_x110, // STX - 8'b100x_1x10, // TXA, TXS - 8'b1110_xx00, // INX, CPX - 8'b1100_1010: // DEX - src_reg <= SEL_X; - - 8'b100x_x100, // STY - 8'b1001_1000, // TYA - 8'b1100_xx00, // CPY - 8'b1x00_1000: // DEY, INY - src_reg <= SEL_Y; - - default: src_reg <= SEL_A; - endcase - -always @(posedge clk) - if( state == DECODE && RDY ) - casex( IR ) - 8'bxxx1_0001, // INDY - 8'b10x1_x110, // LDX/STX zpg/abs, Y - 8'bxxxx_1001: // abs, Y - index_y <= 1; - - default: index_y <= 0; - endcase - - -always @(posedge clk) - if( state == DECODE && RDY ) - casex( IR ) - 8'b100x_x1x0, // STX, STY - 8'b100x_xx01: // STA - store <= 1; - - default: store <= 0; - - endcase - -always @(posedge clk ) - if( state == DECODE && RDY ) - casex( IR ) - 8'b0xxx_x110, // ASL, ROL, LSR, ROR - 8'b11xx_x110: // DEC/INC - write_back <= 1; - - default: write_back <= 0; - endcase - - -always @(posedge clk ) - if( state == DECODE && RDY ) - casex( IR ) - 8'b101x_xxxx: // LDA, LDX, LDY - load_only <= 1; - default: load_only <= 0; - endcase - -always @(posedge clk ) - if( state == DECODE && RDY ) - casex( IR ) - 8'b111x_x110, // INC - 8'b11x0_1000: // INX, INY - inc <= 1; - - default: inc <= 0; - endcase - -always @(posedge clk ) - if( (state == DECODE || state == BRK0) && RDY ) - casex( IR ) - 8'bx11x_xx01: // SBC, ADC - adc_sbc <= 1; - - default: adc_sbc <= 0; - endcase - -always @(posedge clk ) - if( (state == DECODE || state == BRK0) && RDY ) - casex( IR ) - 8'b011x_xx01: // ADC - adc_bcd <= D; - - default: adc_bcd <= 0; - endcase - -always @(posedge clk ) - if( state == DECODE && RDY ) - casex( IR ) - 8'b0xxx_x110, // ASL, ROL, LSR, ROR (abs, absx, zpg, zpgx) - 8'b0xxx_1010: // ASL, ROL, LSR, ROR (acc) - shift <= 1; - - default: shift <= 0; - endcase - -always @(posedge clk ) - if( state == DECODE && RDY ) - casex( IR ) - 8'b11x0_0x00, // CPX, CPY (imm/zp) - 8'b11x0_1100, // CPX, CPY (abs) - 8'b110x_xx01: // CMP - compare <= 1; - - default: compare <= 0; - endcase - -always @(posedge clk ) - if( state == DECODE && RDY ) - casex( IR ) - 8'b01xx_xx10: // ROR, LSR - shift_right <= 1; - - default: shift_right <= 0; - endcase - -always @(posedge clk ) - if( state == DECODE && RDY ) - casex( IR ) - 8'b0x1x_1010, // ROL A, ROR A - 8'b0x1x_x110: // ROR, ROL - rotate <= 1; - - default: rotate <= 0; - endcase - -always @(posedge clk ) - if( state == DECODE && RDY ) - casex( IR ) - 8'b00xx_xx10: // ROL, ASL - op <= OP_ROL; - - 8'b0010_x100: // BIT zp/abs - op <= OP_AND; - - 8'b01xx_xx10: // ROR, LSR - op <= OP_A; - - 8'b1000_1000, // DEY - 8'b1100_1010, // DEX - 8'b110x_x110, // DEC - 8'b11xx_xx01, // CMP, SBC - 8'b11x0_0x00, // CPX, CPY (imm, zpg) - 8'b11x0_1100: op <= OP_SUB; - - 8'b010x_xx01, // EOR - 8'b00xx_xx01: // ORA, AND - op <= { 2'b11, IR[6:5] }; - - default: op <= OP_ADD; - endcase - -always @(posedge clk ) - if( state == DECODE && RDY ) - casex( IR ) - 8'b0010_x100: // BIT zp/abs - bit_ins <= 1; - - default: bit_ins <= 0; - endcase - -/* - * special instructions - */ -always @(posedge clk ) - if( state == DECODE && RDY ) begin - php <= (IR == 8'h08); - clc <= (IR == 8'h18); - plp <= (IR == 8'h28); - sec <= (IR == 8'h38); - cli <= (IR == 8'h58); - sei <= (IR == 8'h78); - clv <= (IR == 8'hb8); - cld <= (IR == 8'hd8); - sed <= (IR == 8'hf8); - brk <= (IR == 8'h00); - end - -always @(posedge clk) - if( RDY ) - cond_code <= IR[7:5]; - -always @* - case( cond_code ) - 3'b000: cond_true = ~N; - 3'b001: cond_true = N; - 3'b010: cond_true = ~V; - 3'b011: cond_true = V; - 3'b100: cond_true = ~C; - 3'b101: cond_true = C; - 3'b110: cond_true = ~Z; - 3'b111: cond_true = Z; - endcase - - -reg NMI_1 = 0; // delayed NMI signal - -always @(posedge clk) - NMI_1 <= NMI; - -always @(posedge clk ) - if( NMI_edge && state == BRK3 ) - NMI_edge <= 0; - else if( NMI & ~NMI_1 ) - NMI_edge <= 1; - -endmodule diff --git a/cores/bbc/rtl/m6522.v b/cores/bbc/rtl/m6522.v deleted file mode 100755 index f3b6a5c..0000000 --- a/cores/bbc/rtl/m6522.v +++ /dev/null @@ -1,1165 +0,0 @@ -`timescale 1 ns / 1 ns // timescale for following modules -// -// A simulation model of VIC20 hardware -// Copyright (c) MikeJ - March 2003 -// -// 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 CODE 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. -// -// You are responsible for any legal issues arising from your use of this code. -// -// The latest version of this file can be found at: www.fpgaarcade.com -// -// Email vic20@fpgaarcade.com -// -// -// Revision list -// -// version 004 fixes to PB7 T1 control and Mode 0 Shift Register operation -// version 003 fix reset of T1/T2 IFR flags if T1/T2 is reload via reg5/reg9 from wolfgang (WoS) -// Ported to numeric_std and simulation fix for signal initializations from arnim laeuger -// version 002 fix from Mark McDougall, untested -// version 001 initial release -// not very sure about the shift register, documentation is a bit light. - -module m6522 ( - I_RS, - I_DATA, - O_DATA, - O_DATA_OE_L, - I_RW_L, - I_CS1, - I_CS2_L, - O_IRQ_L, - I_CA1, - I_CA2, - O_CA2, - O_CA2_OE_L, - I_PA, - O_PA, - O_PA_OE_L, - I_CB1, - O_CB1, - O_CB1_OE_L, - I_CB2, - O_CB2, - O_CB2_OE_L, - I_PB, - O_PB, - O_PB_OE_L, - I_P2_H, - RESET_L, - ENA_4, - CLK); - - -input [3:0] I_RS; -input [7:0] I_DATA; -output reg [7:0] O_DATA; -output O_DATA_OE_L; -input I_RW_L; -input I_CS1; -input I_CS2_L; -output O_IRQ_L; -input I_CA1; -input I_CA2; -output O_CA2; -output O_CA2_OE_L; -input [7:0] I_PA; -output [7:0] O_PA; -output [7:0] O_PA_OE_L; -input I_CB1; -output O_CB1; -output O_CB1_OE_L; -input I_CB2; -output O_CB2; -output O_CB2_OE_L; -input [7:0] I_PB; -output [7:0] O_PB; -output [7:0] O_PB_OE_L; -input I_P2_H; -input RESET_L; -input ENA_4; -input CLK; - - -reg O_CA2; -reg O_CA2_OE_L; - - -// port b -wire O_CB1; -wire O_CB1_OE_L; -reg O_CB2; -reg O_CB2_OE_L; -reg [1:0] phase = 2'b00; -reg p2_h_t1; -wire cs; - -// registers -reg [7:0] r_ddra; -reg [7:0] r_ora; -reg [7:0] r_ira; -reg [7:0] r_ddrb; -reg [7:0] r_orb; -reg [7:0] r_irb; -reg [7:0] r_t1l_l; -reg [7:0] r_t1l_h; -reg [7:0] r_t2l_l; -reg [7:0] r_t2l_h; -// not in real chip -reg [7:0] r_sr; -reg [7:0] r_acr; -reg [7:0] r_pcr; -wire [7:0] r_ifr; -reg [6:0] r_ier; -reg sr_write_ena; -reg sr_read_ena; -reg ifr_write_ena; -reg ier_write_ena; -wire [7:0] clear_irq; -reg [7:0] load_data; - -// timer 1 -reg [15:0] t1c; -reg t1c_active; -reg t1c_done; -reg t1_w_reset_int; -reg t1_r_reset_int; -reg t1_load_counter; -reg t1_reload_counter; -reg t1_toggle; -reg t1_irq; - -// timer 2 -reg [15:0] t2c; -reg t2c_active; -reg t2c_done; -reg t2_pb6; -reg t2_pb6_t1; -reg t2_w_reset_int; -reg t2_r_reset_int; -reg t2_load_counter; -reg t2_reload_counter; -reg t2_irq; -reg t2_sr_ena; - -// shift reg -reg [3:0] sr_cnt; -reg sr_cb1_oe_l; -reg sr_cb1_out; -reg sr_drive_cb2; -reg sr_strobe; -reg sr_strobe_t1; -reg sr_strobe_falling; -reg sr_strobe_rising; -reg sr_irq; -reg sr_out; -reg sr_off_delay; - -// io -reg w_orb_hs; -reg w_ora_hs; -reg r_irb_hs; -reg r_ira_hs; -reg ca_hs_sr; -reg ca_hs_pulse; -reg cb_hs_sr; -reg cb_hs_pulse; - -reg ca1_ip_reg; -reg cb1_ip_reg; -wire ca1_int; -wire cb1_int; -reg ca1_irq; -reg cb1_irq; -reg ca2_ip_reg; -reg cb2_ip_reg; -wire ca2_int; -wire cb2_int; -reg ca2_irq; -reg cb2_irq; -reg final_irq; -reg p_timer2_ena; -reg p_sr_dir_out; -reg p_sr_ena; -reg p_sr_cb1_op; -reg p_sr_cb1_ip; -reg p_sr_use_t2; -reg p_sr_free_run; -reg p_sr_sr_count_ena; - -initial begin - t2_irq = 1'b 0; -end - -initial begin - t1_irq = 1'b 0; -end - - -always @(posedge CLK) begin - - if (ENA_4 === 1'b 1) begin - p2_h_t1 <= I_P2_H; - - if (p2_h_t1 === 1'b 0 & I_P2_H === 1'b 1) begin - phase <= 2'b 11; - end - else begin - phase <= phase + 1'b 1; - end - end -end - - -// internal clock phase -assign cs = (I_CS1 === 1'b 1 & I_CS2_L === 1'b 0 & I_P2_H === 1'b 1) ? 1'b1 : 1'b0; - -// peripheral control reg (pcr) -// 0 ca1 interrupt control (0 +ve edge, 1 -ve edge) -// 3..1 ca2 operation -// 000 input -ve edge -// 001 independend interrupt input -ve edge -// 010 input +ve edge -// 011 independend interrupt input +ve edge -// 100 handshake output -// 101 pulse output -// 110 low output -// 111 high output -// 7..4 as 3..0 for cb1,cb2 -// auxiliary control reg (acr) -// 0 input latch PA (0 disable, 1 enable) -// 1 input latch PB (0 disable, 1 enable) -// 4..2 shift reg control -// 000 disable -// 001 shift in using t2 -// 010 shift in using o2 -// 011 shift in using ext clk -// 100 shift out free running t2 rate -// 101 shift out using t2 -// 101 shift out using o2 -// 101 shift out using ext clk -// 5 t2 timer control (0 timed interrupt, 1 count down with pulses on pb6) -// 7..6 t1 timer control -// 00 timed interrupt each time t1 is loaded pb7 disable -// 01 continuous interrupts pb7 disable -// 00 timed interrupt each time t1 is loaded pb7 one shot output -// 01 continuous interrupts pb7 square wave output -// - -always @(posedge CLK) begin - - if (RESET_L === 1'b 0) begin - r_ora <= 8'h 00; - r_orb <= 8'h 00; - r_ddra <= 8'h 00; - r_ddrb <= 8'h 00; - r_acr <= 8'h 00; - r_pcr <= 8'h 00; - w_orb_hs <= 1'b 0; - w_ora_hs <= 1'b 0; - end - else begin - if (ENA_4 === 1'b 1) begin - w_orb_hs <= 1'b 0; - w_ora_hs <= 1'b 0; - - if (cs === 1'b 1 & I_RW_L === 1'b 0) begin - case (I_RS) - 4'h 0: begin - r_orb <= I_DATA; - w_orb_hs <= 1'b 1; - end - - 4'h 1: begin - r_ora <= I_DATA; - w_ora_hs <= 1'b 1; - end - - 4'h 2: begin - r_ddrb <= I_DATA; - end - - 4'h 3: begin - r_ddra <= I_DATA; - end - - 4'h B: begin - r_acr <= I_DATA; - end - - 4'h C: begin - r_pcr <= I_DATA; - end - - 4'h F: begin - r_ora <= I_DATA; - end - - default: - ; - - endcase - end - - if (r_acr[7] === 1'b1) begin - // DMB: Forgetting to clear B7 broke Acornsoft Planetoid - if(t1_load_counter) - r_orb[7] <= 1'b0; // writing T1C-H resets bit 7 - else if (t1_toggle === 1'b1) - r_orb[7] <= ~r_orb[7]; // toggle - end - end - end -end - - -always @(posedge CLK) begin - - if (RESET_L === 1'b 0) begin - // The spec says, this is not reset. - // Fact is that the 1541 VIA1 timer won't work, - // as the firmware ONLY sets the r_t1l_h latch!!!! - // DMB: These are observed power on values from the Beeb - // DMB: Note, it's a little overzeleaous setting these on reset; that doesn't happen in reality - r_t1l_l <= 8'h FE; - r_t1l_h <= 8'h FF; - r_t2l_l <= 8'h FE; - r_t2l_h <= 8'h FF; - end - else begin - - if (ENA_4 === 1'b 1) begin - t1_w_reset_int <= 1'b0; - t1_load_counter <= 1'b0; - t2_w_reset_int <= 1'b0; - t2_load_counter <= 1'b0; - load_data <= 8'h 00; - sr_write_ena <= 1'b0; - ifr_write_ena <= 1'b0; - ier_write_ena <= 1'b0; - - if (cs === 1'b 1 & I_RW_L === 1'b 0) begin - load_data <= I_DATA; - - case (I_RS) - 4'h 4: begin - r_t1l_l <= I_DATA; - end - - 4'h 5: begin - r_t1l_h <= I_DATA; - t1_w_reset_int <= 1'b1; - t1_load_counter <= 1'b1; - end - - 4'h 6: begin - r_t1l_l <= I_DATA; - end - - 4'h 7: begin - r_t1l_h <= I_DATA; - t1_w_reset_int <= 1'b1; - end - - 4'h 8: begin - r_t2l_l <= I_DATA; - end - - 4'h 9: begin - r_t2l_h <= I_DATA; - t2_w_reset_int <= 1'b1; - t2_load_counter <= 1'b1; - end - - 4'h A: begin - sr_write_ena <= 1'b1; - end - - 4'h D: begin - ifr_write_ena <= 1'b1; - end - - 4'h E: begin - ier_write_ena <= 1'b1; - end - - default: - ; - - endcase - end - end - end -end - - -assign O_DATA_OE_L = (cs === 1'b 1 & I_RW_L === 1'b 1) ? 1'b0 : 1'b1; - - -always @(posedge CLK) begin - - if (ENA_4 === 1'b 1) begin - - t1_r_reset_int <= 1'b0; - t2_r_reset_int <= 1'b0; - sr_read_ena <= 1'b0; - r_irb_hs <= 1'b 0; - r_ira_hs <= 1'b 0; - O_DATA <= 8'h 00; // default - - if (cs === 1'b 1 & I_RW_L === 1'b 1) begin - case (I_RS) - // when x"0" => O_DATA <= r_irb; r_irb_hs <= '1'; - // fix from Mark McDougall, untested - 4'h 0: begin - O_DATA <= r_irb & ~r_ddrb | r_orb & r_ddrb; - r_irb_hs <= 1'b 1; - end - - 4'h 1: begin - O_DATA <= r_ira; - r_ira_hs <= 1'b 1; - end - - 4'h 2: begin - O_DATA <= r_ddrb; - end - - 4'h 3: begin - O_DATA <= r_ddra; - end - - 4'h 4: begin - O_DATA <= t1c[7:0]; - t1_r_reset_int <= 1'b1; - end - - 4'h 5: begin - O_DATA <= t1c[15:8]; - end - - 4'h 6: begin - O_DATA <= r_t1l_l; - end - - 4'h 7: begin - O_DATA <= r_t1l_h; - end - - 4'h 8: begin - O_DATA <= t2c[7:0]; - t2_r_reset_int <= 1'b1; - end - - 4'h 9: begin - O_DATA <= t2c[15:8]; - end - - 4'h A: begin - O_DATA <= r_sr; - sr_read_ena <= 1'b1; - end - - 4'h B: begin - O_DATA <= r_acr; - end - - 4'h C: begin - O_DATA <= r_pcr; - end - - 4'h D: begin - O_DATA <= r_ifr; - end - - 4'h E: begin - O_DATA <= {1'b 1, r_ier}; - end - - 4'h F: begin - O_DATA <= r_ira; - end - - default: - ; - - endcase - end - end -end - -// -// IO -// - -// if the shift register is enabled, cb1 may be an output -// in this case, we should listen to the CB1_OUT for the interrupt - -assign cb1_in_mux = (sr_cb1_oe_l === 1'b 1) ? I_CB1 : sr_cb1_out; - - -// ca1 control -assign ca1_int = (r_pcr[0] === 1'b 0) ? (ca1_ip_reg == 1'b1 & I_CA1 == 1'b0) : // negative edge - (ca1_ip_reg == 1'b0 & I_CA1 == 1'b1); // positive edge - - -// cb1 control -assign cb1_int = (r_pcr[4] === 1'b 0) ? (cb1_ip_reg == 1'b1 & cb1_in_mux == 1'b0) : // negative edge - (cb1_ip_reg == 1'b0 & cb1_in_mux == 1'b1); - - -assign ca2_int = (r_pcr[3] === 1'b 1) ? 1'b0 : - (r_pcr[2] === 1'b 1) ? (ca2_ip_reg == 1'b 0 & I_CA2 == 1'b 1): - (ca2_ip_reg == 1'b 1 & I_CA2 == 1'b 0); - -assign cb2_int = (r_pcr[7] === 1'b 1) ? 1'b0 : - (r_pcr[6] === 1'b 1) ? (cb2_ip_reg == 1'b 0 & I_CB2 == 1'b 1): - (cb2_ip_reg == 1'b 1 & I_CB2 == 1'b 0); - - -always @(posedge CLK) begin - - if (RESET_L === 1'b 0) begin - O_CA2 <= 1'b 0; - O_CA2_OE_L <= 1'b 1; - O_CB2 <= 1'b 0; - O_CB2_OE_L <= 1'b 1; - ca_hs_sr <= 1'b 0; - ca_hs_pulse <= 1'b 0; - cb_hs_sr <= 1'b 0; - cb_hs_pulse <= 1'b 0; - end - else begin - if (ENA_4 === 1'b 1) begin - - // ca - if (phase === 2'b 00 & (w_ora_hs === 1'b 1 | - r_ira_hs === 1'b 1)) begin - ca_hs_sr <= 1'b 1; - end - else if (ca1_int ) begin - ca_hs_sr <= 1'b 0; - end - - if (phase === 2'b 00) begin - ca_hs_pulse <= w_ora_hs | r_ira_hs; - end - - O_CA2_OE_L <= ~r_pcr[3]; - // ca2 output - case (r_pcr[3:1]) - 3'b 000: begin - O_CA2 <= 1'b 0; - // input - end - - 3'b 001: begin - O_CA2 <= 1'b 0; - // input - end - - 3'b 010: begin - O_CA2 <= 1'b 0; - // input - end - - 3'b 011: begin - O_CA2 <= 1'b 0; - // input - end - - 3'b 100: begin - O_CA2 <= ~ca_hs_sr; - // handshake - end - - 3'b 101: begin - O_CA2 <= ~ca_hs_pulse; - // pulse - end - - 3'b 110: begin - O_CA2 <= 1'b 0; - // low - end - - 3'b 111: begin - O_CA2 <= 1'b 1; - // high - end - - default: - ; - - endcase - if (phase === 2'b 00 & w_orb_hs === 1'b 1) begin - cb_hs_sr <= 1'b 1; - // cb - end - else if (cb1_int ) begin - cb_hs_sr <= 1'b 0; - end - - if (phase === 2'b 00) begin - cb_hs_pulse <= w_orb_hs; - end - - O_CB2_OE_L <= ~(r_pcr[7] | sr_drive_cb2); - // cb2 output or serial - if (sr_drive_cb2 === 1'b 1) begin - - // serial output - O_CB2 <= sr_out; - end - else begin - case (r_pcr[7:5]) - 3'b 000: begin - O_CB2 <= 1'b 0; - // input - end - - 3'b 001: begin - O_CB2 <= 1'b 0; - // input - end - - 3'b 010: begin - O_CB2 <= 1'b 0; - // input - end - - 3'b 011: begin - O_CB2 <= 1'b 0; - // input - end - - 3'b 100: begin - O_CB2 <= ~cb_hs_sr; - // handshake - end - - 3'b 101: begin - O_CB2 <= ~cb_hs_pulse; - // pulse - end - - 3'b 110: begin - O_CB2 <= 1'b 0; - // low - end - - 3'b 111: begin - O_CB2 <= 1'b 1; - // high - end - - default: - ; - - endcase - end - end - end -end - -assign O_CB1 = sr_cb1_out; -assign O_CB1_OE_L = sr_cb1_oe_l; - -always @(posedge CLK) begin - - if (RESET_L === 1'b 0) begin - ca1_irq <= 1'b 0; - ca2_irq <= 1'b 0; - cb1_irq <= 1'b 0; - cb2_irq <= 1'b 0; - end - else begin - if (ENA_4 === 1'b 1) begin - - // not pretty - if (ca1_int) begin - ca1_irq <= 1'b 1; - end - else if (r_ira_hs === 1'b 1 | w_ora_hs === 1'b 1 | - clear_irq[1] === 1'b 1 ) begin - ca1_irq <= 1'b 0; - end - - if (ca2_int) begin - ca2_irq <= 1'b 1; - end - else begin - if ((r_ira_hs === 1'b 1 | w_ora_hs === 1'b 1) & - r_pcr[1] === 1'b 0 | clear_irq[0] === 1'b 1) begin - ca2_irq <= 1'b 0; - end - end - - if (cb1_int) begin - cb1_irq <= 1'b 1; - end - else if (r_irb_hs === 1'b 1 | w_orb_hs === 1'b 1 | - clear_irq[4] === 1'b 1 ) begin - cb1_irq <= 1'b 0; - end - - if (cb2_int) begin - cb2_irq <= 1'b 1; - end - else begin - if ((r_irb_hs === 1'b 1 | w_orb_hs === 1'b 1) & - r_pcr[5] === 1'b 0 | clear_irq[3] === 1'b 1) begin - cb2_irq <= 1'b 0; - end - end - end - end -end - - -always @(posedge CLK) begin - - if (RESET_L === 1'b 0) begin - ca1_ip_reg <= 1'b 0; - cb1_ip_reg <= 1'b 0; - ca2_ip_reg <= 1'b 0; - cb2_ip_reg <= 1'b 0; - r_ira <= 8'h 00; - r_irb <= 8'h 00; - end - else begin - if (ENA_4 === 1'b 1) begin - - // we have a fast clock, so we can have input registers - ca1_ip_reg <= I_CA1; - cb1_ip_reg <= cb1_in_mux; - ca2_ip_reg <= I_CA2; - cb2_ip_reg <= I_CB2; - - if (r_acr[0] === 1'b 0) begin - r_ira <= I_PA; - - // enable latching - end - else begin - if (ca1_int) begin - r_ira <= I_PA; - end - end - - if (r_acr[1] === 1'b 0) begin - r_irb <= I_PB; - - // enable latching - end - else begin - if (cb1_int) begin - r_irb <= I_PB; - end - end - end - end -end - -// data direction reg (ddr) 0 = input, 1 = output - -assign O_PA = r_ora; -assign O_PA_OE_L = ~r_ddra; - -assign O_PB_OE_L[6:0] = ~r_ddrb[6:0]; -// not clear if r_ddrb(7) must be 1 as well, an output if under t1 control -assign O_PB_OE_L[7] = (r_acr[7] === 1'b 1) ? 1'b 0 : ~r_ddrb[7]; - -assign O_PB[7:0] = r_orb[7:0]; - -// -// Timer 1 -// - -reg p_timer1_done_done; -always @(posedge CLK) begin - - if (ENA_4 === 1'b1) begin - p_timer1_done_done = t1c == 16'h 0000; - t1c_done <= p_timer1_done_done & phase == 2'b 11; - if (phase === 2'b 11) begin - t1_reload_counter <= p_timer1_done_done & r_acr[6] == 1'b1; - end - if (t1_load_counter ) begin - t1c_done <= 1'b0; - end - end -end - - -always @(posedge CLK) begin - - if (ENA_4 === 1'b 1) begin - if (t1_load_counter | t1_reload_counter & phase === 2'b 11) begin - t1c[7:0] <= r_t1l_l; - t1c[15:8] <= r_t1l_h; - end - else if (phase === 2'b 11 ) begin - t1c <= t1c - 1'b 1; - end - - if (t1_load_counter | t1_reload_counter) begin - t1c_active <= 1'b1; - end - else if (t1c_done ) begin - t1c_active <= 1'b0; - end - - t1_toggle <= 1'b 0; - - if (t1c_active & t1c_done) begin - t1_toggle <= 1'b 1; - t1_irq <= 1'b 1; - end - else if (t1_w_reset_int | t1_r_reset_int | clear_irq[6] === 1'b 1 ) begin - t1_irq <= 1'b 0; - end - - if (t1_load_counter) begin // irq reset on load! - t1_irq <= 1'b 0; - end - end -end - -// -// Timer2 -// - -always @(posedge CLK) begin - - if (ENA_4 === 1'b 1) begin - if (phase === 2'b 01) begin - - // leading edge p2_h - t2_pb6 <= I_PB[6]; - t2_pb6_t1 <= t2_pb6; - end - end -end - -reg p_timer2_done_done; -always @(posedge CLK) begin - - if (ENA_4 === 1'b1) begin - p_timer2_done_done = t2c == 16'h 0000; - t2c_done <= p_timer2_done_done & phase == 2'b 11; - if (phase === 2'b 11) begin - t2_reload_counter <= p_timer2_done_done; - end - if (t2_load_counter ) begin // done reset on load! - t2c_done <= 1'b0; - end - end -end - - -always @(posedge CLK) begin - - if (ENA_4 === 1'b 1) begin - if (r_acr[5] === 1'b 0) begin - p_timer2_ena = 1'b1; - end - else begin - p_timer2_ena = t2_pb6_t1 == 1'b 1 & t2_pb6 == 1'b 0; - // falling edge - end - - if (t2_load_counter | t2_reload_counter & phase === 2'b 11) begin - - // not sure if t2c_reload should be here. Does timer2 just continue to - // count down, or is it reloaded ? Reloaded makes more sense if using - // it to generate a clock for the shift register. - t2c[7:0] <= r_t2l_l; - t2c[15:8] <= r_t2l_h; - end - else begin - if (phase === 2'b 11 & p_timer2_ena) begin - - // or count mode - t2c <= t2c - 1'b 1; - end - end - - t2_sr_ena <= t2c[7:0] == 8'h 00 & phase == 2'b 11; - - if (t2_load_counter) begin - t2c_active <= 1'b1; - end - else if (t2c_done ) begin - t2c_active <= 1'b0; - end - - if (t2c_active & t2c_done) begin - t2_irq <= 1'b 1; - end - else if (t2_w_reset_int | t2_r_reset_int | clear_irq[5] === 1'b 1 ) begin - t2_irq <= 1'b 0; - end - - if (t2_load_counter) begin // irq reset on load! - t2_irq <= 1'b 0; - end - - end -end - -// -// Shift Register -// - -always @(posedge CLK) begin - - if (RESET_L === 1'b 0) begin - r_sr <= 8'h 00; - sr_drive_cb2 <= 1'b 0; - sr_cb1_oe_l <= 1'b 1; - sr_cb1_out <= 1'b 0; - sr_strobe <= 1'b 1; - sr_cnt <= 4'b 0000; - sr_irq <= 1'b 0; - sr_out <= 1'b 1; - sr_off_delay <= 1'b 0; - end - else begin - if (ENA_4 === 1'b 1) begin - - // decode mode - p_sr_dir_out = r_acr[4]; - // output on cb2 - p_sr_cb1_op = 1'b 0; - p_sr_cb1_ip = 1'b 0; - p_sr_use_t2 = 1'b 0; - p_sr_free_run = 1'b 0; - - case (r_acr[4:2]) - 3'b 000: begin - p_sr_ena = 1'b 0; - p_sr_cb1_ip = 1'b 1; - end - - 3'b 001: begin - p_sr_ena = 1'b 1; - p_sr_cb1_op = 1'b 1; - p_sr_use_t2 = 1'b 1; - end - - 3'b 010: begin - p_sr_ena = 1'b 1; - p_sr_cb1_op = 1'b 1; - end - - 3'b 011: begin - p_sr_ena = 1'b 1; - p_sr_cb1_ip = 1'b 1; - end - - 3'b 100: begin - p_sr_ena = 1'b 1; - p_sr_use_t2 = 1'b 1; - p_sr_free_run = 1'b 1; - end - - 3'b 101: begin - p_sr_ena = 1'b 1; - p_sr_cb1_op = 1'b 1; - p_sr_use_t2 = 1'b 1; - end - - 3'b 110: begin - p_sr_ena = 1'b 1; - end - - 3'b 111: begin - p_sr_ena = 1'b 1; - p_sr_cb1_ip = 1'b 1; - end - - default: - ; - - endcase - if (p_sr_cb1_ip === 1'b 1) begin - sr_strobe <= I_CB1; - // clock select - // SR still runs even in disabled mode (on rising edge of CB1). It - // just doesn't generate any interrupts. - // Ref BBC micro advanced user guide p409 - end - else begin - if (sr_cnt[3] === 1'b 0 & p_sr_free_run === 1'b 0) begin - sr_strobe <= 1'b 1; - end - else begin - if (p_sr_use_t2 === 1'b 1 & t2_sr_ena | p_sr_use_t2 === - 1'b 0 & phase === 2'b 00) begin - sr_strobe <= ~sr_strobe; - end - end - end - - // latch on rising edge, shift on falling edge - if (sr_write_ena) begin - r_sr <= load_data; - end - else begin - if (p_sr_dir_out === 1'b 0) begin - - // input - if (sr_cnt[3] === 1'b 1 | p_sr_cb1_ip === 1'b 1) begin - if (sr_strobe_rising) begin - r_sr[0] <= I_CB2; - end - else if (sr_strobe_falling) begin - r_sr[7:1] <= r_sr[6:0]; - end - end - - sr_out <= 1'b 1; - - // output - end - else begin - if (sr_cnt[3] === 1'b 1 | sr_off_delay === 1'b 1 | - p_sr_cb1_ip === 1'b 1 | p_sr_free_run === 1'b 1) begin - if (sr_strobe_falling) begin - r_sr[7:1] <= r_sr[6:0]; - r_sr[0] <= r_sr[7]; - sr_out <= r_sr[7]; - end - end - else begin - sr_out <= 1'b 1; - end - end - end - - p_sr_sr_count_ena = sr_strobe_rising; - - // DMB: reseting sr_count when not enabled cause the sr to - // start running immediately it was enabled, which is incorrect - // and broke the latest SmartSPI ROM on the BBC Micro - if (p_sr_ena & (sr_write_ena | sr_read_ena)) begin - - // some documentation says sr bit in IFR must be set as well ? - sr_cnt <= 4'b 1000; - end - else if (p_sr_sr_count_ena & sr_cnt[3] === 1'b 1 ) begin - sr_cnt <= sr_cnt + 1'b 1; - end - - if (phase === 2'b 00) begin - sr_off_delay <= sr_cnt[3]; - // give some hold time when shifting out - end - - if (p_sr_sr_count_ena & sr_cnt === 4'b 1111 & p_sr_ena === - 1'b 1 & p_sr_free_run === 1'b 0) begin - sr_irq <= 1'b 1; - end - else if (sr_write_ena | sr_read_ena | clear_irq[2] === 1'b 1 ) begin - sr_irq <= 1'b 0; - end - - // assign ops - sr_drive_cb2 <= p_sr_dir_out; - sr_cb1_oe_l <= ~p_sr_cb1_op; - sr_cb1_out <= sr_strobe; - end - end -end - - -always @(posedge CLK) begin - - if (ENA_4 === 1'b 1) begin - sr_strobe_t1 <= sr_strobe; - sr_strobe_rising <= sr_strobe_t1 == 1'b 0 & sr_strobe == 1'b 1; - sr_strobe_falling <= sr_strobe_t1 == 1'b 1 & sr_strobe == 1'b 0; - end -end - -// -// Interrupts -// - -always @(posedge CLK) begin - - if (RESET_L === 1'b 0) begin - r_ier <= 7'b 0000000; - end - else begin - if (ENA_4 === 1'b 1) begin - if (ier_write_ena) begin - if (load_data[7] === 1'b 1) begin - - // set - r_ier <= r_ier | load_data[6:0]; - - // clear - end - else begin - r_ier <= r_ier & ~load_data[6:0]; - end - end - end - end -end - -assign O_IRQ_L = ~final_irq; -assign r_ifr = {final_irq, t1_irq, t2_irq, cb1_irq, cb2_irq, sr_irq, ca1_irq, ca2_irq}; - -always @(posedge CLK) begin - - if (RESET_L === 1'b 0) begin - final_irq <= 1'b 0; - end - else begin - if (ENA_4 === 1'b 1) begin - if ((r_ifr[6:0] & r_ier[6:0]) === 7'b 0000000) begin - final_irq <= 1'b 0; - // no interrupts - end - else begin - final_irq <= 1'b 1; - end - end - end -end - - -assign clear_irq = ifr_write_ena ? load_data : 8'h00; - -endmodule // module M6522 - diff --git a/cores/bbc/rtl/m6522.vhd b/cores/bbc/rtl/m6522.vhd new file mode 100644 index 0000000..87fee00 --- /dev/null +++ b/cores/bbc/rtl/m6522.vhd @@ -0,0 +1,1015 @@ +-- +-- A simulation model of VIC20 hardware - VIA implementation +-- Copyright (c) MikeJ - March 2003 +-- +-- 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 CODE 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. +-- +-- You are responsible for any legal issues arising from your use of this code. +-- +-- The latest version of this file can be found at: www.fpgaarcade.com +-- +-- Email vic20@fpgaarcade.com +-- +-- +-- Revision list +-- +-- dmb: ier bit 7 should read back as '1' +-- dmb: Fixes to sr_do_shift change that broke MMFS on the Beeb (SR mode 0) +-- version 005 Many fixes to all areas, VIA now passes all VICE tests +-- version 004 fixes to PB7 T1 control and Mode 0 Shift Register operation +-- version 003 fix reset of T1/T2 IFR flags if T1/T2 is reload via reg5/reg9 from wolfgang (WoS) +-- Ported to numeric_std and simulation fix for signal initializations from arnim laeuger +-- version 002 fix from Mark McDougall, untested +-- version 001 initial release +-- not very sure about the shift register, documentation is a bit light. + +library ieee ; + use ieee.std_logic_1164.all; + use ieee.numeric_std.all; + +entity M6522 is + port ( + I_RS : in std_logic_vector(3 downto 0); + I_DATA : in std_logic_vector(7 downto 0); + O_DATA : out std_logic_vector(7 downto 0); + O_DATA_OE_L : out std_logic; + + I_RW_L : in std_logic; + I_CS1 : in std_logic; + I_CS2_L : in std_logic; + + O_IRQ_L : out std_logic; -- note, not open drain + + -- port a + I_CA1 : in std_logic; + I_CA2 : in std_logic; + O_CA2 : out std_logic; + O_CA2_OE_L : out std_logic; + + I_PA : in std_logic_vector(7 downto 0); + O_PA : out std_logic_vector(7 downto 0); + O_PA_OE_L : out std_logic_vector(7 downto 0); + + -- port b + I_CB1 : in std_logic; + O_CB1 : out std_logic; + O_CB1_OE_L : out std_logic; + + I_CB2 : in std_logic; + O_CB2 : out std_logic; + O_CB2_OE_L : out std_logic; + + I_PB : in std_logic_vector(7 downto 0); + O_PB : out std_logic_vector(7 downto 0); + O_PB_OE_L : out std_logic_vector(7 downto 0); + + I_P2_H : in std_logic; -- high for phase 2 clock ____----__ + RESET_L : in std_logic; + ENA_4 : in std_logic; -- clk enable + CLK : in std_logic + ); +end; + +architecture RTL of M6522 is + + signal phase : std_logic_vector(1 downto 0):="00"; + signal p2_h_t1 : std_logic; + signal cs : std_logic; + + -- registers + signal r_ddra : std_logic_vector(7 downto 0); + signal r_ora : std_logic_vector(7 downto 0); + signal r_ira : std_logic_vector(7 downto 0); + + signal r_ddrb : std_logic_vector(7 downto 0); + signal r_orb : std_logic_vector(7 downto 0); + signal r_irb : std_logic_vector(7 downto 0); + + signal r_t1l_l : std_logic_vector(7 downto 0); + signal r_t1l_h : std_logic_vector(7 downto 0); + signal r_t2l_l : std_logic_vector(7 downto 0); + signal r_t2l_h : std_logic_vector(7 downto 0); -- not in real chip + signal r_sr : std_logic_vector(7 downto 0); + signal r_acr : std_logic_vector(7 downto 0); + signal r_pcr : std_logic_vector(7 downto 0); + signal r_ifr : std_logic_vector(7 downto 0); + signal r_ier : std_logic_vector(6 downto 0); + + signal sr_write_ena : boolean; + signal sr_read_ena : boolean; + signal ifr_write_ena : boolean; + signal ier_write_ena : boolean; + signal clear_irq : std_logic_vector(7 downto 0); + signal load_data : std_logic_vector(7 downto 0); + + -- timer 1 + signal t1c : std_logic_vector(15 downto 0) := (others => '1'); -- simulators may not catch up w/o init here... + signal t1c_active : boolean; + signal t1c_done : boolean; + signal t1_w_reset_int : boolean; + signal t1_r_reset_int : boolean; + signal t1_load_counter : boolean; + signal t1_reload_counter : boolean; + signal t1_int_enable : boolean := false; + signal t1_toggle : std_logic; + signal t1_irq : std_logic := '0'; + signal t1_pb7 : std_logic := '1'; + signal t1_pb7_en_c : std_logic; + signal t1_pb7_en_d : std_logic; + + -- timer 2 + signal t2c : std_logic_vector(15 downto 0) := (others => '1'); -- simulators may not catch up w/o init here... + signal t2c_active : boolean; + signal t2c_done : boolean; + signal t2_pb6 : std_logic; + signal t2_pb6_t1 : std_logic; + signal t2_cnt_clk : std_logic := '1'; + signal t2_w_reset_int : boolean; + signal t2_r_reset_int : boolean; + signal t2_load_counter : boolean; + signal t2_reload_counter : boolean; + signal t2_int_enable : boolean := false; + signal t2_irq : std_logic := '0'; + signal t2_sr_ena : boolean; + + -- shift reg + signal sr_cnt : std_logic_vector(3 downto 0); + signal sr_cb1_oe_l : std_logic; + signal sr_cb1_out : std_logic; + signal sr_drive_cb2 : std_logic; + signal sr_strobe : std_logic; + signal sr_do_shift : boolean := false; + signal sr_strobe_t1 : std_logic; + signal sr_strobe_falling : boolean; + signal sr_strobe_rising : boolean; + signal sr_irq : std_logic; + signal sr_out : std_logic; + signal sr_active : boolean; + + -- io + signal w_orb_hs : std_logic; + signal w_ora_hs : std_logic; + signal r_irb_hs : std_logic; + signal r_ira_hs : std_logic; + + signal ca_hs_sr : std_logic; + signal ca_hs_pulse : std_logic; + signal cb_hs_sr : std_logic; + signal cb_hs_pulse : std_logic; + + signal cb1_in_mux : std_logic; + signal ca1_ip_reg_c : std_logic; + signal ca1_ip_reg_d : std_logic; + signal cb1_ip_reg_c : std_logic; + signal cb1_ip_reg_d : std_logic; + signal ca1_int : boolean; + signal cb1_int : boolean; + signal ca1_irq : std_logic; + signal cb1_irq : std_logic; + + signal ca2_ip_reg_c : std_logic; + signal ca2_ip_reg_d : std_logic; + signal cb2_ip_reg_c : std_logic; + signal cb2_ip_reg_d : std_logic; + signal ca2_int : boolean; + signal cb2_int : boolean; + signal ca2_irq : std_logic; + signal cb2_irq : std_logic; + + signal final_irq : std_logic; +begin + + p_phase : process + begin + -- internal clock phase + wait until rising_edge(CLK); + if (ENA_4 = '1') then + p2_h_t1 <= I_P2_H; + if (p2_h_t1 = '0') and (I_P2_H = '1') then + phase <= "11"; + else + phase <= std_logic_vector(unsigned(phase) + 1); + end if; + end if; + end process; + + p_cs : process(I_CS1, I_CS2_L, I_P2_H) + begin + cs <= '0'; + if (I_CS1 = '1') and (I_CS2_L = '0') and (I_P2_H = '1') then + cs <= '1'; + end if; + end process; + + -- peripheral control reg (pcr) + -- 0 ca1 interrupt control (0 +ve edge, 1 -ve edge) + -- 3..1 ca2 operation + -- 000 input -ve edge + -- 001 independend interrupt input -ve edge + -- 010 input +ve edge + -- 011 independend interrupt input +ve edge + -- 100 handshake output + -- 101 pulse output + -- 110 low output + -- 111 high output + -- 7..4 as 3..0 for cb1,cb2 + + -- auxiliary control reg (acr) + -- 0 input latch PA (0 disable, 1 enable) + -- 1 input latch PB (0 disable, 1 enable) + -- 4..2 shift reg control + -- 000 disable + -- 001 shift in using t2 + -- 010 shift in using o2 + -- 011 shift in using ext clk + -- 100 shift out free running t2 rate + -- 101 shift out using t2 + -- 101 shift out using o2 + -- 101 shift out using ext clk + -- 5 t2 timer control (0 timed interrupt, 1 count down with pulses on pb6) + -- 7..6 t1 timer control + -- 00 timed interrupt each time t1 is loaded pb7 disable + -- 01 continuous interrupts pb7 disable + -- 00 timed interrupt each time t1 is loaded pb7 one shot output + -- 01 continuous interrupts pb7 square wave output + -- + + p_write_reg_reset : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + r_ora <= x"00"; r_orb <= x"00"; + r_ddra <= x"00"; r_ddrb <= x"00"; + r_acr <= x"00"; r_pcr <= x"00"; + + w_orb_hs <= '0'; + w_ora_hs <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + w_orb_hs <= '0'; + w_ora_hs <= '0'; + if (cs = '1') and (I_RW_L = '0') then + case I_RS is + when x"0" => r_orb <= I_DATA; w_orb_hs <= '1'; + when x"1" => r_ora <= I_DATA; w_ora_hs <= '1'; + when x"2" => r_ddrb <= I_DATA; + when x"3" => r_ddra <= I_DATA; + + when x"B" => r_acr <= I_DATA; + when x"C" => r_pcr <= I_DATA; + when x"F" => r_ora <= I_DATA; + + when others => null; + end case; + end if; + + -- Set timer PB7 state, only on rising edge of setting ACR(7) + if ((t1_pb7_en_d = '0') and (t1_pb7_en_c = '1')) then + t1_pb7 <= '1'; + end if; + + if t1_load_counter then + t1_pb7 <= '0'; -- Reset internal timer 1 PB7 state on every timer load + elsif t1_toggle = '1' then + t1_pb7 <= not t1_pb7; + end if; + end if; + end if; + end process; + + p_write_reg : process (RESET_L, CLK) is + begin + if (RESET_L = '0') then + -- The spec says, this is not reset. + -- Fact is that the 1541 VIA1 timer won't work, + -- as the firmware ONLY sets the r_t1l_h latch!!!! + r_t1l_l <= (others => '1'); -- All latches default to FFFF + r_t1l_h <= (others => '1'); + r_t2l_l <= (others => '1'); + r_t2l_h <= (others => '1'); + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + t1_w_reset_int <= false; + t1_load_counter <= false; + + t2_w_reset_int <= false; + t2_load_counter <= false; + + load_data <= x"00"; + sr_write_ena <= false; + ifr_write_ena <= false; + ier_write_ena <= false; + + if (cs = '1') and (I_RW_L = '0') then + load_data <= I_DATA; + case I_RS is + when x"4" => r_t1l_l <= I_DATA; + when x"5" => r_t1l_h <= I_DATA; t1_w_reset_int <= true; + t1_load_counter <= true; + + when x"6" => r_t1l_l <= I_DATA; + when x"7" => r_t1l_h <= I_DATA; t1_w_reset_int <= true; + + when x"8" => r_t2l_l <= I_DATA; + when x"9" => r_t2l_h <= I_DATA; t2_w_reset_int <= true; + t2_load_counter <= true; + + when x"A" => sr_write_ena <= true; + when x"D" => ifr_write_ena <= true; + when x"E" => ier_write_ena <= true; + + when others => null; + end case; + end if; + end if; + end if; + end process; + + p_oe : process(cs, I_RW_L) + begin + O_DATA_OE_L <= '1'; + if (cs = '1') and (I_RW_L = '1') then + O_DATA_OE_L <= '0'; + end if; + end process; + + p_read : process(cs, I_RW_L, I_RS, r_irb, r_ira, r_ddrb, r_ddra, t1c, r_t1l_l, + r_t1l_h, t2c, r_sr, r_acr, r_pcr, r_ifr, r_ier, r_ora, r_orb, t1_pb7_en_d, t1_pb7) + variable orb : std_logic_vector(7 downto 0); + begin + t1_r_reset_int <= false; + t2_r_reset_int <= false; + sr_read_ena <= false; + r_irb_hs <= '0'; + r_ira_hs <= '0'; + O_DATA <= x"00"; -- default + orb := (r_irb and not r_ddrb) or (r_orb and r_ddrb); + + -- If PB7 under timer control, assign value from timer + if (t1_pb7_en_d = '1') then + orb(7) := t1_pb7; + end if; + + if (cs = '1') and (I_RW_L = '1') then + case I_RS is + when x"0" => O_DATA <= orb; r_irb_hs <= '1'; + when x"1" => O_DATA <= (r_ira and not r_ddra) or (r_ora and r_ddra); r_ira_hs <= '1'; + when x"2" => O_DATA <= r_ddrb; + when x"3" => O_DATA <= r_ddra; + when x"4" => O_DATA <= t1c( 7 downto 0); t1_r_reset_int <= true; + when x"5" => O_DATA <= t1c(15 downto 8); + when x"6" => O_DATA <= r_t1l_l; + when x"7" => O_DATA <= r_t1l_h; + when x"8" => O_DATA <= t2c( 7 downto 0); t2_r_reset_int <= true; + when x"9" => O_DATA <= t2c(15 downto 8); + when x"A" => O_DATA <= r_sr; sr_read_ena <= true; + when x"B" => O_DATA <= r_acr; + when x"C" => O_DATA <= r_pcr; + when x"D" => O_DATA <= r_ifr; + -- DMB: ier bit 7 should read back as '1' + when x"E" => O_DATA <= ('1' & r_ier); + when x"F" => O_DATA <= r_ira; + when others => null; + end case; + end if; + + end process; + + -- + -- IO + -- + + p_ca1_cb1_sel : process(sr_cb1_oe_l, sr_cb1_out, I_CB1) + begin + -- if the shift register is enabled, cb1 may be an output + -- in this case we should NOT listen to the input as + -- CB1 interrupts are not generated by the shift register + if (sr_cb1_oe_l = '1') then + cb1_in_mux <= I_CB1; + else + cb1_in_mux <= '1'; + end if; + end process; + + p_ca1_cb1_int : process(r_pcr, ca1_ip_reg_c, ca1_ip_reg_d, cb1_ip_reg_c, cb1_ip_reg_d) + begin + if (r_pcr(0) = '0') then -- ca1 control + -- negative edge + ca1_int <= (ca1_ip_reg_d = '1') and (ca1_ip_reg_c = '0'); + else + -- positive edge + ca1_int <= (ca1_ip_reg_d = '0') and (ca1_ip_reg_c = '1'); + end if; + + if (r_pcr(4) = '0') then -- cb1 control + -- negative edge + cb1_int <= (cb1_ip_reg_d = '1') and (cb1_ip_reg_c = '0'); + else + -- positive edge + cb1_int <= (cb1_ip_reg_d = '0') and (cb1_ip_reg_c = '1'); + end if; + end process; + + p_ca2_cb2_int : process(r_pcr, ca2_ip_reg_c, ca2_ip_reg_d, cb2_ip_reg_c, cb2_ip_reg_d) + begin + ca2_int <= false; + if (r_pcr(3) = '0') then -- ca2 input + if (r_pcr(2) = '0') then -- ca2 edge + -- negative edge + ca2_int <= (ca2_ip_reg_d = '1') and (ca2_ip_reg_c = '0'); + else + -- positive edge + ca2_int <= (ca2_ip_reg_d = '0') and (ca2_ip_reg_c = '1'); + end if; + end if; + + cb2_int <= false; + if (r_pcr(7) = '0') then -- cb2 input + if (r_pcr(6) = '0') then -- cb2 edge + -- negative edge + cb2_int <= (cb2_ip_reg_d = '1') and (cb2_ip_reg_c = '0'); + else + -- positive edge + cb2_int <= (cb2_ip_reg_d = '0') and (cb2_ip_reg_c = '1'); + end if; + end if; + end process; + + p_ca2_cb2 : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + O_CA2 <= '1'; -- Pullup is default + O_CA2_OE_L <= '1'; + O_CB2 <= '1'; -- Pullup is default + O_CB2_OE_L <= '1'; + + ca_hs_sr <= '0'; + ca_hs_pulse <= '0'; + cb_hs_sr <= '0'; + cb_hs_pulse <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + -- ca + if (phase = "00") and ((w_ora_hs = '1') or (r_ira_hs = '1')) then + ca_hs_sr <= '1'; + elsif ca1_int then + ca_hs_sr <= '0'; + end if; + + if (phase = "00") then + ca_hs_pulse <= w_ora_hs or r_ira_hs; + end if; + + O_CA2_OE_L <= not r_pcr(3); -- ca2 output + case r_pcr(3 downto 1) is + when "000" => O_CA2 <= I_CA2; -- input, output follows input + when "001" => O_CA2 <= I_CA2; -- input, output follows input + when "010" => O_CA2 <= I_CA2; -- input, output follows input + when "011" => O_CA2 <= I_CA2; -- input, output follows input + when "100" => O_CA2 <= not (ca_hs_sr); -- handshake + when "101" => O_CA2 <= not (ca_hs_pulse); -- pulse + when "110" => O_CA2 <= '0'; -- low + when "111" => O_CA2 <= '1'; -- high + when others => null; + end case; + + -- cb + if (phase = "00") and (w_orb_hs = '1') then + cb_hs_sr <= '1'; + elsif cb1_int then + cb_hs_sr <= '0'; + end if; + + if (phase = "00") then + cb_hs_pulse <= w_orb_hs; + end if; + + O_CB2_OE_L <= not (r_pcr(7) or sr_drive_cb2); -- cb2 output or serial + if (sr_drive_cb2 = '1') then -- serial output + O_CB2 <= sr_out; + else + case r_pcr(7 downto 5) is + when "000" => O_CB2 <= I_CB2; -- input, output follows input + when "001" => O_CB2 <= I_CB2; -- input, output follows input + when "010" => O_CB2 <= I_CB2; -- input, output follows input + when "011" => O_CB2 <= I_CB2; -- input, output follows input + when "100" => O_CB2 <= not (cb_hs_sr); -- handshake + when "101" => O_CB2 <= not (cb_hs_pulse); -- pulse + when "110" => O_CB2 <= '0'; -- low + when "111" => O_CB2 <= '1'; -- high + when others => null; + end case; + end if; + end if; + end if; + end process; + + O_CB1 <= sr_cb1_out; + O_CB1_OE_L <= sr_cb1_oe_l; + + p_ca_cb_irq : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + ca1_irq <= '0'; + ca2_irq <= '0'; + cb1_irq <= '0'; + cb2_irq <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + -- not pretty + if ca1_int then + ca1_irq <= '1'; + elsif (r_ira_hs = '1') or (w_ora_hs = '1') or (clear_irq(1) = '1') then + ca1_irq <= '0'; + end if; + + if ca2_int then + ca2_irq <= '1'; + else + if (((r_ira_hs = '1') or (w_ora_hs = '1')) and (r_pcr(1) = '0')) or + (clear_irq(0) = '1') then + ca2_irq <= '0'; + end if; + end if; + + if cb1_int then + cb1_irq <= '1'; + elsif (r_irb_hs = '1') or (w_orb_hs = '1') or (clear_irq(4) = '1') then + cb1_irq <= '0'; + end if; + + if cb2_int then + cb2_irq <= '1'; + else + if (((r_irb_hs = '1') or (w_orb_hs = '1')) and (r_pcr(5) = '0')) or + (clear_irq(3) = '1') then + cb2_irq <= '0'; + end if; + end if; + end if; + end if; + end process; + + p_input_reg : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + ca1_ip_reg_c <= '0'; + ca1_ip_reg_d <= '0'; + + cb1_ip_reg_c <= '0'; + cb1_ip_reg_d <= '0'; + + ca2_ip_reg_c <= '0'; + ca2_ip_reg_d <= '0'; + + cb2_ip_reg_c <= '0'; + cb2_ip_reg_d <= '0'; + + r_ira <= x"00"; + r_irb <= x"00"; + + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + -- we have a fast clock, so we can have input registers + ca1_ip_reg_c <= I_CA1; + ca1_ip_reg_d <= ca1_ip_reg_c; + + cb1_ip_reg_c <= cb1_in_mux; + cb1_ip_reg_d <= cb1_ip_reg_c; + + ca2_ip_reg_c <= I_CA2; + ca2_ip_reg_d <= ca2_ip_reg_c; + + cb2_ip_reg_c <= I_CB2; + cb2_ip_reg_d <= cb2_ip_reg_c; + + if (r_acr(0) = '0') then + r_ira <= I_PA; + else -- enable latching + if ca1_int then + r_ira <= I_PA; + end if; + end if; + + if (r_acr(1) = '0') then + r_irb <= I_PB; + else -- enable latching + if cb1_int then + r_irb <= I_PB; + end if; + end if; + end if; + end if; + end process; + + p_buffers : process(r_ddra, r_ora, r_ddrb, r_acr, r_orb, t1_pb7_en_d, t1_pb7) + begin + -- data direction reg (ddr) 0 = input, 1 = output + O_PA <= r_ora; + O_PA_OE_L <= not r_ddra; + + -- If PB7 is timer driven output set PB7 to the timer state, otherwise use value in ORB register + if (t1_pb7_en_d = '1') then + O_PB <= t1_pb7 & r_orb(6 downto 0); + else + O_PB <= r_orb; + end if; + + -- NOTE: r_ddrb(7) must be set to enable T1 output on PB7 - [various datasheets specify this] + O_PB_OE_L <= not r_ddrb; + end process; + + -- + -- Timer 1 + -- + + -- Detect change in r_acr(7), timer 1 mode for PB7 + p_pb7_enable : process + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + t1_pb7_en_c <= r_acr(7); + t1_pb7_en_d <= t1_pb7_en_c; + end if; + end process; + + p_timer1_done : process + variable done : boolean; + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + done := (t1c = x"0000"); + t1c_done <= done and (phase = "11"); + if (phase = "11") and not t1_load_counter then -- Don't set reload if T1L-H written + t1_reload_counter <= done; + elsif t1_load_counter then -- Cancel a reload when T1L-H written + t1_reload_counter <= false; + end if; + if t1_load_counter then -- done reset on load! + t1c_done <= false; + end if; + end if; + end process; + + p_timer1 : process + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + if t1_load_counter or (t1_reload_counter and phase = "11") then + t1c( 7 downto 0) <= r_t1l_l; + t1c(15 downto 8) <= r_t1l_h; + -- There is a need to write to Latch HI to enable interrupts for both continuous and one-shot modes + if t1_load_counter then + t1_int_enable <= true; + end if; + elsif (phase="11") then + t1c <= std_logic_vector(unsigned(t1c) - 1); + end if; + + if t1_load_counter or t1_reload_counter then + t1c_active <= true; + elsif t1c_done then + t1c_active <= false; + end if; + + t1_toggle <= '0'; + if t1c_active and t1c_done then + if t1_int_enable then -- Set interrupt only if T1L-H has been written + t1_toggle <= '1'; + t1_irq <= '1'; + if (r_acr(6) = '0') then -- Disable further interrupts if in one shot mode + t1_int_enable <= false; + end if; + end if; + elsif t1_w_reset_int or t1_r_reset_int or (clear_irq(6) = '1') then + t1_irq <= '0'; + end if; + if t1_load_counter then -- irq reset on load! + t1_irq <= '0'; + end if; + end if; + end process; + + -- + -- Timer2 + -- + + p_timer2_pb6_input : process + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + if (phase = "01") then -- leading edge p2_h + t2_pb6 <= I_PB(6); + t2_pb6_t1 <= t2_pb6; + end if; + end if; + end process; + + -- Ensure we don't start counting until the P2 clock after r_acr is changed + p_timer2_ena : process + begin + wait until rising_edge(I_P2_H); + if r_acr(5) = '0' then + t2_cnt_clk <= '1'; + else + t2_cnt_clk <= '0'; + end if; + end process; + + p_timer2_done : process + variable done : boolean; + variable done_sr : boolean; + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + done := (t2c = x"0000"); -- Normal timer expires at 0000 + done_sr := (t2c(7 downto 0) = x"00"); -- Shift register expires on low byte = 00 + t2c_done <= done and (phase = "11"); + if (phase = "11") then + t2_reload_counter <= done_sr; -- Timer 2 is only reloaded when used for the shift register + end if; + if t2_load_counter then -- done reset on load! + t2c_done <= false; + end if; + end if; + end process; + + p_timer2 : process + variable ena : boolean; + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + if (t2_cnt_clk ='1') then + ena := true; + t2c_active <= true; + t2_int_enable <= true; + else + ena := (t2_pb6_t1 = '1') and (t2_pb6 = '0'); -- falling edge + end if; + + -- Shift register reload is only active when shift register mode using T2 is enabled + if t2_reload_counter and (phase="11") and ((r_acr(4 downto 2) = "001") or (r_acr(4 downto 2) = "100") or (r_acr(4 downto 2) = "101")) then + t2c(7 downto 0) <= r_t2l_l; -- For shift register only low latch is loaded! + elsif t2_load_counter then + t2_int_enable <= true; + t2c( 7 downto 0) <= r_t2l_l; + t2c(15 downto 8) <= r_t2l_h; + else + if (phase="11") and ena then -- or count mode + t2c <= std_logic_vector(unsigned(t2c) - 1); + end if; + end if; + + -- Shift register strobe on T2 occurs one P2H clock after timer expires + -- so enable the strobe when we roll over to FF + t2_sr_ena <= (t2c(7 downto 0) = x"FF") and (phase = "11"); + + if t2_load_counter then + t2c_active <= true; + elsif t2c_done then + t2c_active <= false; + end if; + + if t2c_active and t2c_done and t2_int_enable then + t2_int_enable <= false; + t2_irq <= '1'; + elsif t2_w_reset_int or t2_r_reset_int or (clear_irq(5) = '1') then + t2_irq <= '0'; + end if; + if t2_load_counter then -- irq reset on load! + t2_irq <= '0'; + end if; + end if; + end process; + + -- + -- Shift Register + -- + + p_sr : process(RESET_L, CLK) + variable dir_out : std_logic; + variable ena : std_logic; + variable cb1_op : std_logic; + variable cb1_ip : std_logic; + variable use_t2 : std_logic; + variable free_run : std_logic; + variable sr_count_ena : boolean; + begin + if (RESET_L = '0') then + r_sr <= x"00"; + sr_drive_cb2 <= '0'; + sr_cb1_oe_l <= '1'; + sr_cb1_out <= '0'; + sr_do_shift <= false; + sr_strobe <= '1'; + sr_cnt <= "0000"; + sr_irq <= '0'; + sr_out <= '0'; + sr_active <= false; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + -- decode mode + dir_out := r_acr(4); -- output on cb2 + cb1_op := '0'; + cb1_ip := '0'; + use_t2 := '0'; + free_run := '0'; + + -- DMB: SR still runs even in disabled mode (on rising edge of CB1). + -- It just doesn't generate any interrupts. + -- Ref BBC micro advanced user guide p409 + + case r_acr(4 downto 2) is + -- DMB: in disabled mode, configure cb1 as an input + when "000" => ena := '0'; cb1_ip := '1'; -- 0x00 Mode 0 SR disabled + when "001" => ena := '1'; cb1_op := '1'; use_t2 := '1'; -- 0x04 Mode 1 Shift in under T2 control + when "010" => ena := '1'; cb1_op := '1'; -- 0x08 Mode 2 Shift in under P2 control + when "011" => ena := '1'; cb1_ip := '1'; -- 0x0C Mode 3 Shift in under control of ext clock + when "100" => ena := '1'; cb1_op := '1'; use_t2 := '1'; free_run := '1'; -- 0x10 Mode 4 Shift out free running under T2 control + when "101" => ena := '1'; cb1_op := '1'; use_t2 := '1'; -- 0x14 Mode 5 Shift out under T2 control + when "110" => ena := '1'; cb1_op := '1'; -- 0x18 Mode 6 Shift out under P2 control + when "111" => ena := '1'; cb1_ip := '1'; -- 0x1C Mode 7 Shift out under control of ext clock + when others => null; + end case; + + -- clock select + -- DMB: in disabled mode, strobe from cb1 + if (cb1_ip = '1') then + sr_strobe <= I_CB1; + else + if (sr_cnt(3) = '0') and (free_run = '0') then + sr_strobe <= '1'; + else + if ((use_t2 = '1') and t2_sr_ena) or + ((use_t2 = '0') and (phase = "00")) then + sr_strobe <= not sr_strobe; + end if; + end if; + end if; + + -- latch on rising edge, shift on falling edge of P2 + if sr_write_ena then + r_sr <= load_data; + sr_out <= r_sr(7); + + else + -- DMB: allow shifting in all modes + if (dir_out = '0') then + -- input + if (sr_cnt(3) = '1') or (cb1_ip = '1') then + if sr_strobe_rising then + sr_do_shift <= true; + r_sr(0) <= I_CB2; + -- DMB: Added sr_stroble_falling to avoid premature shift + -- (fixes issue with MMFS on the Beeb in SR mode 0) + elsif sr_do_shift and sr_strobe_falling then + sr_do_shift <= false; + r_sr(7 downto 1) <= r_sr(6 downto 0); + end if; + end if; + else + -- output + if (sr_cnt(3) = '1') or (cb1_ip = '1') or (free_run = '1') then + if sr_strobe_falling then + sr_out <= r_sr(7); + sr_do_shift <= true; + -- DMB: Added sr_stroble_falling to avoid premature shift + -- (fixes issue with MMFS on the Beeb in SR mode 0) + elsif sr_do_shift and sr_strobe_rising then + sr_do_shift <= false; + r_sr <= r_sr(6 downto 0) & r_sr(7); + end if; + end if; + end if; + end if; + + -- Set shift enabled flag, note does not get set for free_run mode ! + if (ena = '1') and (sr_cnt(3) = '1') then + sr_active <= true; + elsif (ena = '1') and (sr_cnt(3) = '0') and (phase="11") then + sr_active <= false; + end if; + + sr_count_ena := sr_strobe_rising; + + -- DMB: reseting sr_count when not enabled cause the sr to + -- start running immediately it was enabled, which is incorrect + -- and broke the latest SmartSPI ROM on the BBC Micro + if (ena = '1') and (sr_write_ena or sr_read_ena) and (not sr_active) then + -- some documentation says sr bit in IFR must be set as well ? + sr_cnt <= "1000"; + elsif sr_count_ena and (sr_cnt(3) = '1') then + sr_cnt <= std_logic_vector(unsigned(sr_cnt) + 1); + end if; + + if sr_count_ena and (sr_cnt = "1111") and (ena = '1') and (free_run = '0') then + sr_irq <= '1'; + elsif sr_write_ena or sr_read_ena or (clear_irq(2) = '1') then + sr_irq <= '0'; + end if; + + -- assign ops + sr_drive_cb2 <= dir_out; + sr_cb1_oe_l <= not cb1_op; + sr_cb1_out <= sr_strobe; + end if; + end if; + end process; + + p_sr_strobe_rise_fall : process + begin + wait until rising_edge(CLK); + if (ENA_4 = '1') then + sr_strobe_t1 <= sr_strobe; + sr_strobe_rising <= (sr_strobe_t1 = '0') and (sr_strobe = '1'); + sr_strobe_falling <= (sr_strobe_t1 = '1') and (sr_strobe = '0'); + end if; + end process; + + -- + -- Interrupts + -- + + p_ier : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + r_ier <= "0000000"; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + if ier_write_ena then + if (load_data(7) = '1') then + -- set + r_ier <= r_ier or load_data(6 downto 0); + else + -- clear + r_ier <= r_ier and not load_data(6 downto 0); + end if; + end if; + end if; + end if; + end process; + + p_ifr : process(t1_irq, t2_irq, final_irq, ca1_irq, ca2_irq, sr_irq, + cb1_irq, cb2_irq) + begin + r_ifr(7) <= final_irq; + r_ifr(6) <= t1_irq; + r_ifr(5) <= t2_irq; + r_ifr(4) <= cb1_irq; + r_ifr(3) <= cb2_irq; + r_ifr(2) <= sr_irq; + r_ifr(1) <= ca1_irq; + r_ifr(0) <= ca2_irq; + + O_IRQ_L <= not final_irq; + end process; + + p_irq : process(RESET_L, CLK) + begin + if (RESET_L = '0') then + final_irq <= '0'; + elsif rising_edge(CLK) then + if (ENA_4 = '1') then + if ((r_ifr(6 downto 0) and r_ier(6 downto 0)) = "0000000") then + final_irq <= '0'; -- no interrupts + else + final_irq <= '1'; + end if; + end if; + end if; + end process; + + p_clear_irq : process(ifr_write_ena, load_data) + begin + clear_irq <= x"00"; + if ifr_write_ena then + clear_irq <= load_data; + end if; + end process; + +end architecture RTL;