diff options
79 files changed, 31362 insertions, 0 deletions
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..623eb54 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "de1/fpga-bbc"] + path = de1/fpga-bbc + url = ssh://git@git.panaceas.org/git/bbc-b/fpga-bbc diff --git a/de1/docs/WM8731_v4.9.pdf b/de1/docs/WM8731_v4.9.pdf Binary files differnew file mode 100644 index 0000000..83d7028 --- /dev/null +++ b/de1/docs/WM8731_v4.9.pdf diff --git a/de1/fpga-bbc b/de1/fpga-bbc new file mode 160000 +Subproject c2e7e51a5affdc3d58d71534199b9770a362612 diff --git a/de1/fpga-bbc-pq/.gitignore b/de1/fpga-bbc-pq/.gitignore new file mode 100644 index 0000000..f5038c3 --- /dev/null +++ b/de1/fpga-bbc-pq/.gitignore @@ -0,0 +1,2 @@ +status +*~ diff --git a/de1/fpga-bbc-pq/master/audio-16bit-48k.patch b/de1/fpga-bbc-pq/master/audio-16bit-48k.patch new file mode 100644 index 0000000..315a9fd --- /dev/null +++ b/de1/fpga-bbc-pq/master/audio-16bit-48k.patch @@ -0,0 +1,186 @@ +diff --git a/bbc_micro_de1.vhd b/bbc_micro_de1.vhd +index 5cc666c..462e507 100644 +--- a/bbc_micro_de1.vhd ++++ b/bbc_micro_de1.vhd +@@ -437,7 +437,7 @@ component sn76489_top is + we_n_i : in std_logic; + ready_o : out std_logic; + d_i : in std_logic_vector(0 to 7); +- aout_o : out signed(0 to 7) ++ aout_o : out signed(0 to 15) + ); + + end component; +@@ -445,7 +445,7 @@ end component; + component i2s_intf is + generic( + mclk_rate : positive := 12000000; +- sample_rate : positive := 8000; ++ sample_rate : positive := 48000; + preamble : positive := 1; -- I2S + word_length : positive := 16 + ); +@@ -713,7 +713,7 @@ signal keyb_break : std_logic; + -- Sound generator + signal sound_ready : std_logic; + signal sound_di : std_logic_vector(7 downto 0); +-signal sound_ao : signed(7 downto 0); ++signal sound_ao : signed(15 downto 0); + signal pcm_inl : std_logic_vector(15 downto 0); + signal pcm_inr : std_logic_vector(15 downto 0); + +@@ -938,13 +938,13 @@ begin + clock, mhz4_clken, + reset_n, '0', sound_enable_n, + sound_ready, sound_di, +- sound_ao ++ sound_ao + ); + i2s : i2s_intf port map ( + CLOCK_24(0), reset_n, + pcm_inl, pcm_inr, +- std_logic_vector(sound_ao) & "00000000", +- std_logic_vector(sound_ao) & "00000000", ++ std_logic_vector(sound_ao), ++ std_logic_vector(sound_ao), + AUD_XCK, AUD_DACLRCK, + AUD_BCLK, AUD_DACDAT, AUD_ADCDAT + ); +diff --git a/i2c_loader.vhd b/i2c_loader.vhd +index 61bdd22..e0a7115 100644 +--- a/i2c_loader.vhd ++++ b/i2c_loader.vhd +@@ -84,8 +84,8 @@ constant init_regs : regs := ( + X"0C", X"62", + -- Format 16-bit I2S, no bit inversion or phase changes + X"0E", X"02", +- -- Sampling control, 8 kHz USB mode (MCLK = 250fs * 6) +- X"10", X"0D", ++ -- Sampling control, 48 kHz USB mode (MCLK = 250fs) ++ X"10", X"01", + -- Activate + X"12", X"01" + ); +diff --git a/i2s_intf.vhd b/i2s_intf.vhd +index 49b6efb..dc00622 100644 +--- a/i2s_intf.vhd ++++ b/i2s_intf.vhd +@@ -43,7 +43,7 @@ use IEEE.STD_LOGIC_UNSIGNED.ALL; + entity i2s_intf is + generic( + mclk_rate : positive := 12000000; +- sample_rate : positive := 8000; ++ sample_rate : positive := 48000; + preamble : positive := 1; -- I2S + word_length : positive := 16 + ); +diff --git a/sn76489-1.0/sn76489_attenuator.vhd b/sn76489-1.0/sn76489_attenuator.vhd +index 444064e..a160a05 100644 +--- a/sn76489-1.0/sn76489_attenuator.vhd ++++ b/sn76489-1.0/sn76489_attenuator.vhd +@@ -53,7 +53,7 @@ entity sn76489_attenuator is + port ( + attenuation_i : in std_logic_vector(0 to 3); + factor_i : in signed(0 to 1); +- product_o : out signed(0 to 7) ++ product_o : out signed(0 to 15) + ); + + end sn76489_attenuator; +@@ -83,7 +83,7 @@ begin + + type volume_t is array (natural range 0 to 15) of natural; + constant volume_c : volume_t := +- (31, 25, 20, 16, 12, 10, 8, 6, 5, 4, 3, 2, 2, 2, 1, 0); ++ ( 1905, 1514, 1202, 955, 758, 602, 479, 380, 302, 240, 191, 151, 120, 95, 76, 0); + + variable attenuation_v : unsigned(attenuation_i'range); + variable volume_v : signed(product_o'range); +diff --git a/sn76489-1.0/sn76489_comp_pack-p.vhd b/sn76489-1.0/sn76489_comp_pack-p.vhd +index c5fcc90..88c5c23 100644 +--- a/sn76489-1.0/sn76489_comp_pack-p.vhd ++++ b/sn76489-1.0/sn76489_comp_pack-p.vhd +@@ -18,7 +18,7 @@ package sn76489_comp_pack is + port ( + attenuation_i : in std_logic_vector(0 to 3); + factor_i : in signed(0 to 1); +- product_o : out signed(0 to 7) ++ product_o : out signed(0 to 15) + ); + end component; + +@@ -33,7 +33,7 @@ package sn76489_comp_pack is + rst_a_i : in std_logic_vector(0 to 3); + rst_cnt_i: in std_logic_vector(0 to 9); + ff_o : out std_logic; +- tone_o : out signed(0 to 7) ++ tone_o : out signed(0 to 15) + ); + end component; + +@@ -46,7 +46,7 @@ package sn76489_comp_pack is + d_i : in std_logic_vector(0 to 7); + addr_i : in std_logic_vector(0 to 1); + tone3_ff_i : in std_logic; +- noise_o : out signed(0 to 7) ++ noise_o : out signed(0 to 15) + ); + end component; + +@@ -74,7 +74,7 @@ package sn76489_comp_pack is + we_n_i : in std_logic; + ready_o : out std_logic; + d_i : in std_logic_vector(0 to 7); +- aout_o : out signed(0 to 7) ++ aout_o : out signed(0 to 15) + ); + end component; + +diff --git a/sn76489-1.0/sn76489_noise.vhd b/sn76489-1.0/sn76489_noise.vhd +index 035adab..a19df77 100644 +--- a/sn76489-1.0/sn76489_noise.vhd ++++ b/sn76489-1.0/sn76489_noise.vhd +@@ -58,7 +58,7 @@ entity sn76489_noise is + d_i : in std_logic_vector(0 to 7); + addr_i : in std_logic_vector(0 to 1); + tone3_ff_i : in std_logic; +- noise_o : out signed(0 to 7) ++ noise_o : out signed(0 to 15) + ); + + end sn76489_noise; +@@ -81,7 +81,7 @@ architecture rtl of sn76489_noise is + shift_source_q : std_logic; + signal shift_rise_edge_s : boolean; + +- signal lfsr_q : std_logic_vector(0 to 7); ++ signal lfsr_q : std_logic_vector(0 to 15); + + signal freq_s : signed(0 to 1); + +diff --git a/sn76489-1.0/sn76489_tone.vhd b/sn76489-1.0/sn76489_tone.vhd +index f1b6885..4421423 100644 +--- a/sn76489-1.0/sn76489_tone.vhd ++++ b/sn76489-1.0/sn76489_tone.vhd +@@ -60,7 +60,7 @@ entity sn76489_tone is + rst_a_i : in std_logic_vector(0 to 3); + rst_cnt_i: in std_logic_vector(0 to 9); + ff_o : out std_logic; +- tone_o : out signed(0 to 7) ++ tone_o : out signed(0 to 15) + ); + + end sn76489_tone; +diff --git a/sn76489-1.0/sn76489_top.vhd b/sn76489-1.0/sn76489_top.vhd +index 2f6a01c..512521f 100644 +--- a/sn76489-1.0/sn76489_top.vhd ++++ b/sn76489-1.0/sn76489_top.vhd +@@ -72,7 +72,7 @@ entity sn76489_top is + we_n_i : in std_logic; + ready_o : out std_logic; + d_i : in std_logic_vector(0 to 7); +- aout_o : out signed(0 to 7) ++ aout_o : out signed(0 to 15) + ); + + end sn76489_top; diff --git a/de1/fpga-bbc-pq/master/build-system.patch b/de1/fpga-bbc-pq/master/build-system.patch new file mode 100644 index 0000000..7b9f40f --- /dev/null +++ b/de1/fpga-bbc-pq/master/build-system.patch @@ -0,0 +1,66 @@ +diff --git a/Makefile b/Makefile +new file mode 100644 +index 0000000..dc728fe +--- /dev/null ++++ b/Makefile +@@ -0,0 +1,39 @@ ++PROJ=bbc_micro_de1 ++ ++SRCS=$(wildcard *.vhd *.v *.qsf *.qpf T65/*.vhd sn76489-1.0/*.vhd roms roms/saa5050/saa5050.hex) ++SOF=${PROJ}.sof ++ ++default: load_sof.stamp ++ ++sta.stamp:asm.stamp ++ ./quartus_wrap quartus_sta ${PROJ} -c ${PROJ} ++ touch $@ ++ ++asm.stamp:fit.stamp ++ ./quartus_wrap quartus_asm --read_settings_files=off --write_settings_files=off ${PROJ} -c ${PROJ} ++ touch $@ ++ ++${SOF}:asm.stamp ++ ++fit.stamp: ans.stamp ++ ./quartus_wrap quartus_fit --read_settings_files=off --write_settings_files=off ${PROJ} -c ${PROJ} ++ touch $@ ++ ++ans.stamp: source.stamp ++ ./quartus_wrap quartus_map --read_settings_files=on --write_settings_files=off ${PROJ} -c ${PROJ} ++ touch $@ ++ ++source.stamp:${SRCS} ++ touch source.stamp ++ ++load_sof.stamp: ${SOF} ++ ./quartus_wrap quartus_pgm -m JTAG -o "p;${SOF}" -c 1 ++ #touch $@ ++ ++clean: ++ /bin/rm -rf db incremental_db ++ /bin/rm -f *.stamp ${SOF} *.rpt *.html *.summary *.pin *.jdi *.qws *.pof *.done *.rom ++ ++ ++ ++ +diff --git a/quartus_wrap b/quartus_wrap +new file mode 100755 +index 0000000..e818413 +--- /dev/null ++++ b/quartus_wrap +@@ -0,0 +1,15 @@ ++#!/bin/bash ++ ++AD=/software/apps/altera/quartus_ii_13.0sp1 ++if [ $(uname -m ) == "x86_64" ]; then ++ LL=linux64 ++else ++ LL=linux ++fi ++QUARTUS_ROOTDIR="${AD}/quartus" ++PATH="${AD}/quartus/bin:${AD}/quartus/sopc_builder/bin:${AD}/nios2eds/sdk2/bin:${AD}/nios2eds/bin:${AD}/nios2eds/bin/gnu/H-i686-pc-linux-gnu/bin:${PATH}" ++LD_LIBRARY_PATH="${AD}/quartus/${LL}:/software/apps/altera/libcompat/32:/software/apps/altera/libcompat/64:${LD_LIBRARY_PATH}" ++ ++export LD_LIBRARY_PATH PATH QUARTUS_ROOTDIR ++ ++"$@" diff --git a/de1/fpga-bbc-pq/master/cpu-core-fixes.patch b/de1/fpga-bbc-pq/master/cpu-core-fixes.patch new file mode 100644 index 0000000..4319a09 --- /dev/null +++ b/de1/fpga-bbc-pq/master/cpu-core-fixes.patch @@ -0,0 +1,3881 @@ +diff --git a/T65/T65.vhd b/T65/T65.vhd +index 09253fe..bea8434 100644 +--- a/T65/T65.vhd ++++ b/T65/T65.vhd +@@ -1,7 +1,20 @@ + -- **** + -- T65(b) core. In an effort to merge and maintain bug fixes .... + -- ++-- 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) ++-- ++-- Wolfgang April 2014 ++-- Ver 303 Bugfixes for NMI from foft ++-- Ver 302 Bugfix for BRK command ++-- Wolfgang January 2014 + -- Ver 301 more merging + -- Ver 300 Bugfixes by ehenciak added, started tidyup *bust* + -- MikeJ March 2005 +@@ -69,345 +82,376 @@ library IEEE; + -- ehenciak 2-23-2005 : Added the enable signal so that one doesn't have to use + -- the ready signal to limit the CPU. + 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) +- ); ++ 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);--NOTE:Make sure DI equals DO when writing. This is important for DCP/DCM undoc instruction. TODO:convert to inout ++ 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) ++ ); + end T65; + + architecture rtl of T65 is + +- -- Registers +- signal ABC, X, Y, D : std_logic_vector(15 downto 0); +- signal P, AD, DL : std_logic_vector(7 downto 0) := x"00"; +- 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 : std_logic_vector(3 downto 0); +- signal Write_Data_r : std_logic_vector(2 downto 0); +- signal Set_Addr_To_r : std_logic_vector(1 downto 0); +- signal PCAdder : unsigned(8 downto 0); +- +- signal RstCycle : std_logic; +- signal IRQCycle : std_logic; +- signal NMICycle : std_logic; +- +- signal B_o : 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 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 : std_logic_vector(3 downto 0); +- signal Set_BusA_To : std_logic_vector(2 downto 0); +- signal Set_Addr_To : std_logic_vector(1 downto 0); +- signal Write_Data : std_logic_vector(2 downto 0); +- 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 really_rdy : std_logic; +- signal R_W_n_i : std_logic; ++ -- Registers ++ signal ABC, X, Y, D : 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 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 ALUmore : std_logic; ++ ++ signal really_rdy : std_logic; ++ signal R_W_n_i : std_logic; ++ signal R_W_n_i_d : std_logic; ++ ++ signal NMIActClear : std_logic; -- MWW hack + + begin +- -- ehenciak : gate Rdy with read/write to make an "OK, it's +- -- really OK to stop the processor now if Rdy is +- -- deasserted" signal +- really_rdy <= Rdy or not(R_W_n_i); +- +- -- ehenciak : Drive R_W_n_i off chip. +- R_W_n <= R_W_n_i; +- +- Sync <= '1' when MCycle = "000" else '0'; +- EF <= EF_i; +- MF <= MF_i; +- XF <= XF_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 /= "00" else '0'; -- Incorrect !!!!!!!!!!!! +- VPA <= '1' when Jump(1) = '0' else '0'; -- Incorrect !!!!!!!!!!!! +- +- mcode : T65_MCode +- port map( +- Mode => Mode_r, +- IR => IR, +- MCycle => MCycle, +- P => P, +- 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 : 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 +- ); +- +- process (Res_n, Clk) +- begin +- if Res_n = '0' then +- PC <= (others => '0'); -- Program Counter +- IR <= "00000000"; +- S <= (others => '0'); -- Dummy !!!!!!!!!!!!!!!!!!!!! +- D <= (others => '0'); +- PBR <= (others => '0'); +- DBR <= (others => '0'); +- +- Mode_r <= (others => '0'); +- ALU_Op_r <= "1100"; +- Write_Data_r <= "000"; +- Set_Addr_To_r <= "00"; +- +- R_W_n_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 +- R_W_n_i <= not Write or RstCycle; +- +- D <= (others => '1'); -- Dummy +- 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; +- end if; +- +- ALU_Op_r <= ALU_Op; +- Write_Data_r <= Write_Data; +- if Break = '1' then +- Set_Addr_To_r <= "00"; +- 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 LDS = '1' then +- S(7 downto 0) <= unsigned(ALU_Q); +- 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 (Clk) +- begin +- if Clk'event and Clk = '1' then +- 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 +- P <= P_Out; +- end if; +- end if; +- if SaveP = '1' then +- P <= P_Out; +- end if; +- if LDP = '1' then +- P <= ALU_Q; +- end if; +- if IR(4 downto 0) = "11000" then +- case IR(7 downto 5) is +- when "000" => +- P(Flag_C) <= '0'; +- when "001" => +- P(Flag_C) <= '1'; +- when "010" => +- P(Flag_I) <= '0'; +- when "011" => +- P(Flag_I) <= '1'; +- when "101" => +- P(Flag_V) <= '0'; +- when "110" => +- P(Flag_D) <= '0'; +- when "111" => +- P(Flag_D) <= '1'; +- when others => +- end case; +- end if; +- +- --if IR = "00000000" and MCycle = "011" and RstCycle = '0' and NMICycle = '0' and IRQCycle = '0' then +- -- P(Flag_B) <= '1'; +- --end if; +- --if IR = "00000000" and MCycle = "100" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then +- -- P(Flag_I) <= '1'; +- -- P(Flag_B) <= B_o; +- --end if; +- +- -- B=1 always on the 6502 +- P(Flag_B) <= '1'; +- if IR = "00000000" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then +- if MCycle = "011" then +- -- B=0 in *copy* of P pushed onto the stack +- P(Flag_B) <= '0'; +- elsif MCycle = "100" then +- P(Flag_I) <= '1'; ++ -- workaround for ready-handling ++ -- ehenciak : Drive R_W_n_i off chip. ++ R_W_n <= R_W_n_i; ++ ++ -- ehenciak : gate Rdy with read/write to make an "OK, it's ++ -- really OK to stop the processor now if Rdy is ++ -- deasserted" signal ++ really_rdy <= Rdy or not(R_W_n_i); ++ ---- ++ ++ Sync <= '1' when MCycle = "000" else '0'; ++ EF <= EF_i; ++ MF <= MF_i; ++ XF <= XF_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'; -- Incorrect !!!!!!!!!!!! ++ VPA <= '1' when Jump(1) = '0' else '0'; -- Incorrect !!!!!!!!!!!! ++ ++ Regs <= std_logic_vector(PC) & std_logic_vector(S)& P & Y(7 downto 0) & X(7 downto 0) & ABC(7 downto 0); ++ ++ mcode : 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, ++ ALUmore => ALUmore, ++ Write => Write ++ ); ++ ++ alu : 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 ++ ); ++ ++ ++ process (Res_n, Clk) ++ begin ++ if Res_n = '0' then ++ PC <= (others => '0'); -- Program Counter ++ IR <= "00000000"; ++ S <= (others => '0'); -- Dummy !!!!!!!!!!!!!!!!!!!!! ++ D <= (others => '0'); ++ 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; ++ ++ R_W_n_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 ++ R_W_n_i <= not Write or RstCycle; ++ ++ D <= (others => '1'); -- Dummy ++ 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; ++ 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 LDS = '1' then ++ S(7 downto 0) <= unsigned(ALU_Q); ++ end if; ++ ++ if IR = "00000000" and MCycle = "001" and IRQCycle = '0' and NMICycle = '0' then ++ PC <= PC + 1; + end if; +- end if; +- +- if SO_n_o = '1' and SO_n = '0' then +- P(Flag_V) <= '1'; +- end if; +- if RstCycle = '1' and Mode_r /= "00" then +- P(Flag_1) <= '1'; +- P(Flag_D) <= '0'; +- P(Flag_I) <= '1'; +- end if; +- P(Flag_1) <= '1'; +- +- B_o <= P(Flag_B); +- SO_n_o <= SO_n; +- IRQ_n_o <= IRQ_n; +- NMI_n_o <= NMI_n; +- end if; +- end if; +- end if; +- end process; ++ -- ++ -- 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, Clk) ++ variable tmpP:std_logic_vector(7 downto 0);--ML:Lets try to handle loading P at mcycle=0 and set/clk flags at same cycle ++ begin ++ if Res_n = '0' then ++ P <= x"00"; -- ensure we have nothing set on reset (e.g. B flag!) ++ 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 ++-- P <= P_Out;-- Replaced with: ++ tmpP:=P_Out; ++ end if; ++ end if; ++ if SaveP = '1' then ++-- P <= P_Out;-- Replaced with: ++ tmpP:=P_Out; ++ end if; ++ if LDP = '1' then ++-- P <= ALU_Q;-- Replaced with: --ML:no need anymore: AND x"EF"; -- NEVER set B on RTI and PLP ++ tmpP:=ALU_Q; ++ end if; ++ if IR(4 downto 0) = "11000" then ++ case IR(7 downto 5) is ++ when "000" =>--0x18(clc) ++-- P(Flag_C) <= '0';-- Replaced with: ++ tmpP(Flag_C) := '0'; ++ when "001" =>--0x38(sec) ++-- P(Flag_C) <= '1'; ++ tmpP(Flag_C) := '1'; ++ when "010" =>--0x58(cli) ++-- P(Flag_I) <= '0'; ++ tmpP(Flag_I) := '0'; ++ when "011" =>--0x78(sei) ++-- P(Flag_I) <= '1'; ++ tmpP(Flag_I) := '1'; ++ when "101" =>--0xb8(clv) ++-- P(Flag_V) <= '0'; ++ tmpP(Flag_V) := '0'; ++ when "110" =>--0xd8(cld) ++-- P(Flag_D) <= '0'; ++ tmpP(Flag_D) := '0'; ++ when "111" =>--0xf8(sed) ++-- P(Flag_D) <= '1'; ++ tmpP(Flag_D) := '1'; ++ when others => ++ end case; ++ end if; ++ --ML:Removed change of B flag, its constant '1' in P ++ --ML:The B flag appears to be locked to '1', but when pushed to stack, the SR data on the stack has the B flag cleared on interrupts, set on BRK instr. ++ --ML:The state of the B flag on warm reset apparently is unchanged (not confirmed, please do if you know) ++ --ML:The state of the B flag on cold reset is uncertain, but my guess would be set, unless it can be used to detect cold from warm reset. ++ --Since we cant (well, won't) simulate B=0 on cold reset, we just behave as if it was constant 1. ++-- P(Flag_B) <= '1'; ++ tmpP(Flag_B) := '1'; ++-- if IR = "00000000" and MCycle = "011" and RstCycle = '0' and NMICycle = '0' and IRQCycle = '0' then -- BRK ++-- P(Flag_B) <= '1'; ++-- elsif IR = "00001000" then -- PHP ++-- P(Flag_B) <= '1'; ++-- else ++-- P(Flag_B) <= '0'; --> not the best way, but we keep B zero except for BRK and PHP opcodes ++-- end if; ++ if IR = "00000000" and MCycle = "100" and RstCycle = '0' then --and (NMICycle = '1' or IRQCycle = '1') then ++ --This should happen after P has been pushed to stack ++-- P(Flag_I) <= '1'; ++ tmpP(Flag_I) := '1'; ++ end if; ++ if SO_n_o = '1' and SO_n = '0' then ++-- P(Flag_V) <= '1'; ++ tmpP(Flag_V) := '1'; ++ end if; ++ if RstCycle = '1' then ++-- P(Flag_I) <= '0'; ++-- P(Flag_D) <= '0'; ++ tmpP(Flag_I) := '1'; ++ tmpP(Flag_D) := '0'; ++ end if; ++-- P(Flag_1) <= '1'; ++ tmpP(Flag_1) := '1'; ++ ++ P<=tmpP;--new way ++ ++ SO_n_o <= SO_n; ++ IRQ_n_o <= IRQ_n; ++ end if; ++ NMI_n_o <= NMI_n; -- MWW: detect nmi even if not rdy ++ end if; ++ end if; ++ end process; + + --------------------------------------------------------------------------- + -- +@@ -415,109 +459,125 @@ begin + -- + --------------------------------------------------------------------------- + +- process (Res_n, Clk) +- begin +- if Res_n = '0' then +- BusA_r <= (others => '0'); +- BusB <= (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 +- if (Rdy = '1') then +- BusA_r <= BusA; +- BusB <= DI; +- +- 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; +- +- -- ehenciak : modified to use Y register as well (bugfix) +- 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' then +- BAL(2 downto 0) <= "010"; +- else +- BAL(2 downto 0) <= "110"; +- end if; +- if Set_addr_To_r = "11" 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 "000", +- ABC(7 downto 0) when "001", +- X(7 downto 0) when "010", +- Y(7 downto 0) when "011", +- std_logic_vector(S(7 downto 0)) when "100", +- P when "101", +- (others => '-') when others; +- +- with Set_Addr_To_r select +- A <= "0000000000000001" & std_logic_vector(S(7 downto 0)) when "01", +- DBR & "00000000" & AD when "10", +- "00000000" & BAH & BAL(7 downto 0) when "11", +- PBR & std_logic_vector(PC(15 downto 8)) & std_logic_vector(PCAdder(7 downto 0)) when others; +- +- with Write_Data_r select +- DO <= DL when "000", +- ABC(7 downto 0) when "001", +- X(7 downto 0) when "010", +- Y(7 downto 0) when "011", +- std_logic_vector(S(7 downto 0)) when "100", +- P when "101", +- std_logic_vector(PC(7 downto 0)) when "110", +- std_logic_vector(PC(15 downto 8)) when others; ++ process (Res_n, Clk) ++ begin ++ if Res_n = '0' then ++ BusA_r <= (others => '0'); ++ BusB <= (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 ++ if (really_rdy = '1') then ++ --if (Rdy = '1') then ++ BusA_r <= BusA; ++ if ALUmore='1' then ++ BusB <= ALU_Q; ++ else ++ BusB <= DI; ++ 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; ++ ++ -- ehenciak : modified to use Y register as well (bugfix) ++ 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; ++ ++ NMIActClear <= '0'; ++ if IR = "00000000" then ++ BAL <= (others => '1'); ++ BAH <= (others => '1'); ++ if RstCycle = '1' then ++ BAL(2 downto 0) <= "100"; ++ elsif NMICycle = '1' then ++ BAL(2 downto 0) <= "010"; ++ elsif NMIAct = '1' then -- MWW, force this to be changed by NMI, even if in midstream IRQ/brk ++ BAL(2 downto 0) <= "010"; ++ NMIActClear <= '1'; ++ 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, ++ (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_S, ++ DBR & "00000000" & AD when Set_Addr_To_AD, ++ "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; ++ ++ --ML: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, ++ (others=>'-') when Write_Data_DONTCARE;--Can probably remove this ++ + + ------------------------------------------------------------------------- + -- +@@ -525,40 +585,44 @@ begin + -- + ------------------------------------------------------------------------- + +- process (Res_n, Clk) +- begin +- if Res_n = '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' then +- NMICycle <= '1'; +- 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; +- +- if NMICycle = '1' then +- NMIAct <= '0'; +- end if; +- if NMI_n_o = '1' and NMI_n = '0' then +- NMIAct <= '1'; +- end if; +- end if; +- end if; +- end if; +- end process; ++ process (Res_n, Clk) ++ begin ++ if Res_n = '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 (NMIActClear = '1') then ++ NMIAct <= '0'; ++ end if; ++ ++ if MCycle = LCycle or Break = '1' then ++ MCycle <= "000"; ++ RstCycle <= '0'; ++ IRQCycle <= '0'; ++ NMICycle <= '0'; ++ if NMIAct = '1' then ++ NMICycle <= '1'; ++ 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; ++ ++ if NMICycle = '1' then ++ NMIAct <= '0'; ++ end if; ++ end if; ++ if NMI_n_o = '1' and NMI_n = '0' then -- MWW: detect nmi even if not rdy ++ NMIAct <= '1'; ++ end if; ++ end if; ++ end if; ++ end process; + + end; +diff --git a/T65/T65_ALU.vhd b/T65/T65_ALU.vhd +index b1f6d63..49ae4a1 100644 +--- a/T65/T65_ALU.vhd ++++ b/T65/T65_ALU.vhd +@@ -2,6 +2,8 @@ + -- T65(b) core. In an effort to merge and maintain bug fixes .... + -- + -- ++-- Ver 303 ost(ML) July 2014 ++-- ALU opcodes to vhdl types + -- Ver 300 Bugfixes by ehenciak added + -- MikeJ March 2005 + -- Latest version from www.fpgaarcade.com (original www.opencores.org) +@@ -62,199 +64,201 @@ 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 std_logic_vector(3 downto 0); +- 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) +- ); ++ 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); ++ -- 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); + + 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); ++ 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; ++ 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(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; ++ 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); ++ 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)); ++ 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; ++ 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; ++ 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_C <= AH(6) or AH(5); + +- ADC_Q <= std_logic_vector(AH(4 downto 1) & AL(4 downto 1)); +- end process; ++ 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; +- begin +- C := P_In(Flag_C) 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); ++ 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; ++ 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; ++ 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); ++ SBC_C <= not AH(5); ++ SBC_V <= (AH(4) xor BusA(7)) and (BusA(7) xor BusB(7)); ++ SBC_N <= AH(4); + +- 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; ++ 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; ++ 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) +- variable Q_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; +- case Op(3 downto 0) is +- when "0000" => +- -- ORA +- Q_t := BusA or BusB; +- when "0001" => +- -- AND +- Q_t := BusA and BusB; +- when "0010" => +- -- EOR +- Q_t := BusA xor BusB; +- when "0011" => +- -- ADC +- P_Out(Flag_V) <= ADC_V; +- P_Out(Flag_C) <= ADC_C; +- Q_t := ADC_Q; +- when "0101" | "1101" => +- -- LDA +- when "0110" => +- -- CMP +- P_Out(Flag_C) <= SBC_C; +- when "0111" => +- -- SBC +- P_Out(Flag_V) <= SBC_V; +- P_Out(Flag_C) <= SBC_C; +- Q_t := SBC_Q; +- when "1000" => +- -- ASL +- Q_t := BusA(6 downto 0) & "0"; +- P_Out(Flag_C) <= BusA(7); +- when "1001" => +- -- ROL +- Q_t := BusA(6 downto 0) & P_In(Flag_C); +- P_Out(Flag_C) <= BusA(7); +- when "1010" => +- -- LSR +- Q_t := "0" & BusA(7 downto 1); +- P_Out(Flag_C) <= BusA(0); +- when "1011" => +- -- ROR +- Q_t := P_In(Flag_C) & BusA(7 downto 1); +- P_Out(Flag_C) <= BusA(0); +- when "1100" => +- -- BIT +- P_Out(Flag_V) <= BusB(6); +- when "1110" => +- -- DEC +- Q_t := std_logic_vector(unsigned(BusA) - 1); +- when "1111" => +- -- INC +- Q_t := std_logic_vector(unsigned(BusA) + 1); +- when others => +- end case; ++ 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) ++ variable Q_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; ++ 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_EQ2|ALU_OP_EQ3=> ++ -- LDA ++ when ALU_OP_CMP=> ++ P_Out(Flag_C) <= SBC_C; ++ when ALU_OP_SBC=> ++ P_Out(Flag_V) <= SBC_V; ++ P_Out(Flag_C) <= SBC_C; ++ Q_t := SBC_Q; ++ 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_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 => ++ --EQ1,EQ2,EQ3 passes BusA to Q_t ++ end case; + +- case Op(3 downto 0) is +- when "0011" => +- P_Out(Flag_N) <= ADC_N; +- P_Out(Flag_Z) <= ADC_Z; +- when "0110" | "0111" => +- P_Out(Flag_N) <= SBC_N; +- P_Out(Flag_Z) <= SBC_Z; +- when "0100" => +- when "1100" => +- 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 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; ++ 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=> ++ P_Out(Flag_N) <= SBC_N; ++ P_Out(Flag_Z) <= SBC_Z; ++ when ALU_OP_EQ1=> ++ 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 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; + +- Q <= Q_t; +- end process; ++ Q <= Q_t; ++ end process; + + end; +diff --git a/T65/T65_MCode.vhd b/T65/T65_MCode.vhd +index 6c6c864..bfc4005 100644 +--- a/T65/T65_MCode.vhd ++++ b/T65/T65_MCode.vhd +@@ -2,9 +2,17 @@ + -- T65(b) core. In an effort to merge and maintain bug fixes .... + -- + -- ++-- Ver 303 ost(ML) July 2014 ++-- (Sorry for some scratchpad comments that may make little sense) ++-- Mods and some 6502 undocumented instructions. ++-- Undoc opcodes learnt from: ++-- "Extra Instructions Of The 65XX Series CPU" ++-- By: Adam Vardy (abe0084@infonet.st-johns.nf.ca) ++-- [File created: 22, Aug. 1995... 27, Sept. 1996] + -- Ver 302 minor timing fixes + -- Ver 301 Jump timing fixed + -- Ver 300 Bugfixes by ehenciak added ++-- Wolfgang January 2014 + -- MikeJ March 2005 + -- Latest version from www.fpgaarcade.com (original www.opencores.org) + -- +@@ -65,988 +73,1324 @@ + 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 std_logic_vector(2 downto 0); +- P : in std_logic_vector(7 downto 0); +- LCycle : out std_logic_vector(2 downto 0); +- ALU_Op : out std_logic_vector(3 downto 0); +- Set_BusA_To : out std_logic_vector(2 downto 0); -- DI,A,X,Y,S,P +- Set_Addr_To : out std_logic_vector(1 downto 0); -- PC Adder,S,AD,BA +- Write_Data : out std_logic_vector(2 downto 0); -- DL,A,X,Y,S,P,PCL,PCH +- 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 +- ); ++ 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 std_logic_vector(2 downto 0); ++ P : in std_logic_vector(7 downto 0); ++ LCycle : out std_logic_vector(2 downto 0); ++ ALU_Op : out T_ALU_Op; ++ Set_BusA_To : out T_Set_BusA_To;-- DI,A,X,Y,S,P ++ 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,A&X ++ 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; ++ ALUmore : out std_logic; ++ Write : out std_logic ++ ); + end T65_MCode; + + architecture rtl of T65_MCode is + +- signal Branch : std_logic; ++ signal Branch : std_logic; ++ --ML:I need the Lcycle locally, so I made it a signal. ++ signal tLcycle:std_logic_vector(Lcycle'range); ++ signal tALUmore:std_logic; ++ ++ --Some simulation debug values. Put an unique number for each assignment and identify it in simulation. ++ signal dbg_Set_BusA_To :integer:=0; --sim debug value to find where Set_BusA_To gets set. ++ signal dbg_LCycle :integer:=0; --sim debug value to fin where tLCycle gets set. ++ signal dbg_Set_Addr_To :integer:=0; --sim debug value to fin where Set_Addr_To gets set. + + 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; ++ 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 <= "001"; +- Set_BusA_To <= "001"; -- A +- Set_Addr_To <= (others => '0'); +- Write_Data <= (others => '0'); +- 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'; ++ LCycle<=tLCycle; ++ ALUmore<=tALUmore; + +- case IR(7 downto 5) is +- when "100" => +- --{{{ +- case IR(1 downto 0) is +- when "00" => +- Set_BusA_To <= "011"; -- Y +- Write_Data <= "011"; -- Y +- when "10" => +- Set_BusA_To <= "010"; -- X +- Write_Data <= "010"; -- X +- when others => +- Write_Data <= "001"; -- A +- end case; +- --}}} +- when "101" => +- --{{{ +- case IR(1 downto 0) is +- when "00" => +- if IR(4) /= '1' or IR(2) /= '0' then +- LDY <= '1'; +- end if; +- when "10" => +- LDX <= '1'; +- when others => +- LDA <= '1'; +- end case; +- Set_BusA_To <= "000"; -- DI +- --}}} +- when "110" => +- --{{{ +- case IR(1 downto 0) is +- when "00" => +- if IR(4) = '0' then +- LDY <= '1'; +- end if; +- Set_BusA_To <= "011"; -- Y +- when others => +- Set_BusA_To <= "001"; -- A +- end case; +- --}}} +- when "111" => +- --{{{ +- case IR(1 downto 0) is +- when "00" => +- if IR(4) = '0' then +- LDX <= '1'; +- end if; +- Set_BusA_To <= "010"; -- X +- when others => +- Set_BusA_To <= "001"; -- A +- end case; +- --}}} +- when others => +- end case; ++ process (IR, MCycle, P, Branch, Mode,tALUmore) ++ begin ++ tLCycle <= "001"; ++ 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'; ++ tALUmore <='0'; ++ ++ case IR(7 downto 5) is ++ when "100" =>--covers 8x,9x ++ --{{{ ++ case IR(1 downto 0) is ++ when "00" => ++ Set_BusA_To <= Set_BusA_To_Y; ++ dbg_Set_BusA_To<=1; ++ Write_Data <= Write_Data_Y; ++ when "10" => ++ Set_BusA_To <= Set_BusA_To_X; ++ dbg_Set_BusA_To<=2; ++ Write_Data <= Write_Data_X; ++ when others => ++ Write_Data <= Write_Data_ABC; ++ end case; ++ --}}} ++ when "101" =>--covers ax,bx ++ --{{{ ++ case IR(1 downto 0) is ++ when "00" => ++ if IR(4) /= '1' or IR(2) /= '0' then--only for ax or b4,bc ++ LDY <= '1'; ++ end if; ++ when "10" => ++ LDX <= '1'; ++ when "11" =>--undoc (beware OAL(ab),LAS(bb)=>Dont know what will happen) ++ LDX<='1'; ++ LDA<='1'; ++ when others => ++ LDA <= '1'; ++ end case; ++ Set_BusA_To <= Set_BusA_To_DI; ++ dbg_Set_BusA_To<=4; ++ --}}} ++ when "110" =>--covers cx,dx ++ --{{{ ++ case IR(1 downto 0) is ++ when "00" => ++ if IR(4) = '0' then--only for cx ++ LDY <= '1'; ++ end if; ++ Set_BusA_To <= Set_BusA_To_Y; ++ dbg_Set_BusA_To<=5; ++ when others => ++ Set_BusA_To <= Set_BusA_To_ABC; ++ dbg_Set_BusA_To<=6; ++ end case; ++ --}}} ++ when "111" =>--covers ex,fx ++ --{{{ ++ case IR(1 downto 0) is ++ when "00" => ++ if IR(4) = '0' then--only ex ++ LDX <= '1'; ++ end if; ++ Set_BusA_To <= Set_BusA_To_X; ++ dbg_Set_BusA_To<=7; ++ when others => ++ Set_BusA_To <= Set_BusA_To_ABC; ++ dbg_Set_BusA_To<=8; ++ end case; ++ --}}} ++ when others => ++ end case; + +- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then +- Set_BusA_To <= "000"; -- DI +- end if; ++-- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then--covers 0x-7x,cx-fx x=2,6,a,e ++ 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 Mode="00" and IR(0)='1' and ((IR(3 downto 2)="11" and MCycle = "101") or (IR(3 downto 2)="01" and MCycle = "100"))then ++ --if Mode="00" and IR(0)='1' and MCycle+1 = tLCycle then ++ if tALUmore='1' then ++ Set_BusA_To <= Set_BusA_To_ABC;--For added compare to DCP/DCM ++ dbg_Set_BusA_To<=99; ++ else ++ Set_BusA_To <= Set_BusA_To_DI; ++ dbg_Set_BusA_To<=9; ++ end if; ++ end if; + +- case IR(4 downto 0) is +- when "00000" | "01000" | "01010" | "11000" | "11010" => +- --{{{ +- -- Implied +- case IR is +- when "00000000" => +- -- BRK +- LCycle <= "110"; +- case to_integer(unsigned(MCycle)) is +- when 1 => +- Set_Addr_To <= "01"; -- S +- Write_Data <= "111"; -- PCH +- Write <= '1'; +- when 2 => +- Dec_S <= '1'; +- Set_Addr_To <= "01"; -- S +- Write_Data <= "110"; -- PCL +- Write <= '1'; +- when 3 => +- Dec_S <= '1'; +- Set_Addr_To <= "01"; -- S +- Write_Data <= "101"; -- P +- Write <= '1'; +- when 4 => +- Dec_S <= '1'; +- Set_Addr_To <= "11"; -- BA +- when 5 => +- LDDI <= '1'; +- Set_Addr_To <= "11"; -- BA +- when 6 => +- Jump <= "10"; -- DIDL +- when others => +- end case; +- when "00100000" => +- -- JSR +- LCycle <= "101"; +- case to_integer(unsigned(MCycle)) is +- when 1 => +- Jump <= "01"; +- LDDI <= '1'; +- Set_Addr_To <= "01"; -- S +- when 2 => +- Set_Addr_To <= "01"; -- S +- Write_Data <= "111"; -- PCH +- Write <= '1'; +- when 3 => +- Dec_S <= '1'; +- Set_Addr_To <= "01"; -- S +- Write_Data <= "110"; -- PCL +- Write <= '1'; +- when 4 => +- Dec_S <= '1'; +- when 5 => +- Jump <= "10"; -- DIDL +- when others => +- end case; +- when "01000000" => +- -- RTI +- LCycle <= "101"; +- case to_integer(unsigned(MCycle)) is +- when 1 => +- Set_Addr_To <= "01"; -- S +- when 2 => +- Inc_S <= '1'; +- Set_Addr_To <= "01"; -- S +- when 3 => +- Inc_S <= '1'; +- Set_Addr_To <= "01"; -- S +- Set_BusA_To <= "000"; -- DI +- when 4 => +- LDP <= '1'; +- Inc_S <= '1'; +- LDDI <= '1'; +- Set_Addr_To <= "01"; -- S +- when 5 => +- Jump <= "10"; -- DIDL +- when others => +- end case; +- when "01100000" => +- -- RTS +- LCycle <= "101"; +- case to_integer(unsigned(MCycle)) is +- when 1 => +- Set_Addr_To <= "01"; -- S +- when 2 => +- Inc_S <= '1'; +- Set_Addr_To <= "01"; -- S +- when 3 => +- Inc_S <= '1'; +- LDDI <= '1'; +- Set_Addr_To <= "01"; -- S +- when 4 => +- Jump <= "10"; -- DIDL +- when 5 => +- Jump <= "01"; +- when others => +- end case; +- when "00001000" | "01001000" | "01011010" | "11011010" => +- -- PHP, PHA, PHY*, PHX* +- LCycle <= "010"; +- if Mode = "00" and IR(1) = '1' then +- LCycle <= "001"; +- end if; +- case to_integer(unsigned(MCycle)) is +- when 1 => +- case IR(7 downto 4) is +- when "0000" => +- Write_Data <= "101"; -- P +- when "0100" => +- Write_Data <= "001"; -- A +- when "0101" => +- Write_Data <= "011"; -- Y +- when "1101" => +- Write_Data <= "010"; -- X +- when others => +- end case; +- Write <= '1'; +- Set_Addr_To <= "01"; -- S +- when 2 => +- Dec_S <= '1'; +- when others => +- end case; +- when "00101000" | "01101000" | "01111010" | "11111010" => +- -- PLP, PLA, PLY*, PLX* +- LCycle <= "011"; +- if Mode = "00" and IR(1) = '1' then +- LCycle <= "001"; +- end if; +- case IR(7 downto 4) is +- when "0010" => +- LDP <= '1'; +- when "0110" => +- LDA <= '1'; +- when "0111" => +- if Mode /= "00" then +- LDY <= '1'; +- end if; +- when "1111" => +- if Mode /= "00" then +- LDX <= '1'; +- end if; +- when others => +- end case; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- SaveP <= '1'; +- when 1 => +- Set_Addr_To <= "01"; -- S +- when 2 => +- Inc_S <= '1'; +- Set_Addr_To <= "01"; -- S +- when 3 => +- Set_BusA_To <= "000"; -- DI +- when others => +- end case; +- when "10100000" | "11000000" | "11100000" => +- -- LDY, CPY, CPX +- -- Immediate +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Jump <= "01"; +- when others => +- end case; +- when "10001000" => +- -- DEY +- LDY <= '1'; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Set_BusA_To <= "011"; -- Y +- when others => +- end case; +- when "11001010" => +- -- DEX +- LDX <= '1'; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Set_BusA_To <= "010"; -- X +- when others => +- end case; +- when "00011010" | "00111010" => +- -- INC*, DEC* +- if Mode /= "00" then +- LDA <= '1'; -- A +- end if; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Set_BusA_To <= "100"; -- S +- when others => +- end case; +- when "00001010" | "00101010" | "01001010" | "01101010" => +- -- ASL, ROL, LSR, ROR +- LDA <= '1'; -- A +- Set_BusA_To <= "001"; -- A +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- when others => +- end case; +- when "10001010" | "10011000" => +- -- TYA, TXA +- LDA <= '1'; -- A +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- when others => +- end case; +- when "10101010" | "10101000" => +- -- TAX, TAY +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Set_BusA_To <= "001"; -- A +- when others => +- end case; +- when "10011010" => +- -- TXS +- case to_integer(unsigned(MCycle)) is +- when 0 => +- LDS <= '1'; +- when 1 => +- when others => +- end case; +- when "10111010" => +- -- TSX +- LDX <= '1'; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Set_BusA_To <= "100"; -- S +- when others => +- end case; ++ case IR(4 downto 0) is ++ when "00000" | "01000" | "01010" | "11000" | "11010" => ++ --{{{ ++ -- Implied ++ case IR is ++ when "00000000" => ++ -- BRK ++ tLCycle <= "110"; ++ dbg_LCycle<=1; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=1; ++ Write_Data <= Write_Data_PCH; ++ Write <= '1'; ++ when 2 => ++ Dec_S <= '1'; ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=2; ++ Write_Data <= Write_Data_PCL; ++ Write <= '1'; ++ when 3 => ++ Dec_S <= '1'; ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=3; ++ Write_Data <= Write_Data_P; ++ Write <= '1'; ++ when 4 => ++ Dec_S <= '1'; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=4; ++ when 5 => ++ LDDI <= '1'; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=5; ++ when 6 => ++ Jump <= "10"; -- DIDL ++ when others => ++ end case; ++ when "00100000" => ++ -- JSR ++ tLCycle <= "101"; ++ dbg_LCycle<=2; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDDI <= '1'; ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=6; ++ when 2 => ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=7; ++ Write_Data <= Write_Data_PCH; ++ Write <= '1'; ++ when 3 => ++ Dec_S <= '1'; ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=8; ++ Write_Data <= Write_Data_PCL; ++ Write <= '1'; ++ when 4 => ++ Dec_S <= '1'; ++ when 5 => ++ Jump <= "10"; -- DIDL ++ when others => ++ end case; ++ when "01000000" => ++ -- RTI ++ tLCycle <= "101"; ++ dbg_LCycle<=3; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=9; ++ when 2 => ++ Inc_S <= '1'; ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=10; ++ when 3 => ++ Inc_S <= '1'; ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=11; ++ Set_BusA_To <= Set_BusA_To_DI; ++ dbg_Set_BusA_To<=10; ++ when 4 => ++ LDP <= '1'; ++ Inc_S <= '1'; ++ LDDI <= '1'; ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=12; ++ when 5 => ++ Jump <= "10"; -- DIDL ++ when others => ++ end case; ++ when "01100000" => ++ -- RTS ++ tLCycle <= "101"; ++ dbg_LCycle<=4; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=13; ++ when 2 => ++ Inc_S <= '1'; ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=14; ++ when 3 => ++ Inc_S <= '1'; ++ LDDI <= '1'; ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=15; ++ when 4 => ++ Jump <= "10"; -- DIDL ++ when 5 => ++ Jump <= "01"; ++ when others => ++ end case; ++ when "00001000" | "01001000" | "01011010" | "11011010" => ++ -- PHP, PHA, PHY*, PHX* ++ tLCycle <= "010"; ++ dbg_LCycle<=5; ++ if Mode = "00" and IR(1) = '1' then--2 cycle nop ++ tLCycle <= "001"; ++ dbg_LCycle<=6; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 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" => --not correct unsupporte ++ 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_S; ++ dbg_Set_Addr_To<=16; ++ end if; ++ when 2 => ++ Dec_S <= '1'; ++ when others => ++ end case; ++ when "00101000" | "01101000" | "01111010" | "11111010" => ++ -- PLP, PLA, PLY*, PLX* ++ tLCycle <= "011"; ++ dbg_LCycle<=7; ++ if Mode = "00" and IR(1) = '1' then--2 cycle nop ++ tLCycle <= "001"; ++ dbg_LCycle<=8; ++ 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; + +- -- when "00011000" | "00111000" | "01011000" | "01111000" | "10111000" | "11011000" | "11111000" | "11001000" | "11101000" => +- -- -- CLC, SEC, CLI, SEI, CLV, CLD, SED, INY, INX +- -- case to_integer(unsigned(MCycle)) is +- -- when 1 => +- -- when others => +- -- end case; +- when others => +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when others => +- end case; +- end case; +- --}}} ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ if Mode /= "00" or IR(1) = '0' then--wrong on 6502 ++ SaveP <= '1'; ++ end if; ++ when 1 => ++ if Mode /= "00" or IR(1) = '0' then--wrong on 6502 ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=17; ++ -- MWW This is wrong, ALU_OP is not populated yet, so previous op's P_out can be saved (This was caused by ROL followed by PLA - THE ISSUE MAY BE DEEPER!) ++ --SaveP <= '1'; --MWW ++ LDP <= '0';--MWW ++ end if; ++ when 2 => ++ Inc_S <= '1'; ++ Set_Addr_To <= Set_Addr_To_S; ++ dbg_Set_Addr_To<=18; ++ --SaveP <= '1';--MWW ++ LDP <= '0'; --MWW ++ when 3 => ++ Set_BusA_To <= Set_BusA_To_DI; ++ dbg_Set_BusA_To<=11; ++ when others => ++ end case; ++ when "10100000" | "11000000" | "11100000" => ++ -- LDY, CPY, CPX ++ -- Immediate ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ when others => ++ end case; ++ when "10001000" => ++ -- DEY ++ LDY <= '1'; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Set_BusA_To <= Set_BusA_To_Y; ++ dbg_Set_BusA_To<=12; ++ when others => ++ end case; ++ when "11001010" => ++ -- DEX ++ LDX <= '1'; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Set_BusA_To <= Set_BusA_To_X; ++ dbg_Set_BusA_To<=13; ++ when others => ++ end case; ++ when "00011010" | "00111010" => ++ -- INC*, DEC* ++ if Mode /= "00" then ++ LDA <= '1'; -- A ++ else ++ tLCycle <= "001";--undoc 2 cycle nop..can I just load tLCycle counter like this? ++ dbg_LCycle<=9; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Set_BusA_To <= Set_BusA_To_S; ++ dbg_Set_BusA_To<=14; ++ when others => ++ end case; ++ when "00001010" | "00101010" | "01001010" | "01101010" => ++ -- ASL, ROL, LSR, ROR ++ LDA <= '1'; -- A ++ Set_BusA_To <= Set_BusA_To_ABC; ++ dbg_Set_BusA_To<=15; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ when others => ++ end case; ++ when "10001010" | "10011000" => ++ -- TYA, TXA ++ LDA <= '1'; -- A ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ when others => ++ end case; ++ when "10101010" | "10101000" => ++ -- TAX, TAY ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Set_BusA_To <= Set_BusA_To_ABC; ++ dbg_Set_BusA_To<=16; ++ when others => ++ end case; ++ when "10011010" => ++ -- TXS ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ LDS <= '1'; ++ when 1 => ++ when others => ++ end case; ++ when "10111010" => ++ -- TSX ++ LDX <= '1'; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Set_BusA_To <= Set_BusA_To_S; ++ dbg_Set_BusA_To<=17; ++ when others => ++ end case; + +- when "00001" | "00011" => +- --{{{ +- -- Zero Page Indexed Indirect (d,x) +- LCycle <= "101"; +- if IR(7 downto 6) /= "10" then +- LDA <= '1'; +- end if; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Jump <= "01"; +- LDAD <= '1'; +- Set_Addr_To <= "10"; -- AD +- when 2 => +- ADAdd <= '1'; +- Set_Addr_To <= "10"; -- AD +- when 3 => +- BAAdd <= "01"; -- DB Inc +- LDBAL <= '1'; +- Set_Addr_To <= "10"; -- AD +- when 4 => +- LDBAH <= '1'; +- if IR(7 downto 5) = "100" then +- Write <= '1'; +- end if; +- Set_Addr_To <= "11"; -- BA +- when 5 => +- when others => +- end case; +- --}}} ++ -- when "00011000" | "00111000" | "01011000" | "01111000" | "10111000" | "11011000" | "11111000" | "11001000" | "11101000" => ++ -- -- CLC, SEC, CLI, SEI, CLV, CLD, SED, INY, INX ++ -- case to_integer(unsigned(MCycle)) is ++ -- when 1 => ++ -- when others => ++ -- end case; ++ when others => ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when others => ++ end case; ++ end case; ++ --}}} + +- when "01001" | "01011" => +- --{{{ +- -- Immediate +- LDA <= '1'; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Jump <= "01"; +- when others => +- end case; ++ when "00001" | "00011" => ++ --{{{ ++ -- Zero Page Indexed Indirect (d,x) ++ tLCycle <= "101"; ++ dbg_LCycle<=10; ++ if IR(7 downto 6) /= "10" then ++ LDA <= '1'; ++ if Mode="00" and IR(1)='1' then--b3 ++ LDX <= '1';--undoc, can load both A and X ++ end if; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDAD <= '1'; ++ Set_Addr_To <= Set_Addr_To_AD; ++ dbg_Set_Addr_To<=19; ++ when 2 => ++ ADAdd <= '1'; ++ Set_Addr_To <= Set_Addr_To_AD; ++ dbg_Set_Addr_To<=20; ++ when 3 => ++ BAAdd <= "01"; -- DB Inc ++ LDBAL <= '1'; ++ Set_Addr_To <= Set_Addr_To_AD; ++ dbg_Set_Addr_To<=21; ++ when 4 => ++ LDBAH <= '1'; ++ if IR(7 downto 5) = "100" then ++ Write <= '1'; ++ end if; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=22; ++ when 5 => ++ if Mode="00" and IR(1)='1' then ++ tALUmore <= '1';--ML:For undoc ASO support ++ end if; ++ when 0 => ++ if Mode="00" and IR(1)='1' then ++ SaveP <= '1';--ML:For undoc DCP/DCM support, save again after compare ++ end if; ++ when others => ++ end case; ++ --}}} + +- --}}} ++ when "01001" | "01011" => ++ --{{{ ++ -- Immediate ++ LDA <= '1'; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ when others => ++ end case; + +- when "00010" | "10010" => +- --{{{ +- -- Immediate, KIL +- LDX <= '1'; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- if IR = "10100010" then +- -- LDX +- Jump <= "01"; +- else +- -- KIL !!!!!!!!!!!!!!!!!!!!!!!!!!!!! +- end if; +- when others => +- end case; +- --}}} ++ --}}} + +- when "00100" => +- --{{{ +- -- Zero Page +- LCycle <= "010"; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- if IR(7 downto 5) = "001" then +- SaveP <= '1'; +- end if; +- when 1 => +- Jump <= "01"; +- LDAD <= '1'; +- if IR(7 downto 5) = "100" then +- Write <= '1'; +- end if; +- Set_Addr_To <= "10"; -- AD +- when 2 => +- when others => +- end case; +- --}}} ++ when "00010" | "10010" => ++ --{{{ ++ -- Immediate, SKB, KIL + +- when "00101" | "00110" | "00111" => +- --{{{ +- -- Zero Page +- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then +- -- Read-Modify-Write +- LCycle <= "100"; +- case to_integer(unsigned(MCycle)) is +- when 1 => +- Jump <= "01"; +- LDAD <= '1'; +- Set_Addr_To <= "10"; -- AD +- when 2 => +- LDDI <= '1'; +- Write <= '1'; +- Set_Addr_To <= "10"; -- AD +- when 3 => +- LDALU <= '1'; +- SaveP <= '1'; +- Write <= '1'; +- Set_Addr_To <= "10"; -- AD +- when 4 => +- when others => +- end case; +- else +- LCycle <= "010"; +- if IR(7 downto 6) /= "10" then +- LDA <= '1'; +- end if; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Jump <= "01"; +- LDAD <= '1'; +- if IR(7 downto 5) = "100" then +- Write <= '1'; +- end if; +- Set_Addr_To <= "10"; -- AD +- when 2 => +- when others => +- end case; +- end if; +- --}}} ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ if IR = "10100010" then ++ -- LDX ++ Jump <= "01"; ++ LDX <= '1';--ML: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 ++ -- SKB skip next byte undoc ++ else ++ -- KIL !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ++ end if; ++ when others => ++ end case; ++ --}}} + +- when "01100" => +- --{{{ +- -- Absolute +- if IR(7 downto 6) = "01" and IR(4 downto 0) = "01100" then +- -- JMP +- if IR(5) = '0' then +- --LCycle <= "011"; +- LCycle <= "010"; +- case to_integer(unsigned(MCycle)) is +- when 1 => +- Jump <= "01"; +- LDDI <= '1'; +- when 2 => +- Jump <= "10"; -- DIDL +- when others => +- end case; +- else +- --LCycle <= "101"; +- LCycle <= "100"; -- mikej +- case to_integer(unsigned(MCycle)) is +- when 1 => +- Jump <= "01"; +- LDDI <= '1'; +- LDBAL <= '1'; +- when 2 => +- LDBAH <= '1'; +- if Mode /= "00" then +- Jump <= "10"; -- DIDL +- end if; +- if Mode = "00" then +- Set_Addr_To <= "11"; -- BA +- end if; +- when 3 => +- LDDI <= '1'; +- if Mode = "00" then +- Set_Addr_To <= "11"; -- BA +- BAAdd <= "01"; -- DB Inc +- else +- Jump <= "01"; +- end if; +- when 4 => +- Jump <= "10"; -- DIDL +- when others => +- end case; +- end if; +- else +- LCycle <= "011"; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- if IR(7 downto 5) = "001" then +- SaveP <= '1'; +- end if; +- when 1 => +- Jump <= "01"; +- LDBAL <= '1'; +- when 2 => +- Jump <= "01"; +- LDBAH <= '1'; +- if IR(7 downto 5) = "100" then +- Write <= '1'; +- end if; +- Set_Addr_To <= "11"; -- BA +- when 3 => +- when others => +- end case; +- end if; +- --}}} ++ when "00100" => ++ --{{{ ++ -- Zero Page ++ tLCycle <= "010"; ++ dbg_LCycle<=11; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ if IR(7 downto 5) = "001" then--24=BIT zpg ++ SaveP <= '1'; ++ end if; ++ when 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_AD; ++ dbg_Set_Addr_To<=23; ++ when 2 => ++ when others => ++ end case; ++ --}}} + +- when "01101" | "01110" | "01111" => +- --{{{ +- -- Absolute +- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then +- -- Read-Modify-Write +- LCycle <= "101"; +- case to_integer(unsigned(MCycle)) is +- when 1 => +- Jump <= "01"; +- LDBAL <= '1'; +- when 2 => +- Jump <= "01"; +- LDBAH <= '1'; +- Set_Addr_To <= "11"; -- BA +- when 3 => +- LDDI <= '1'; +- Write <= '1'; +- Set_Addr_To <= "11"; -- BA +- when 4 => +- Write <= '1'; +- LDALU <= '1'; +- SaveP <= '1'; +- Set_Addr_To <= "11"; -- BA +- when 5 => +- SaveP <= '0'; -- MIKEJ was 1 +- when others => +- end case; +- else +- LCycle <= "011"; +- if IR(7 downto 6) /= "10" then +- LDA <= '1'; +- end if; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Jump <= "01"; +- LDBAL <= '1'; +- when 2 => +- Jump <= "01"; +- LDBAH <= '1'; +- if IR(7 downto 5) = "100" then +- Write <= '1'; +- end if; +- Set_Addr_To <= "11"; -- BA +- when 3 => +- when others => +- end case; +- end if; +- --}}} ++ when "00101" | "00110" | "00111" => ++ --{{{ ++ -- Zero Page ++-- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then--0x-7x,cx-fx, x=2,6,a,e ++ 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 ++ if Mode="00" and IR(0)='1' then ++ LDA<='1'; ++ end if; ++ tLCycle <= "100"; ++ dbg_LCycle<=12; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDAD <= '1'; ++ Set_Addr_To <= Set_Addr_To_AD; ++ dbg_Set_Addr_To<=24; ++ when 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_AD; ++ dbg_Set_Addr_To<=25; ++ when 3 => ++ LDALU <= '1'; ++ SaveP <= '1'; ++ Write <= '1'; ++ Set_Addr_To <= Set_Addr_To_AD; ++ dbg_Set_Addr_To<=26; ++ when 4 => ++ if Mode="00" and IR(0)='1' then ++ tALUmore <= '1';--ML:For undoc DCP/DCM support ++ end if; ++ when 0 => ++ if Mode="00" and IR(0)='1' then ++ SaveP <= '1';--ML:For undoc DCP/DCM support, save again after compare ++ end if; ++ when others => ++ end case; ++ else ++ tLCycle <= "010"; ++ dbg_LCycle<=13; ++ if IR(7 downto 6) /= "10" then ++ LDA <= '1'; ++ if Mode="00" and IR(1)='1' then--b3 ++ LDX <= '1';--undoc, can load both A and X ++ end if; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ LDAD <= '1'; ++ if IR(7 downto 5) = "100" then ++ Write <= '1'; ++ end if; ++ Set_Addr_To <= Set_Addr_To_AD; ++ dbg_Set_Addr_To<=27; ++ when 2 => ++ when others => ++ end case; ++ end if; ++ --}}} + +- when "10000" => +- --{{{ +- -- Relative ++ when "01100" => ++ --{{{ ++ -- Absolute ++ if IR(7 downto 6) = "01" and IR(4 downto 0) = "01100" then--4c,6c ++ -- JMP ++ if IR(5) = '0' then ++ --tLCycle <= "011"; ++ tLCycle <= "010"; ++ dbg_LCycle<=14; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDDI <= '1'; ++ when 2 => ++ Jump <= "10"; -- DIDL ++ when others => ++ end case; ++ else ++ --tLCycle <= "101"; ++ tLCycle <= "100"; -- mikej ++ dbg_LCycle<=15; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDDI <= '1'; ++ LDBAL <= '1'; ++ when 2 => ++ LDBAH <= '1'; ++ if Mode /= "00" then ++ Jump <= "10"; -- DIDL ++ end if; ++ if Mode = "00" then ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=28; ++ end if; ++ when 3 => ++ LDDI <= '1'; ++ if Mode = "00" then ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=29; ++ BAAdd <= "01"; -- DB Inc ++ else ++ Jump <= "01"; ++ end if; ++ when 4 => ++ Jump <= "10"; -- DIDL ++ when others => ++ end case; ++ end if; ++ else ++ tLCycle <= "011"; ++ dbg_LCycle<=16; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ if IR(7 downto 5) = "001" then--2c-BIT ++ SaveP <= '1'; ++ end if; ++ when 1 => ++ Jump <= "01"; ++ LDBAL <= '1'; ++ when 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; ++ dbg_Set_Addr_To<=30; ++ when 3 => ++ when others => ++ end case; ++ end if; ++ --}}} + +- -- 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 ++ when "01101" | "01110" | "01111" => ++ --{{{ ++ -- Absolute ++-- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then--0x-7x,cx-fx, x=2,6,a,e ++ 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 ++ tLCycle <= "101"; ++ dbg_LCycle<=17; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDBAL <= '1'; ++ when 2 => ++ Jump <= "01"; ++ LDBAH <= '1'; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=31; ++ when 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; ++ dbg_Set_Addr_To<=32; ++ when 4 => ++ Write <= '1'; ++ LDALU <= '1'; ++ SaveP <= '1'; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=33; ++ when 5 => ++ --SaveP <= '0'; -- MIKEJ was 1 ++ if Mode="00" and IR(0)='1' then ++ tALUmore <= '1';--ML:For undoc DCP/DCM support ++ end if; ++ when 0 => ++ if Mode="00" and IR(0)='1' then ++ SaveP <= '1';--ML:For undoc DCP/DCM support, save again after compare ++ end if; ++ when others => ++ end case; ++ else ++ tLCycle <= "011"; ++ dbg_LCycle<=18; ++ if IR(7 downto 6) /= "10" then ++ LDA <= '1'; ++ if Mode="00" and IR(1)='1' then--b3 ++ LDX <= '1';--undoc, can load both A and X ++ end if; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ LDBAL <= '1'; ++ when 2 => ++ Jump <= "01"; ++ LDBAH <= '1'; ++ if IR(7 downto 5) = "100" then ++ Write <= '1'; ++ end if; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=34; ++ when 3 => ++ when others => ++ end case; ++ end if; ++ --}}} + +- LCycle <= "011"; -- We're done @ T3 if branching...upper +- -- level logic will stop at T2 if no page cross +- -- (See the Break signal) +- else ++ when "10000" => ++ --{{{ ++ -- Relative + +- LCycle <= "001"; ++ -- 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 ++ tLCycle <= "011"; -- We're done @ T3 if branching...upper ++ -- level logic will stop at T2 if no page cross ++ -- (See the Break signal) ++ dbg_LCycle<=19; ++ else ++ tLCycle <= "001"; ++ dbg_LCycle<=20; + +- end if; ++ end if; + +- -- This decodes the current microcycle and takes the +- -- proper course of action... +- case to_integer(unsigned(MCycle)) is ++ -- This decodes the current microcycle and takes the ++ -- proper course of action... ++ case to_integer(unsigned(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 1 => ++ -- 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 1 => + +- Jump <= "01"; -- Increments the PC by one (PC will now be PC+2) +- -- from microcycle T0. ++ 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. ++ 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 2 => ++ -- 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 2 => + +- Jump <= "11"; -- Tell the PC Jump logic to use relative mode. ++ 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. ++ 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 3 => ++ -- 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 3 => + + +- when others => null; -- Do nothing. ++ when others => null; -- Do nothing. + +- end case; +- --}}} ++ end case; ++ --}}} + +- when "10001" | "10011" => +- --{{{ +- -- Zero Page Indirect Indexed (d),y +- LCycle <= "101"; +- if IR(7 downto 6) /= "10" then +- LDA <= '1'; +- end if; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Jump <= "01"; +- LDAD <= '1'; +- Set_Addr_To <= "10"; -- AD +- when 2 => +- LDBAL <= '1'; +- BAAdd <= "01"; -- DB Inc +- Set_Addr_To <= "10"; -- AD +- when 3 => +- Set_BusA_To <= "011"; -- Y +- BAAdd <= "10"; -- BA Add +- LDBAH <= '1'; +- Set_Addr_To <= "11"; -- BA +- when 4 => +- BAAdd <= "11"; -- BA Adj +- if IR(7 downto 5) = "100" then +- Write <= '1'; +- else +- BreakAtNA <= '1'; +- end if; +- Set_Addr_To <= "11"; -- BA +- when 5 => +- when others => +- end case; +- --}}} ++ when "10001" | "10011" => ++ --{{{ ++ -- Zero Page Indirect Indexed (d),y ++ tLCycle <= "101"; ++ dbg_LCycle<=21; ++ if IR(7 downto 6) /= "10" then--91,b1,93,b3 only ++ LDA <= '1'; ++ if Mode="00" and IR(1)='1' then--b3 ++ LDX <= '1';--undoc, can load both A and X ++ end if; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDAD <= '1'; ++ Set_Addr_To <= Set_Addr_To_AD; ++ dbg_Set_Addr_To<=35; ++ when 2 => ++ LDBAL <= '1'; ++ BAAdd <= "01"; -- DB Inc ++ Set_Addr_To <= Set_Addr_To_AD; ++ dbg_Set_Addr_To<=36; ++ when 3 => ++ Set_BusA_To <= Set_BusA_To_Y; ++ dbg_Set_BusA_To<=18; ++ BAAdd <= "10"; -- BA Add ++ LDBAH <= '1'; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=37; ++ when 4 => ++ BAAdd <= "11"; -- BA Adj ++ if IR(7 downto 5) = "100" or IR(1)='1' then ++ Write <= '1'; ++ else ++ BreakAtNA <= '1'; ++ if Mode="00" and IR(1)='1' then ++ tALUmore <= '1';--ML:For undoc ++ end if; ++ end if; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=38; ++ when 5 => ++ if Mode="00" and IR(1)='1' then ++ tALUmore <= '1';--ML:For undoc ++ end if; ++ when 0 => ++ if Mode="00" and IR(1)='1' then ++ SaveP <= '1';--ML:For undoc ++ end if; ++ when others => ++ end case; ++ --}}} + +- when "10100" | "10101" | "10110" | "10111" => +- --{{{ +- -- Zero Page, X +- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then +- -- Read-Modify-Write +- LCycle <= "101"; +- case to_integer(unsigned(MCycle)) is +- when 1 => +- Jump <= "01"; +- LDAD <= '1'; +- Set_Addr_To <= "10"; -- AD +- when 2 => +- ADAdd <= '1'; +- Set_Addr_To <= "10"; -- AD +- when 3 => +- LDDI <= '1'; +- Write <= '1'; +- Set_Addr_To <= "10"; -- AD +- when 4 => +- LDALU <= '1'; +- SaveP <= '1'; +- Write <= '1'; +- Set_Addr_To <= "10"; -- AD +- when 5 => +- when others => +- end case; +- else +- LCycle <= "011"; +- if IR(7 downto 6) /= "10" then +- LDA <= '1'; +- end if; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Jump <= "01"; +- LDAD <= '1'; +- Set_Addr_To <= "10"; -- AD +- when 2 => +- ADAdd <= '1'; +- -- Added this check for Y reg. use... +- if (IR(3 downto 0) = "0110") then +- AddY <= '1'; +- end if; ++ when "10100" | "10101" | "10110" | "10111" => ++ --{{{ ++ -- Zero Page, X ++-- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then--16,36,56,76,d6,f6 ++ 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 ++ if Mode="00" and IR(0)='1' then ++ LDA<='1'; ++ end if; ++ tLCycle <= "101"; ++ dbg_LCycle<=22; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDAD <= '1'; ++ Set_Addr_To <= Set_Addr_To_AD; ++ dbg_Set_Addr_To<=39; ++ when 2 => ++ ADAdd <= '1'; ++ Set_Addr_To <= Set_Addr_To_AD; ++ dbg_Set_Addr_To<=40; ++ when 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_AD; ++ dbg_Set_Addr_To<=41; ++ when 4 => ++ LDALU <= '1'; ++ SaveP <= '1'; ++ Write <= '1'; ++ Set_Addr_To <= Set_Addr_To_AD; ++ dbg_Set_Addr_To<=42; ++ when 5 => ++ if Mode="00" and IR(0)='1' then ++ tALUmore <= '1';--ML:For undoc DCP/DCM support ++ end if; ++ when 0 => ++ if Mode="00" and IR(0)='1' then ++ SaveP <= '1';--ML:For undoc DCP/DCM support, save again after compare ++ end if; ++ when others => ++ end case; ++ elsif Mode="00" and IR(7 downto 6)/="10" and IR(4)='1' and IR(1 downto 0)="00" then --covers 1x,3x,5x,7x,dx,fx, for skb/nopzx 6502 undocs ++ tLCycle <= "011";--SKB's at x4 ++ dbg_LCycle<=222; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01";--skip a byte ++ when others=> ++ end case; ++ else ++ tLCycle <= "011"; ++ dbg_LCycle<=23; ++ if IR(7 downto 6) /= "10" then ++ LDA <= '1'; ++ if Mode="00" and IR(1 downto 0)="11" then--x7 ++ LDX <= '1';--undoc, can load both A and X ++ end if; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ LDAD <= '1'; ++ Set_Addr_To <= Set_Addr_To_AD; ++ dbg_Set_Addr_To<=43; ++ when 2 => ++ ADAdd <= '1'; ++ -- Added this check for Y reg. use... ++ if (IR(3 downto 0) = "0110") then--96,b6 ++ AddY <= '1'; ++ end if; + +- if IR(7 downto 5) = "100" then +- Write <= '1'; +- end if; +- Set_Addr_To <= "10"; -- AD +- when 3 => null; +- when others => +- end case; +- end if; +- --}}} ++ if IR(7 downto 5) = "100" then--94,95,96,97 the only write instruction ++ Write <= '1'; ++ end if; ++ Set_Addr_To <= Set_Addr_To_AD; ++ dbg_Set_Addr_To<=44; ++ when 3 => null; ++ when others => ++ end case; ++ end if; ++ --}}} + +- when "11001" | "11011" => +- --{{{ +- -- Absolute Y +- LCycle <= "100"; +- if IR(7 downto 6) /= "10" then +- LDA <= '1'; +- end if; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Jump <= "01"; +- LDBAL <= '1'; +- when 2 => +- Jump <= "01"; +- Set_BusA_To <= "011"; -- Y +- BAAdd <= "10"; -- BA Add +- LDBAH <= '1'; +- Set_Addr_To <= "11"; -- BA +- when 3 => +- BAAdd <= "11"; -- BA adj +- if IR(7 downto 5) = "100" then +- Write <= '1'; +- else +- BreakAtNA <= '1'; +- end if; +- Set_Addr_To <= "11"; -- BA +- when 4 => +- when others => +- end case; +- --}}} ++ when "11001" | "11011" => ++ --{{{ ++ -- Absolute Y ++ tLCycle <= "100"; ++ dbg_LCycle<=24; ++ if IR(7 downto 6) /= "10" then ++ LDA <= '1'; ++ if Mode="00" and IR(1 downto 0)="11" then--xb ++ LDX <= '1';--undoc, can load both A and X ++ end if; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDBAL <= '1'; ++ when 2 => ++ Jump <= "01"; ++ Set_BusA_To <= Set_BusA_To_Y; ++ dbg_Set_BusA_To<=19; ++ BAAdd <= "10"; -- BA Add ++ LDBAH <= '1'; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=45; ++ when 3 => ++ BAAdd <= "11"; -- BA adj ++-- if IR(7 downto 5) = "100" then--99/9b ++ if IR(7 downto 5) = "100" or IR(1)='1' then ++ Write <= '1'; ++ else ++ BreakAtNA <= '1'; ++ end if; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=46; ++ when 4 => ++ if Mode="00" and IR(1)='1' then ++ tALUmore <= '1';--ML:For undoc ++ end if; ++ when 0 => ++ if Mode="00" and IR(1)='1' then ++ SaveP <= '1';--ML:For undoc ++ end if; ++ when others => ++ end case; ++ --}}} + +- when "11100" | "11101" | "11110" | "11111" => +- --{{{ +- -- Absolute X ++ when "11100" | "11101" | "11110" | "11111" => ++ --{{{ ++ -- Absolute X + +- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then +- -- Read-Modify-Write +- LCycle <= "110"; +- case to_integer(unsigned(MCycle)) is +- when 1 => +- Jump <= "01"; +- LDBAL <= '1'; +- when 2 => +- Jump <= "01"; +- Set_BusA_To <= "010"; -- X +- BAAdd <= "10"; -- BA Add +- LDBAH <= '1'; +- Set_Addr_To <= "11"; -- BA +- when 3 => +- BAAdd <= "11"; -- BA adj +- Set_Addr_To <= "11"; -- BA +- when 4 => +- LDDI <= '1'; +- Write <= '1'; +- Set_Addr_To <= "11"; -- BA +- when 5 => +- LDALU <= '1'; +- SaveP <= '1'; +- Write <= '1'; +- Set_Addr_To <= "11"; -- BA +- when 6 => +- when others => +- end case; +- else +- LCycle <= "100"; +- if IR(7 downto 6) /= "10" then +- LDA <= '1'; +- end if; +- case to_integer(unsigned(MCycle)) is +- when 0 => +- when 1 => +- Jump <= "01"; +- LDBAL <= '1'; +- when 2 => +- Jump <= "01"; +- -- mikej +- -- special case 0xBE which uses Y reg as index!! +- if (IR = "10111110") then +- Set_BusA_To <= "011"; -- Y +- else +- Set_BusA_To <= "010"; -- X +- end if; +- BAAdd <= "10"; -- BA Add +- LDBAH <= '1'; +- Set_Addr_To <= "11"; -- BA +- when 3 => +- BAAdd <= "11"; -- BA adj +- if IR(7 downto 5) = "100" then +- Write <= '1'; +- else +- BreakAtNA <= '1'; +- end if; +- Set_Addr_To <= "11"; -- BA +- when 4 => +- when others => +- end case; +- end if; +- --}}} +- when others => +- end case; +- end process; ++-- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then--1x,3x,5x,7x,dx,fx, x=c,d,e,f ++ 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 ++ tLCycle <= "110"; ++ dbg_LCycle<=25; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDBAL <= '1'; ++ when 2 => ++ Jump <= "01"; ++ Set_BusA_To <= Set_BusA_To_X; ++ dbg_Set_BusA_To<=20; ++ BAAdd <= "10"; -- BA Add ++ LDBAH <= '1'; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=47; ++ when 3 => ++ BAAdd <= "11"; -- BA adj ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=48; ++ when 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; ++ dbg_Set_Addr_To<=49; ++ when 5 => ++ LDALU <= '1'; ++ SaveP <= '1'; ++ Write <= '1'; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=50; ++ when 6 => ++ if Mode="00" and IR(0)='1' then ++ tALUmore <= '1';--ML:For undoc DCP/DCM support ++ end if; ++ when 0 => ++ if Mode="00" and IR(0)='1' then ++ SaveP <= '1';--ML:For undoc DCP/DCM support, save again after compare ++ end if; ++ when others => ++ end case; ++-- elsif Mode="00" and IR(7 downto 6)/="10" and IR(4)='1' and IR(1 downto 0)="00" then --covers 1x,3x,5x,7x,dx,fx, for 6502 skw/nopax undocs ++-- tLCycle <= "100";--SKW's at xc ++-- dbg_LCycle<=260; ++-- case to_integer(unsigned(MCycle)) is ++-- when 1 => ++-- Jump <= "01";--skip a byte ++-- when 2 => ++-- Jump <= "01";--skip a byte ++-- when 3 => ++-- BreakAtNA <= '1'; ++-- when others=> ++-- end case; ++ else--9c,9d,9e,9f,bc,bd,be,bf ++ tLCycle <= "100"; ++ dbg_LCycle<=26; ++ if IR(7 downto 6) /= "10" then ++ if Mode/="00" or IR(4)='0' or IR(1 downto 0)/="00" then --covers 1x,3x,5x,7x,dx,fx, for 6502 skw/nopax undocs ++ LDA <= '1'; ++ if Mode="00" and IR(1 downto 0)="11" then--9f,bf ++ LDX <= '1';--undoc, can load both A and X ++ end if; ++ end if; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ LDBAL <= '1'; ++ when 2 => ++ Jump <= "01"; ++ -- mikej ++ -- special case 0xBE which uses Y reg as index!! (added undoc 9e,9f,bf) ++-- if (IR = "10-1111-") then ++ if(IR(7 downto 6)="10" and IR(4 downto 1)="1111") then ++ Set_BusA_To <= Set_BusA_To_Y; ++ dbg_Set_BusA_To<=21; ++ else ++ Set_BusA_To <= Set_BusA_To_X; ++ dbg_Set_BusA_To<=22; ++ end if; ++ BAAdd <= "10"; -- BA Add ++ LDBAH <= '1'; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=51; ++ when 3 => ++ BAAdd <= "11"; -- BA adj ++ if IR(7 downto 5) = "100" then--9x ++ Write <= '1'; ++ else ++ BreakAtNA <= '1'; ++ end if; ++ Set_Addr_To <= Set_Addr_To_BA; ++ dbg_Set_Addr_To<=52; ++ when 4 => ++ when others => ++ end case; ++ end if; ++ --}}} ++ when others => ++ end case; ++ end process; + +- process (IR, MCycle) +- 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 +- when "000" | "001" | "011" => +- case IR(7 downto 5) is +- when "110" | "111" => +- -- CP +- ALU_Op <= "0110"; +- when "101" => +- -- LD +- ALU_Op <= "0101"; +- when "001" => +- -- BIT +- ALU_Op <= "1100"; +- when others => +- -- NOP/ST +- ALU_Op <= "0100"; +- end case; +- when "010" => +- case IR(7 downto 5) is +- when "111" | "110" => +- -- IN +- ALU_Op <= "1111"; +- when "100" => +- -- DEY +- ALU_Op <= "1110"; +- when others => +- -- LD +- ALU_Op <= "1101"; +- end case; +- when "110" => +- case IR(7 downto 5) is +- when "100" => +- -- TYA +- ALU_Op <= "1101"; +- when others => +- ALU_Op <= "----"; +- end case; +- when others => +- case IR(7 downto 5) is +- when "101" => +- -- LD +- ALU_Op <= "1101"; +- when others => +- ALU_Op <= "0100"; +- end case; +- end case; +- --}}} +- when "01" => -- OR +- --{{{ +- ALU_Op(3) <= '0'; +- ALU_Op(2 downto 0) <= IR(7 downto 5); +- --}}} +- when "10" => +- --{{{ +- ALU_Op(3) <= '1'; +- ALU_Op(2 downto 0) <= IR(7 downto 5); +- case IR(7 downto 5) is +- when "000" => +- if IR(4 downto 2) = "110" then +- -- INC +- ALU_Op <= "1111"; +- end if; +- when "001" => +- if IR(4 downto 2) = "110" then +- -- DEC +- ALU_Op <= "1110"; +- end if; +- when "100" => +- if IR(4 downto 2) = "010" then +- -- TXA +- ALU_Op <= "0101"; +- else +- ALU_Op <= "0100"; +- end if; +- when others => +- end case; +- --}}} +- when others => +- --{{{ +- case IR(7 downto 5) is +- when "100" => +- ALU_Op <= "0100"; +- when others => +- if MCycle = "000" then +- ALU_Op(3) <= '0'; +- ALU_Op(2 downto 0) <= IR(7 downto 5); +- else +- ALU_Op(3) <= '1'; +- ALU_Op(2 downto 0) <= IR(7 downto 5); +- end if; +- end case; +- --}}} +- end case; +- end process; ++ process (IR, MCycle, Mode,tALUmore) ++ 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 ++ when "000" | "001" | "011" =>-- "---0 xx00", xx!="10" ++ case IR(7 downto 5) is ++ when "110" | "111" =>--c0,c4,cc,e0,e5,ec ++ -- CP ++ ALU_Op <= ALU_OP_CMP; ++ when "101" =>--a0,a4,ac ++ -- LD ++ ALU_Op <= ALU_OP_EQ2; ++ when "001" =>--20,24,2c (20 is ignored, as its a jmp) ++ -- BIT ++ ALU_Op <= ALU_OP_BIT; ++ when others =>--other x0,x4,xc ++ -- NOP/ST ++ ALU_Op <= ALU_OP_EQ1; ++ end case; ++ when "010" =>-- "---0 1000" ++ case IR(7 downto 5) is ++ when "111" | "110" =>--c8,e8 ++ -- IN ++ ALU_Op <= ALU_OP_INC; ++ when "100" =>--88 ++ -- DEY ++ ALU_Op <= ALU_OP_DEC; ++ when others => ++ -- LD ++ ALU_Op <= ALU_OP_EQ3; ++ end case; ++ when "110" =>-- "---1 1000" ++ case IR(7 downto 5) is ++ when "100" =>--98 ++ -- TYA ++ ALU_Op <= ALU_OP_EQ3; ++ when others => ++ ALU_Op <= ALU_OP_UNDEF; ++ end case; ++ when others =>-- "---x xx00" ++ case IR(7 downto 5) is ++ when "101" =>--ax,bx ++ -- LD ++ ALU_Op <= ALU_OP_EQ3; ++ 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=> ++ 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; ++--ML:replaced by above case() ++-- ALU_Op(3) <= '0'; ++-- ALU_Op(2 downto 0) <= IR(7 downto 5); ++ --}}} ++ when "10" => ++ --{{{ ++ 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_EQ3;--ldx ++ when 6=> ++ ALU_Op<=ALU_OP_DEC; ++ when others=> ++ ALU_Op<=ALU_OP_INC; ++ end case; ++--ML:replaced by above case() ++-- ALU_Op(3) <= '1'; ++-- ALU_Op(2 downto 0) <= IR(7 downto 5); ++ case IR(7 downto 5) is ++ when "000" => ++ if IR(4 downto 2) = "110" and Mode/="00" then--ML:00011010,1a->inc acc, not on 6502 ++ -- INC ++ ALU_Op <= ALU_OP_INC; ++ end if; ++ when "001" => ++ if IR(4 downto 2) = "110" and Mode/="00" then--ML:00111010,3a->dec acc, not on 6502 ++ -- DEC ++ ALU_Op <= ALU_OP_DEC; ++ end if; ++ when "100" => ++ if IR(4 downto 2) = "010" then --10001010,8a->TXA ++ -- TXA ++ ALU_Op <= ALU_OP_EQ2; ++ else --100xxx10, 82,86,8e,92,96,9a,9e ++ ALU_Op <= ALU_OP_EQ1; ++ end if; ++ when others => ++ end case; ++ --}}} ++ when others =>--"11" undoc double alu ops ++ --{{{ ++ case IR(7 downto 5) is ++ when "101" =>--ax,bx ++ ALU_Op <= ALU_OP_EQ1; ++ when others => ++-- if MCycle >= tLCycle then ++ if tALUmore='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; ++--replaced by above case() ++-- ALU_Op(3) <= '0'; ++-- ALU_Op(2 downto 0) <= IR(7 downto 5); ++ 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_EQ3;--ldx ++ when 6=> ++ ALU_Op<=ALU_OP_DEC; ++ when others=> ++ ALU_Op<=ALU_OP_INC; ++ end case; ++--replaced by above case() ++-- ALU_Op(3) <= '1'; ++-- ALU_Op(2 downto 0) <= IR(7 downto 5); ++ end if; ++ end case; ++ --}}} ++ end case; ++ end process; + + end; +diff --git a/T65/T65_Pack.vhd b/T65/T65_Pack.vhd +index e025e1b..1c9178d 100644 +--- a/T65/T65_Pack.vhd ++++ b/T65/T65_Pack.vhd +@@ -2,6 +2,8 @@ + -- T65(b) core. In an effort to merge and maintain bug fixes .... + -- + -- ++-- Ver 303 ost(ML) July 2014 ++-- "magic" constants converted to vhdl types + -- Ver 300 Bugfixes by ehenciak added + -- MikeJ March 2005 + -- Latest version from www.fpgaarcade.com (original www.opencores.org) +@@ -59,59 +61,110 @@ 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; ++ 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; + +- component T65_MCode +- 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 std_logic_vector(2 downto 0); +- P : in std_logic_vector(7 downto 0); +- LCycle : out std_logic_vector(2 downto 0); +- ALU_Op : out std_logic_vector(3 downto 0); +- Set_BusA_To : out std_logic_vector(2 downto 0); -- DI,A,X,Y,S,P +- Set_Addr_To : out std_logic_vector(1 downto 0); -- PC Adder,S,AD,BA +- Write_Data : out std_logic_vector(2 downto 0); -- DL,A,X,Y,S,P,PCL,PCH +- 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 component; ++ 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_DONTCARE ++ ); ++ type T_Set_Addr_To is ++ ( ++ Set_Addr_To_S, ++ Set_Addr_To_AD, ++ Set_Addr_To_PBR, ++ 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_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_UNDEF--"----"--may be replaced with any? ++ ); + +- component T65_ALU +- port( +- Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 +- Op : in std_logic_vector(3 downto 0); +- 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 component; ++ component T65_MCode ++ 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 std_logic_vector(2 downto 0); ++ P : in std_logic_vector(7 downto 0); ++ LCycle : out std_logic_vector(2 downto 0); ++ ALU_Op : out T_ALU_Op; ++ Set_BusA_To : out T_Set_BusA_To;-- DI,A,X,Y,S,P ++ 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 ++ 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; ++ ALUmore : out std_logic; ++ Write : out std_logic ++ ); ++ end component; ++ ++ component T65_ALU ++ port( ++ Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 ++ 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 component; + + end; diff --git a/de1/fpga-bbc-pq/master/dram-floating-pins.patch b/de1/fpga-bbc-pq/master/dram-floating-pins.patch new file mode 100644 index 0000000..2c75184 --- /dev/null +++ b/de1/fpga-bbc-pq/master/dram-floating-pins.patch @@ -0,0 +1,193 @@ +diff --git a/bbc_micro_de1.vhd b/bbc_micro_de1.vhd +index 2788103..fa7b2e8 100644 +--- a/bbc_micro_de1.vhd ++++ b/bbc_micro_de1.vhd +@@ -70,7 +70,7 @@ generic ( + -- 5 Not used + -- 6 Not used + -- 7 MOS +- ROM_OFFSET : std_logic_vector(7 downto 0) := "00001000" ++ ROM_OFFSET : std_logic_vector(21 downto 0) := std_logic_vector(to_unsigned(16#20000#,22)) + ); + port ( + -- Clocks +@@ -663,6 +663,7 @@ signal sys_via_ca2_out : std_logic; + signal sys_via_ca2_oe_n : std_logic; + signal sys_via_pa_in : std_logic_vector(7 downto 0); + signal sys_via_pa_out : std_logic_vector(7 downto 0); ++signal effective_sys_via_pa_out : std_logic_vector(7 downto 0); + signal sys_via_pa_oe_n : std_logic_vector(7 downto 0); + signal sys_via_cb1_in : std_logic := '0'; + signal sys_via_cb1_out : std_logic; +@@ -745,6 +746,9 @@ signal romsel : std_logic_vector(3 downto 0); + + signal mhz1_enable : std_logic; -- Set for access to any 1 MHz peripheral + ++signal video_data : std_logic_vector (7 downto 0); ++signal cpu_ram_di : std_logic_vector (7 downto 0); ++ + begin + ------------------------- + -- COMPONENT INSTANCES +@@ -800,6 +804,8 @@ begin + cpu_a, + cpu_di, + cpu_do ); ++ ++ crtc_lpstb <='0'; + + crtc : mc6845 port map ( + clock, +@@ -826,7 +832,7 @@ begin + vidproc_enable, + cpu_a(0), + cpu_do, +- SRAM_DQ(7 downto 0), ++ video_data, + vidproc_invert_n, + vidproc_disen, + crtc_cursor, +@@ -850,7 +856,7 @@ begin + reset_n, + clock, -- Data input is synchronised from the bus clock domain + vid_clken, +- SRAM_DQ(6 downto 0), ++ video_data(6 downto 0), + ttxt_glr, + ttxt_dew, + ttxt_crs, +@@ -889,6 +895,8 @@ begin + mhz4_clken, + clock + ); ++ ++ effective_sys_via_pa_out <= sys_via_pa_out or sys_via_pa_oe_n; + + -- User VIA + user_via : m6522 port map ( +@@ -1118,7 +1126,7 @@ begin + + -- CPU data bus mux and interrupts + cpu_di <= +- SRAM_DQ(7 downto 0) when ram_enable = '1' else ++ cpu_ram_di when ram_enable = '1' else + FL_DQ when rom_enable = '1' else + FL_DQ when mos_enable = '1' else + crtc_do when crtc_enable = '1' else +@@ -1137,19 +1145,17 @@ begin + FL_CE_N <= '0'; + FL_OE_N <= '0'; + FL_WE_N <= '1'; +- FL_ADDR(21 downto 17) <= ROM_OFFSET(7 downto 3); +- FL_ADDR(16 downto 14) <= +- "111" when mos_enable = '1' else +- "0" & romsel(1 downto 0); ++ FL_ADDR(21 downto 17) <= ROM_OFFSET(21 downto 17); ++ FL_ADDR(16 downto 14) <= "111" when mos_enable = '1' else "0" & romsel(1 downto 0); + FL_ADDR(13 downto 0) <= cpu_a(13 downto 0); + + -- SRAM bus + SRAM_UB_N <= '1'; + SRAM_LB_N <= '0'; +- SRAM_CE_N <= '0'; ++ SRAM_CE_N <= clock; + SRAM_OE_N <= '0'; +- SRAM_DQ(15 downto 8) <= (others => '0'); +- ++ video_data <= SRAM_DQ(7 downto 0); ++ + -- Synchronous outputs to SRAM + process(clock,reset_n) + variable ram_write : std_logic; +@@ -1158,23 +1164,25 @@ begin + + if reset_n = '0' then + SRAM_WE_N <= '1'; +- SRAM_DQ(7 downto 0) <= (others => 'Z'); ++ SRAM_DQ(15 downto 0) <= (others => 'Z'); + elsif rising_edge(clock) then +- -- Default to inputs +- SRAM_DQ(7 downto 0) <= (others => 'Z'); +- + -- Register SRAM signals to outputs (clock must be at least 2x CPU clock) + if vid_clken = '1' then +- -- Fetch data from previous CPU cycle ++ -- set up bus for CPU cycle + SRAM_WE_N <= not ram_write; + SRAM_ADDR <= "00" & cpu_a(15 downto 0); + if ram_write = '1' then ++ SRAM_DQ(15 downto 8) <=(others =>'0'); + SRAM_DQ(7 downto 0) <= cpu_do; ++ else ++ SRAM_DQ(15 downto 0) <= (others => 'Z'); + end if; + else +- -- Fetch data from previous display cycle ++ cpu_ram_di <= SRAM_DQ(7 downto 0); ++ -- setup crtc cycle + SRAM_WE_N <= '1'; + SRAM_ADDR <= "000" & display_a; ++ SRAM_DQ(15 downto 0) <= (others => 'Z'); + end if; + end if; + end process; +@@ -1242,24 +1250,25 @@ begin + + -- Connections to System VIA + -- ADC +- sys_via_cb1_in <= '1'; -- /EOC ++ sys_via_cb1_in <= '0'; -- EOC + -- CRTC + sys_via_ca1_in <= crtc_vsync; + sys_via_cb2_in <= crtc_lpstb; + -- Keyboard + sys_via_ca2_in <= keyb_int; + sys_via_pa_in(7) <= keyb_out; +- sys_via_pa_in(6 downto 0) <= sys_via_pa_out(6 downto 0); -- Must loop back output pins or keyboard won't work +- keyb_column <= sys_via_pa_out(3 downto 0); +- keyb_row <= sys_via_pa_out(6 downto 4); ++ sys_via_pa_in(6 downto 0) <= effective_sys_via_pa_out(6 downto 0); -- Must loop back output pins or keyboard won't work ++ keyb_column <= effective_sys_via_pa_out(3 downto 0); ++ keyb_row <= effective_sys_via_pa_out(6 downto 4); + -- Sound +- sound_di <= sys_via_pa_out; ++ sound_di <= effective_sys_via_pa_out; + -- Others (idle until missing bits implemented) + sys_via_pb_in(7 downto 4) <= (others => '1'); + + -- Connections to User VIA (user port is output on green LEDs) + user_via_ca1_in <= '1'; -- Pulled up + --LEDG <= user_via_pb_out; ++ --LEDG(7 downto 2) <= (others => '0'); + + -- MMBEEB + user_via_cb1_in <= user_via_pb_out(1); +@@ -1290,15 +1299,15 @@ begin + disp_addr_offs <= ic32(5 downto 4); + caps_lock_led_n <= ic32(6); + shift_lock_led_n <= ic32(7); ++ + + process(clock,reset_n) + variable bit_num : integer; + begin + bit_num := to_integer(unsigned(sys_via_pb_out(2 downto 0))); +- + if reset_n = '0' then +- ic32 <= (others => '0'); +- elsif rising_edge(clock) then ++ ic32 <= (others => '1'); ++ elsif rising_edge(clock) then -- the real beep latches this on the 1MHz bus clock exactly once per sys_via_enable + ic32(bit_num) <= sys_via_pb_out(3); + end if; + end process; +@@ -1311,6 +1320,9 @@ begin + -- DEBUG STUFF + ----------------- + ++ DRAM_DQ <= (others => 'Z'); ++ DRAM_DQ <= (others => 'Z'); ++ + GPIO_0(0) <= not (crtc_hsync xor crtc_vsync); + GPIO_0(1) <= crtc_de; + diff --git a/de1/fpga-bbc-pq/master/endstop b/de1/fpga-bbc-pq/master/endstop new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/de1/fpga-bbc-pq/master/endstop diff --git a/de1/fpga-bbc-pq/master/fix-warnings.patch b/de1/fpga-bbc-pq/master/fix-warnings.patch new file mode 100644 index 0000000..cb144a6 --- /dev/null +++ b/de1/fpga-bbc-pq/master/fix-warnings.patch @@ -0,0 +1,43 @@ +diff --git a/bbc_micro_de1.vhd b/bbc_micro_de1.vhd +index 0985580..9234f82 100644 +--- a/bbc_micro_de1.vhd ++++ b/bbc_micro_de1.vhd +@@ -159,11 +159,12 @@ port ( + SD_MISO : in std_logic; + + -- GPIO +- GPIO_0 : inout std_logic_vector(35 downto 0); +- GPIO_1 : inout std_logic_vector(35 downto 0) ++ GPIO_0 : out std_logic_vector(35 downto 0); ++ GPIO_1 : out std_logic_vector(35 downto 0) + ); + end entity; + ++-- altera message_off 10036 + architecture rtl of bbc_micro_de1 is + + ------------------------------ +diff --git a/mc6845.vhd b/mc6845.vhd +index c28152d..59407d1 100644 +--- a/mc6845.vhd ++++ b/mc6845.vhd +@@ -70,6 +70,7 @@ port ( + ); + end entity; + ++-- altera message_off 10036 + architecture rtl of mc6845 is + + -- Host-accessible registers +diff --git a/saa5050.vhd b/saa5050.vhd +index d082339..ad09624 100644 +--- a/saa5050.vhd ++++ b/saa5050.vhd +@@ -85,6 +85,7 @@ port ( + ); + end entity; + ++-- altera message_off 10036 + architecture rtl of saa5050 is + + component saa5050_rom IS diff --git a/de1/fpga-bbc-pq/master/gitignore.patch b/de1/fpga-bbc-pq/master/gitignore.patch new file mode 100644 index 0000000..c4702f2 --- /dev/null +++ b/de1/fpga-bbc-pq/master/gitignore.patch @@ -0,0 +1,24 @@ +diff --git a/.gitignore b/.gitignore +new file mode 100644 +index 0000000..f3f2537 +--- /dev/null ++++ b/.gitignore +@@ -0,0 +1,18 @@ ++*.stamp ++bbc_micro_de1.asm.rpt ++bbc_micro_de1.fit.rpt ++bbc_micro_de1.fit.smsg ++bbc_micro_de1.fit.summary ++bbc_micro_de1.flow.rpt ++bbc_micro_de1.jdi ++bbc_micro_de1.map.rpt ++bbc_micro_de1.map.summary ++bbc_micro_de1.pin ++bbc_micro_de1.pof ++bbc_micro_de1.qpf ++bbc_micro_de1.sof ++bbc_micro_de1_assignment_defaults.qdf ++db/ ++fit.stamp ++incremental_db/ ++source.stamp diff --git a/de1/fpga-bbc-pq/master/keyboard-fixes.patch b/de1/fpga-bbc-pq/master/keyboard-fixes.patch new file mode 100644 index 0000000..c12e167 --- /dev/null +++ b/de1/fpga-bbc-pq/master/keyboard-fixes.patch @@ -0,0 +1,53 @@ +diff --git a/bbc_micro_de1.vhd b/bbc_micro_de1.vhd +index 7de7276..08145ca 100644 +--- a/bbc_micro_de1.vhd ++++ b/bbc_micro_de1.vhd +@@ -922,6 +922,9 @@ begin + clock + ); + ++ --LEDG(0) <= not PS2_CLK; ++ --LEDG(1) <= not PS2_DAT; ++ + -- Keyboard + keyb : keyboard port map ( + clock, hard_reset_n, mhz1_clken, +diff --git a/keyboard.vhd b/keyboard.vhd +index d3dd8f4..c1893c6 100644 +--- a/keyboard.vhd ++++ b/keyboard.vhd +@@ -73,6 +73,7 @@ port ( + ); + end entity; + ++-- altera message_off 10036 + architecture rtl of keyboard is + + -- PS/2 interface +@@ -208,6 +209,13 @@ begin + KEYPRESS <= '0'; + end if; + end process; ++ ++ keys(10) <= (others => '0'); ++ keys(11) <= (others => '0'); ++ keys(12) <= (others => '0'); ++ keys(13) <= (others => '0'); ++ keys(14) <= (others => '0'); ++ keys(15) <= (others => '0'); + + -- Decode PS/2 data + process(CLOCK,nRESET) +@@ -229,12 +237,6 @@ begin + keys(8) <= (others => '0'); + keys(9) <= (others => '0'); + -- These non-existent rows are used in the BBC master +- keys(10) <= (others => '0'); +- keys(11) <= (others => '0'); +- keys(12) <= (others => '0'); +- keys(13) <= (others => '0'); +- keys(14) <= (others => '0'); +- keys(15) <= (others => '0'); + elsif rising_edge(CLOCK) then + -- Copy DIP switches through to row 0 + keys(2)(0) <= DIP_SWITCH(7); diff --git a/de1/fpga-bbc-pq/master/keyboard.patch b/de1/fpga-bbc-pq/master/keyboard.patch new file mode 100644 index 0000000..ffeefc3 --- /dev/null +++ b/de1/fpga-bbc-pq/master/keyboard.patch @@ -0,0 +1,787 @@ +diff --git a/bbc_micro_de1.vhd b/bbc_micro_de1.vhd +index 462e507..7de7276 100644 +--- a/bbc_micro_de1.vhd ++++ b/bbc_micro_de1.vhd +@@ -398,8 +398,8 @@ port ( + CLKEN_1MHZ : in std_logic; + + -- PS/2 interface +- PS2_CLK : in std_logic; +- PS2_DATA : in std_logic; ++ PS2_CLK : inout std_logic; ++ PS2_DATA : inout std_logic; + + -- If 1 then column is incremented automatically at + -- 1 MHz rate +@@ -416,7 +416,9 @@ port ( + BREAK_OUT : out std_logic; + + -- DIP switch inputs +- DIP_SWITCH : in std_logic_vector(7 downto 0) ++ DIP_SWITCH : in std_logic_vector(7 downto 0); ++ ++ DEBUG : out std_logic_vector(7 downto 0) + ); + end component; + +@@ -930,7 +932,8 @@ begin + keyb_out, + keyb_int, + keyb_break, +- SW(7 downto 0) ++ SW(7 downto 0), ++ LEDG + ); + + -- Sound generator (and drive logic for I2S codec) +diff --git a/keyboard.vhd b/keyboard.vhd +index cba4054..d3dd8f4 100644 +--- a/keyboard.vhd ++++ b/keyboard.vhd +@@ -50,8 +50,8 @@ port ( + CLKEN_1MHZ : in std_logic; + + -- PS/2 interface +- PS2_CLK : in std_logic; +- PS2_DATA : in std_logic; ++ PS2_CLK : inout std_logic; ++ PS2_DATA : inout std_logic; + + -- If 1 then column is incremented automatically at + -- 1 MHz rate +@@ -68,31 +68,57 @@ port ( + BREAK_OUT : out std_logic; + + -- DIP switch inputs +- DIP_SWITCH : in std_logic_vector(7 downto 0) ++ DIP_SWITCH : in std_logic_vector(7 downto 0); ++ DEBUG : out std_logic_vector(7 downto 0) + ); + end entity; + + architecture rtl of keyboard is + + -- PS/2 interface +-component ps2_intf is +-generic (filter_length : positive := 8); ++--component ps2_intf is ++--generic (filter_length : positive := 8); ++--port( ++-- CLK : in std_logic; ++-- nRESET : in std_logic; ++-- ++-- -- PS/2 interface (could be bi-dir) ++-- PS2_CLK : inout std_logic; ++-- PS2_DATA : inout std_logic; ++-- ++-- -- Byte-wide data interface - only valid for one clock ++-- -- so must be latched externally if required ++-- DATA : out std_logic_vector(7 downto 0); ++-- VALID : out std_logic; ++-- ERROR : out std_logic; ++-- DEBUG : out std_logic_vector(7 downto 0) ++-- ); ++--end component; ++ ++component ps2_keyboard is + port( + CLK : in std_logic; +- nRESET : in std_logic; +- +- -- PS/2 interface (could be bi-dir) +- PS2_CLK : in std_logic; +- PS2_DATA : in std_logic; +- +- -- Byte-wide data interface - only valid for one clock +- -- so must be latched externally if required +- DATA : out std_logic_vector(7 downto 0); +- VALID : out std_logic; +- ERROR : out std_logic +- ); ++ RESET : in std_logic; ++ PS2_CLK_O : out std_logic; ++ PS2_DATA_O : out std_logic; ++ PS2_CLK_I : in std_logic; ++ PS2_DATA_I : in std_logic; ++ RX_EXTENDED : out std_logic; ++ RX_RELEASED : out std_logic; ++ RX_SHIFT_KEY_ON : out std_logic; ++ RX_SCAN_CODE : out std_logic_vector(7 downto 0); ++ RX_ASCII : out std_logic_vector(7 downto 0); ++ RX_DATA_READY : out std_logic; ++ RX_READ : in std_logic; ++ TX_DATA : in std_logic_vector(7 downto 0); ++ TX_WRITE : in std_logic; ++ TX_WRITE_ACK_O : out std_logic; ++ TX_ERROR_NO_KEYBOARD_ACK : out std_logic; ++ TRANSLATE : in std_logic ++); + end component; + ++ + -- Interface to PS/2 block + signal keyb_data : std_logic_vector(7 downto 0); + signal keyb_valid : std_logic; +@@ -104,13 +130,46 @@ signal keys : key_matrix; + signal col : unsigned(3 downto 0); + signal release : std_logic; + signal extended : std_logic; ++ ++signal rx_extended : std_logic; ++signal rx_release : std_logic; ++signal rx_shift_key_on : std_logic; ++signal rx_ascii : std_logic_vector(7 downto 0); ++signal tx_write_ack : std_logic; ++signal tx_error : std_logic; ++ ++signal ps2_clk_o : std_logic; ++signal ps2_data_o: std_logic; ++signal tx_data : std_logic_vector(7 downto 0); ++signal tx_write : std_logic; + begin + +- ps2 : ps2_intf port map ( +- CLOCK, nRESET, +- PS2_CLK, PS2_DATA, +- keyb_data, keyb_valid, keyb_error +- ); ++ PS2_CLK <='0' when ps2_clk_o='0' else 'Z'; ++ PS2_DATA <='0' when ps2_data_o='0' else 'Z'; ++ ++ ++ ++ ps2 : ps2_keyboard port map ( ++ CLOCK, not nRESET, ++ ps2_clk_o,ps2_data_o, ++ PS2_CLK,PS2_DATA, ++ rx_extended,rx_release, ++ rx_shift_key_on, keyb_data,rx_ascii, ++ keyb_valid,keyb_valid,tx_data, ++ tx_write,tx_write_ack,tx_error,'0'); ++ ++ ++ process(CLOCK,nRESET,tx_write_ack) begin ++ if nRESET = '0' then ++ tx_write <= '1'; ++ tx_data <= to_stdlogicvector(x"F4"); ++ elsif rising_edge(CLOCK) then ++ if tx_write_ack='1' then ++ tx_write<='0'; ++ end if; ++ end if; ++ end process; ++ + + -- Column counts automatically when AUTOSCAN is enabled, otherwise + -- value is loaded from external input +@@ -188,6 +247,7 @@ begin + keys(9)(0) <= DIP_SWITCH(0); + + if keyb_valid = '1' then ++ DEBUG <= keyb_data; + -- Decode keyboard input + if keyb_data = X"e0" then + -- Extended key code follows +diff --git a/ps2_keyboard.v b/ps2_keyboard.v +new file mode 100644 +index 0000000..0f21c7c +--- /dev/null ++++ b/ps2_keyboard.v +@@ -0,0 +1,597 @@ ++//------------------------------------------------------------------------------------- ++ ++ ++`define TOTAL_BITS 11 ++`define EXTEND_CODE 16'hE0 ++`define RELEASE_CODE 16'hF0 ++`define LEFT_SHIFT 16'h12 ++`define RIGHT_SHIFT 16'h59 ++ ++ ++module ps2_keyboard ( ++ clk, ++ reset, ++ ps2_clk_o, ++ ps2_data_o, ++ ps2_clk_i, ++ ps2_data_i, ++ rx_extended, ++ rx_released, ++ rx_shift_key_on, ++ rx_scan_code, ++ rx_ascii, ++ rx_data_ready, // rx_read_o ++ rx_read, // rx_read_ack_i ++ tx_data, ++ tx_write, ++ tx_write_ack_o, ++ tx_error_no_keyboard_ack, ++ translate ++ ); ++ ++// Parameters ++ ++// The timer value can be up to (2^bits) inclusive. ++parameter TIMER_60USEC_VALUE_PP = 2950; // Number of sys_clks for 60usec. ++parameter TIMER_60USEC_BITS_PP = 12; // Number of bits needed for timer ++parameter TIMER_5USEC_VALUE_PP = 186; // Number of sys_clks for debounce ++parameter TIMER_5USEC_BITS_PP = 8; // Number of bits needed for timer ++parameter TRAP_SHIFT_KEYS_PP = 0; // Default: No shift key trap. ++ ++// State encodings, provided as parameters ++// for flexibility to the one instantiating the module. ++// In general, the default values need not be changed. ++ ++// State "m1_rx_clk_l" has been chosen on purpose. Since the input ++// synchronizing flip-flops initially contain zero, it takes one clk ++// for them to update to reflect the actual (idle = high) status of ++// the I/O lines from the keyboard. Therefore, choosing 0 for m1_rx_clk_l ++// allows the state machine to transition to m1_rx_clk_h when the true ++// values of the input signals become present at the outputs of the ++// synchronizing flip-flops. This initial transition is harmless, and it ++// eliminates the need for a "reset" pulse before the interface can operate. ++ ++parameter m1_rx_clk_h = 1; ++parameter m1_rx_clk_l = 0; ++parameter m1_rx_falling_edge_marker = 13; ++parameter m1_rx_rising_edge_marker = 14; ++parameter m1_tx_force_clk_l = 3; ++parameter m1_tx_first_wait_clk_h = 10; ++parameter m1_tx_first_wait_clk_l = 11; ++parameter m1_tx_reset_timer = 12; ++parameter m1_tx_wait_clk_h = 2; ++parameter m1_tx_clk_h = 4; ++parameter m1_tx_clk_l = 5; ++parameter m1_tx_wait_keyboard_ack = 6; ++parameter m1_tx_done_recovery = 7; ++parameter m1_tx_error_no_keyboard_ack = 8; ++parameter m1_tx_rising_edge_marker = 9; ++parameter m2_rx_data_ready = 1; ++parameter m2_rx_data_ready_ack = 0; ++ ++ ++// I/O declarations ++input clk; ++input reset; ++output ps2_clk_o ; ++output ps2_data_o ; ++input ps2_clk_i ; ++input ps2_data_i ; ++output rx_extended; ++output rx_released; ++output rx_shift_key_on; ++output [7:0] rx_scan_code; ++output [7:0] rx_ascii; ++output rx_data_ready; ++input rx_read; ++input [7:0] tx_data; ++input tx_write; ++output tx_write_ack_o; ++output tx_error_no_keyboard_ack; ++input translate ; ++ ++reg rx_extended; ++reg rx_released; ++reg [7:0] rx_scan_code; ++reg [7:0] rx_ascii; ++reg rx_data_ready; ++reg tx_error_no_keyboard_ack; ++ ++// Internal signal declarations ++wire timer_60usec_done; ++wire timer_5usec_done; ++wire extended; ++wire released; ++wire shift_key_on; ++ ++ // NOTE: These two signals used to be one. They ++ // were split into two signals because of ++ // shift key trapping. With shift key ++ // trapping, no event is generated externally, ++ // but the "hold" data must still be cleared ++ // anyway regardless, in preparation for the ++ // next scan codes. ++wire rx_output_event; // Used only to clear: hold_released, hold_extended ++wire rx_output_strobe; // Used to produce the actual output. ++ ++wire tx_parity_bit; ++wire rx_shifting_done; ++wire tx_shifting_done; ++wire [11:0] shift_key_plus_code; ++ ++reg [`TOTAL_BITS-1:0] q; ++reg [3:0] m1_state; ++reg [3:0] m1_next_state; ++reg m2_state; ++reg m2_next_state; ++reg [3:0] bit_count; ++reg enable_timer_60usec; ++reg enable_timer_5usec; ++reg [TIMER_60USEC_BITS_PP-1:0] timer_60usec_count; ++reg [TIMER_5USEC_BITS_PP-1:0] timer_5usec_count; ++reg [7:0] ascii; // "REG" type only because a case statement is used. ++reg left_shift_key; ++reg right_shift_key; ++reg hold_extended; // Holds prior value, cleared at rx_output_strobe ++reg hold_released; // Holds prior value, cleared at rx_output_strobe ++reg ps2_clk_s; // Synchronous version of this input ++reg ps2_data_s; // Synchronous version of this input ++reg ps2_clk_hi_z; // Without keyboard, high Z equals 1 due to pullups. ++reg ps2_data_hi_z; // Without keyboard, high Z equals 1 due to pullups. ++ ++//-------------------------------------------------------------------------- ++// Module code ++ ++assign ps2_clk_o = ps2_clk_hi_z ; ++assign ps2_data_o = ps2_data_hi_z ; ++ ++// Input "synchronizing" logic -- synchronizes the inputs to the state ++// machine clock, thus avoiding errors related to ++// spurious state machine transitions. ++always @(posedge clk) ++begin ++ ps2_clk_s <= ps2_clk_i; ++ ps2_data_s <= ps2_data_i; ++end ++ ++// State register ++always @(posedge clk) ++begin : m1_state_register ++ if (reset) m1_state <= m1_rx_clk_h; ++ else m1_state <= m1_next_state; ++end ++ ++// State transition logic ++always @(m1_state ++ or q ++ or tx_shifting_done ++ or tx_write ++ or ps2_clk_s ++ or ps2_data_s ++ or timer_60usec_done ++ or timer_5usec_done ++ ) ++begin : m1_state_logic ++ ++ // Output signals default to this value, unless changed in a state condition. ++ ps2_clk_hi_z <= 1; ++ ps2_data_hi_z <= 1; ++ tx_error_no_keyboard_ack <= 0; ++ enable_timer_60usec <= 0; ++ enable_timer_5usec <= 0; ++ ++ case (m1_state) ++ ++ m1_rx_clk_h : ++ begin ++ enable_timer_60usec <= 1; ++ if (tx_write) m1_next_state <= m1_tx_reset_timer; ++ else if (~ps2_clk_s) m1_next_state <= m1_rx_falling_edge_marker; ++ else m1_next_state <= m1_rx_clk_h; ++ end ++ ++ m1_rx_falling_edge_marker : ++ begin ++ enable_timer_60usec <= 0; ++ m1_next_state <= m1_rx_clk_l; ++ end ++ ++ m1_rx_rising_edge_marker : ++ begin ++ enable_timer_60usec <= 0; ++ m1_next_state <= m1_rx_clk_h; ++ end ++ ++ ++ m1_rx_clk_l : ++ begin ++ enable_timer_60usec <= 1; ++ if (tx_write) m1_next_state <= m1_tx_reset_timer; ++ else if (ps2_clk_s) m1_next_state <= m1_rx_rising_edge_marker; ++ else m1_next_state <= m1_rx_clk_l; ++ end ++ ++ m1_tx_reset_timer: ++ begin ++ enable_timer_60usec <= 0; ++ m1_next_state <= m1_tx_force_clk_l; ++ end ++ ++ m1_tx_force_clk_l : ++ begin ++ enable_timer_60usec <= 1; ++ ps2_clk_hi_z <= 0; // Force the ps2_clk line low. ++ if (timer_60usec_done) m1_next_state <= m1_tx_first_wait_clk_h; ++ else m1_next_state <= m1_tx_force_clk_l; ++ end ++ ++ m1_tx_first_wait_clk_h : ++ begin ++ enable_timer_5usec <= 1; ++ ps2_data_hi_z <= 0; // Start bit. ++ if (~ps2_clk_s && timer_5usec_done) ++ m1_next_state <= m1_tx_clk_l; ++ else ++ m1_next_state <= m1_tx_first_wait_clk_h; ++ end ++ ++ // This state must be included because the device might possibly ++ // delay for up to 10 milliseconds before beginning its clock pulses. ++ // During that waiting time, we cannot drive the data (q[0]) because it ++ // is possibly 1, which would cause the keyboard to abort its receive ++ // and the expected clocks would then never be generated. ++ m1_tx_first_wait_clk_l : ++ begin ++ ps2_data_hi_z <= 0; ++ if (~ps2_clk_s) m1_next_state <= m1_tx_clk_l; ++ else m1_next_state <= m1_tx_first_wait_clk_l; ++ end ++ ++ m1_tx_wait_clk_h : ++ begin ++ enable_timer_5usec <= 1; ++ ps2_data_hi_z <= q[0]; ++ if (ps2_clk_s && timer_5usec_done) ++ m1_next_state <= m1_tx_rising_edge_marker; ++ else ++ m1_next_state <= m1_tx_wait_clk_h; ++ end ++ ++ m1_tx_rising_edge_marker : ++ begin ++ ps2_data_hi_z <= q[0]; ++ m1_next_state <= m1_tx_clk_h; ++ end ++ ++ m1_tx_clk_h : ++ begin ++ ps2_data_hi_z <= q[0]; ++ if (tx_shifting_done) m1_next_state <= m1_tx_wait_keyboard_ack; ++ else if (~ps2_clk_s) m1_next_state <= m1_tx_clk_l; ++ else m1_next_state <= m1_tx_clk_h; ++ end ++ ++ m1_tx_clk_l : ++ begin ++ ps2_data_hi_z <= q[0]; ++ if (ps2_clk_s) m1_next_state <= m1_tx_wait_clk_h; ++ else m1_next_state <= m1_tx_clk_l; ++ end ++ ++ m1_tx_wait_keyboard_ack : ++ begin ++ if (~ps2_clk_s && ps2_data_s) ++ m1_next_state <= m1_tx_error_no_keyboard_ack; ++ else if (~ps2_clk_s && ~ps2_data_s) ++ m1_next_state <= m1_tx_done_recovery; ++ else m1_next_state <= m1_tx_wait_keyboard_ack; ++ end ++ ++ m1_tx_done_recovery : ++ begin ++ if (ps2_clk_s && ps2_data_s) m1_next_state <= m1_rx_clk_h; ++ else m1_next_state <= m1_tx_done_recovery; ++ end ++ ++ m1_tx_error_no_keyboard_ack : ++ begin ++ tx_error_no_keyboard_ack <= 1; ++ if (ps2_clk_s && ps2_data_s) m1_next_state <= m1_rx_clk_h; ++ else m1_next_state <= m1_tx_error_no_keyboard_ack; ++ end ++ ++ default : m1_next_state <= m1_rx_clk_h; ++ endcase ++end ++ ++// State register ++always @(posedge clk) ++begin : m2_state_register ++ if (reset) m2_state <= m2_rx_data_ready_ack; ++ else m2_state <= m2_next_state; ++end ++ ++// State transition logic ++always @(m2_state or rx_output_strobe or rx_read) ++begin : m2_state_logic ++ case (m2_state) ++ m2_rx_data_ready_ack: ++ begin ++ rx_data_ready <= 1'b0; ++ if (rx_output_strobe) m2_next_state <= m2_rx_data_ready; ++ else m2_next_state <= m2_rx_data_ready_ack; ++ end ++ m2_rx_data_ready: ++ begin ++ rx_data_ready <= 1'b1; ++ if (rx_read) m2_next_state <= m2_rx_data_ready_ack; ++ else m2_next_state <= m2_rx_data_ready; ++ end ++ default : m2_next_state <= m2_rx_data_ready_ack; ++ endcase ++end ++ ++// This is the bit counter ++always @(posedge clk) ++begin ++ if ( reset ++ || rx_shifting_done ++ || (m1_state == m1_tx_wait_keyboard_ack) // After tx is done. ++ ) bit_count <= 0; // normal reset ++ else if (timer_60usec_done ++ && (m1_state == m1_rx_clk_h) ++ && (ps2_clk_s) ++ ) bit_count <= 0; // rx watchdog timer reset ++ else if ( (m1_state == m1_rx_falling_edge_marker) // increment for rx ++ ||(m1_state == m1_tx_rising_edge_marker) // increment for tx ++ ) ++ bit_count <= bit_count + 1; ++end ++// This signal is high for one clock at the end of the timer count. ++assign rx_shifting_done = (bit_count == `TOTAL_BITS); ++assign tx_shifting_done = (bit_count == `TOTAL_BITS-1); ++ ++// This is the signal which enables loading of the shift register. ++// It also indicates "ack" to the device writing to the transmitter. ++assign tx_write_ack_o = ( (tx_write && (m1_state == m1_rx_clk_h)) ++ ||(tx_write && (m1_state == m1_rx_clk_l)) ++ ); ++ ++// This is the ODD parity bit for the transmitted word. ++assign tx_parity_bit = ~^tx_data; ++ ++// This is the shift register ++always @(posedge clk) ++begin ++ if (reset) q <= 0; ++ else if (tx_write_ack_o) q <= {1'b1,tx_parity_bit,tx_data,1'b0}; ++ else if ( (m1_state == m1_rx_falling_edge_marker) ++ ||(m1_state == m1_tx_rising_edge_marker) ) ++ q <= {ps2_data_s,q[`TOTAL_BITS-1:1]}; ++end ++ ++// This is the 60usec timer counter ++always @(posedge clk) ++begin ++ if (~enable_timer_60usec) timer_60usec_count <= 0; ++ else if (~timer_60usec_done) timer_60usec_count <= timer_60usec_count + 1; ++end ++assign timer_60usec_done = (timer_60usec_count == (TIMER_60USEC_VALUE_PP - 1)); ++ ++// This is the 5usec timer counter ++always @(posedge clk) ++begin ++ if (~enable_timer_5usec) timer_5usec_count <= 0; ++ else if (~timer_5usec_done) timer_5usec_count <= timer_5usec_count + 1; ++end ++assign timer_5usec_done = (timer_5usec_count == TIMER_5USEC_VALUE_PP - 1); ++ ++ ++// Create the signals which indicate special scan codes received. ++// These are the "unlatched versions." ++`ifdef PS2_TRAP_EXTENDED ++assign extended = (q[8:1] == `EXTEND_CODE) && rx_shifting_done && translate ; ++`else ++assign extended = 1'b0 ; ++`endif ++assign released = (q[8:1] == `RELEASE_CODE) && rx_shifting_done && translate ; ++ ++// Store the special scan code status bits ++// Not the final output, but an intermediate storage place, ++// until the entire set of output data can be assembled. ++always @(posedge clk) ++begin ++ if (reset || rx_output_event) ++ begin ++ hold_extended <= 0; ++ hold_released <= 0; ++ end ++ else ++ begin ++ if (rx_shifting_done && extended) hold_extended <= 1; ++ if (rx_shifting_done && released) hold_released <= 1; ++ end ++end ++ ++ ++// These bits contain the status of the two shift keys ++always @(posedge clk) ++begin ++ if (reset) left_shift_key <= 0; ++ else if ((q[8:1] == `LEFT_SHIFT) && rx_shifting_done && ~hold_released) ++ left_shift_key <= 1; ++ else if ((q[8:1] == `LEFT_SHIFT) && rx_shifting_done && hold_released) ++ left_shift_key <= 0; ++end ++ ++always @(posedge clk) ++begin ++ if (reset) right_shift_key <= 0; ++ else if ((q[8:1] == `RIGHT_SHIFT) && rx_shifting_done && ~hold_released) ++ right_shift_key <= 1; ++ else if ((q[8:1] == `RIGHT_SHIFT) && rx_shifting_done && hold_released) ++ right_shift_key <= 0; ++end ++ ++assign rx_shift_key_on = left_shift_key || right_shift_key; ++ ++// Output the special scan code flags, the scan code and the ascii ++always @(posedge clk) ++begin ++ if (reset) ++ begin ++ rx_extended <= 0; ++ rx_released <= 0; ++ rx_scan_code <= 0; ++ rx_ascii <= 0; ++ end ++ else if (rx_output_strobe) ++ begin ++ rx_extended <= hold_extended; ++ rx_released <= hold_released; ++ rx_scan_code <= q[8:1]; ++ rx_ascii <= ascii; ++ end ++end ++ ++// Store the final rx output data only when all extend and release codes ++// are received and the next (actual key) scan code is also ready. ++// (the presence of rx_extended or rx_released refers to the ++// the current latest scan code received, not the previously latched flags.) ++assign rx_output_event = (rx_shifting_done ++ && ~extended ++ && ~released ++ ); ++ ++assign rx_output_strobe = (rx_shifting_done ++ && ~extended ++ && ~released ++ && ( (TRAP_SHIFT_KEYS_PP == 0) ++ || ( (q[8:1] != `RIGHT_SHIFT) ++ &&(q[8:1] != `LEFT_SHIFT) ++ ) ++ ) ++ ); ++ ++// This part translates the scan code into an ASCII value... ++// Only the ASCII codes which I considered important have been included. ++// if you want more, just add the appropriate case statement lines... ++// (You will need to know the keyboard scan codes you wish to assign.) ++// The entries are listed in ascending order of ASCII value. ++assign shift_key_plus_code = {3'b0,rx_shift_key_on,q[8:1]}; ++always @(shift_key_plus_code) ++begin ++ casez (shift_key_plus_code) ++ 12'h?66 : ascii <= 8'h08; // Backspace ("backspace" key) ++ 12'h?0d : ascii <= 8'h09; // Horizontal Tab ++ 12'h?5a : ascii <= 8'h0d; // Carriage return ("enter" key) ++ 12'h?76 : ascii <= 8'h1b; // Escape ("esc" key) ++ 12'h?29 : ascii <= 8'h20; // Space ++ 12'h116 : ascii <= 8'h21; // ! ++ 12'h152 : ascii <= 8'h22; // " ++ 12'h126 : ascii <= 8'h23; // # ++ 12'h125 : ascii <= 8'h24; // $ ++ 12'h12e : ascii <= 8'h25; // % ++ 12'h13d : ascii <= 8'h26; // & ++ 12'h052 : ascii <= 8'h27; // ' ++ 12'h146 : ascii <= 8'h28; // ( ++ 12'h145 : ascii <= 8'h29; // ) ++ 12'h13e : ascii <= 8'h2a; // * ++ 12'h155 : ascii <= 8'h2b; // + ++ 12'h041 : ascii <= 8'h2c; // , ++ 12'h04e : ascii <= 8'h2d; // - ++ 12'h049 : ascii <= 8'h2e; // . ++ 12'h04a : ascii <= 8'h2f; // / ++ 12'h045 : ascii <= 8'h30; // 0 ++ 12'h016 : ascii <= 8'h31; // 1 ++ 12'h01e : ascii <= 8'h32; // 2 ++ 12'h026 : ascii <= 8'h33; // 3 ++ 12'h025 : ascii <= 8'h34; // 4 ++ 12'h02e : ascii <= 8'h35; // 5 ++ 12'h036 : ascii <= 8'h36; // 6 ++ 12'h03d : ascii <= 8'h37; // 7 ++ 12'h03e : ascii <= 8'h38; // 8 ++ 12'h046 : ascii <= 8'h39; // 9 ++ 12'h14c : ascii <= 8'h3a; // : ++ 12'h04c : ascii <= 8'h3b; // ; ++ 12'h141 : ascii <= 8'h3c; // < ++ 12'h055 : ascii <= 8'h3d; // = ++ 12'h149 : ascii <= 8'h3e; // > ++ 12'h14a : ascii <= 8'h3f; // ? ++ 12'h11e : ascii <= 8'h40; // @ ++ 12'h11c : ascii <= 8'h41; // A ++ 12'h132 : ascii <= 8'h42; // B ++ 12'h121 : ascii <= 8'h43; // C ++ 12'h123 : ascii <= 8'h44; // D ++ 12'h124 : ascii <= 8'h45; // E ++ 12'h12b : ascii <= 8'h46; // F ++ 12'h134 : ascii <= 8'h47; // G ++ 12'h133 : ascii <= 8'h48; // H ++ 12'h143 : ascii <= 8'h49; // I ++ 12'h13b : ascii <= 8'h4a; // J ++ 12'h142 : ascii <= 8'h4b; // K ++ 12'h14b : ascii <= 8'h4c; // L ++ 12'h13a : ascii <= 8'h4d; // M ++ 12'h131 : ascii <= 8'h4e; // N ++ 12'h144 : ascii <= 8'h4f; // O ++ 12'h14d : ascii <= 8'h50; // P ++ 12'h115 : ascii <= 8'h51; // Q ++ 12'h12d : ascii <= 8'h52; // R ++ 12'h11b : ascii <= 8'h53; // S ++ 12'h12c : ascii <= 8'h54; // T ++ 12'h13c : ascii <= 8'h55; // U ++ 12'h12a : ascii <= 8'h56; // V ++ 12'h11d : ascii <= 8'h57; // W ++ 12'h122 : ascii <= 8'h58; // X ++ 12'h135 : ascii <= 8'h59; // Y ++ 12'h11a : ascii <= 8'h5a; // Z ++ 12'h054 : ascii <= 8'h5b; // [ ++ 12'h05d : ascii <= 8'h5c; // \ ++ 12'h05b : ascii <= 8'h5d; // ] ++ 12'h136 : ascii <= 8'h5e; // ^ ++ 12'h14e : ascii <= 8'h5f; // _ ++ 12'h00e : ascii <= 8'h60; // ` ++ 12'h01c : ascii <= 8'h61; // a ++ 12'h032 : ascii <= 8'h62; // b ++ 12'h021 : ascii <= 8'h63; // c ++ 12'h023 : ascii <= 8'h64; // d ++ 12'h024 : ascii <= 8'h65; // e ++ 12'h02b : ascii <= 8'h66; // f ++ 12'h034 : ascii <= 8'h67; // g ++ 12'h033 : ascii <= 8'h68; // h ++ 12'h043 : ascii <= 8'h69; // i ++ 12'h03b : ascii <= 8'h6a; // j ++ 12'h042 : ascii <= 8'h6b; // k ++ 12'h04b : ascii <= 8'h6c; // l ++ 12'h03a : ascii <= 8'h6d; // m ++ 12'h031 : ascii <= 8'h6e; // n ++ 12'h044 : ascii <= 8'h6f; // o ++ 12'h04d : ascii <= 8'h70; // p ++ 12'h015 : ascii <= 8'h71; // q ++ 12'h02d : ascii <= 8'h72; // r ++ 12'h01b : ascii <= 8'h73; // s ++ 12'h02c : ascii <= 8'h74; // t ++ 12'h03c : ascii <= 8'h75; // u ++ 12'h02a : ascii <= 8'h76; // v ++ 12'h01d : ascii <= 8'h77; // w ++ 12'h022 : ascii <= 8'h78; // x ++ 12'h035 : ascii <= 8'h79; // y ++ 12'h01a : ascii <= 8'h7a; // z ++ 12'h154 : ascii <= 8'h7b; // { ++ 12'h15d : ascii <= 8'h7c; // | ++ 12'h15b : ascii <= 8'h7d; // } ++ 12'h10e : ascii <= 8'h7e; // ~ ++ 12'h?71 : ascii <= 8'h7f; // (Delete OR DEL on numeric keypad) ++ default : ascii <= 8'h2e; // '.' used for unlisted characters. ++ endcase ++end ++ ++ ++endmodule ++ ++//`undefine TOTAL_BITS ++//`undefine EXTEND_CODE ++//`undefine RELEASE_CODE ++//`undefine LEFT_SHIFT ++//`undefine RIGHT_SHIFT ++ diff --git a/de1/fpga-bbc-pq/master/line-endings.patch b/de1/fpga-bbc-pq/master/line-endings.patch new file mode 100644 index 0000000..dd090b6 --- /dev/null +++ b/de1/fpga-bbc-pq/master/line-endings.patch @@ -0,0 +1,17558 @@ +diff --git a/CII_Starter_pin_assignments.csv b/CII_Starter_pin_assignments.csv +index f46adb0..3e1f8de 100644 +--- a/CII_Starter_pin_assignments.csv ++++ b/CII_Starter_pin_assignments.csv +@@ -1,455 +1,455 @@ +-
+-# Note: The column header names should not be changed if you wish to import this .csv file into the Quartus II software.
+-
+-From,To,Assignment Name,Value,Enabled
+-,GPIO_0[0],Location,PIN_A13,Yes
+-,GPIO_0[1],Location,PIN_B13,Yes
+-,GPIO_0[2],Location,PIN_A14,Yes
+-,GPIO_0[3],Location,PIN_B14,Yes
+-,GPIO_0[4],Location,PIN_A15,Yes
+-,GPIO_0[5],Location,PIN_B15,Yes
+-,GPIO_0[6],Location,PIN_A16,Yes
+-,GPIO_0[7],Location,PIN_B16,Yes
+-,GPIO_0[8],Location,PIN_A17,Yes
+-,GPIO_0[9],Location,PIN_B17,Yes
+-,GPIO_0[10],Location,PIN_A18,Yes
+-,GPIO_0[11],Location,PIN_B18,Yes
+-,GPIO_0[12],Location,PIN_A19,Yes
+-,GPIO_0[13],Location,PIN_B19,Yes
+-,GPIO_0[14],Location,PIN_A20,Yes
+-,GPIO_0[15],Location,PIN_B20,Yes
+-,GPIO_0[16],Location,PIN_C21,Yes
+-,GPIO_0[17],Location,PIN_C22,Yes
+-,GPIO_0[18],Location,PIN_D21,Yes
+-,GPIO_0[19],Location,PIN_D22,Yes
+-,GPIO_0[20],Location,PIN_E21,Yes
+-,GPIO_0[21],Location,PIN_E22,Yes
+-,GPIO_0[22],Location,PIN_F21,Yes
+-,GPIO_0[23],Location,PIN_F22,Yes
+-,GPIO_0[24],Location,PIN_G21,Yes
+-,GPIO_0[25],Location,PIN_G22,Yes
+-,GPIO_0[26],Location,PIN_J21,Yes
+-,GPIO_0[27],Location,PIN_J22,Yes
+-,GPIO_0[28],Location,PIN_K21,Yes
+-,GPIO_0[29],Location,PIN_K22,Yes
+-,GPIO_0[30],Location,PIN_J19,Yes
+-,GPIO_0[31],Location,PIN_J20,Yes
+-,GPIO_0[32],Location,PIN_J18,Yes
+-,GPIO_0[33],Location,PIN_K20,Yes
+-,GPIO_0[34],Location,PIN_L19,Yes
+-,GPIO_0[35],Location,PIN_L18,Yes
+-,GPIO_1[0],Location,PIN_H12,Yes
+-,GPIO_1[1],Location,PIN_H13,Yes
+-,GPIO_1[2],Location,PIN_H14,Yes
+-,GPIO_1[3],Location,PIN_G15,Yes
+-,GPIO_1[4],Location,PIN_E14,Yes
+-,GPIO_1[5],Location,PIN_E15,Yes
+-,GPIO_1[6],Location,PIN_F15,Yes
+-,GPIO_1[7],Location,PIN_G16,Yes
+-,GPIO_1[8],Location,PIN_F12,Yes
+-,GPIO_1[9],Location,PIN_F13,Yes
+-,GPIO_1[10],Location,PIN_C14,Yes
+-,GPIO_1[11],Location,PIN_D14,Yes
+-,GPIO_1[12],Location,PIN_D15,Yes
+-,GPIO_1[13],Location,PIN_D16,Yes
+-,GPIO_1[14],Location,PIN_C17,Yes
+-,GPIO_1[15],Location,PIN_C18,Yes
+-,GPIO_1[16],Location,PIN_C19,Yes
+-,GPIO_1[17],Location,PIN_C20,Yes
+-,GPIO_1[18],Location,PIN_D19,Yes
+-,GPIO_1[19],Location,PIN_D20,Yes
+-,GPIO_1[20],Location,PIN_E20,Yes
+-,GPIO_1[21],Location,PIN_F20,Yes
+-,GPIO_1[22],Location,PIN_E19,Yes
+-,GPIO_1[23],Location,PIN_E18,Yes
+-,GPIO_1[24],Location,PIN_G20,Yes
+-,GPIO_1[25],Location,PIN_G18,Yes
+-,GPIO_1[26],Location,PIN_G17,Yes
+-,GPIO_1[27],Location,PIN_H17,Yes
+-,GPIO_1[28],Location,PIN_J15,Yes
+-,GPIO_1[29],Location,PIN_H18,Yes
+-,GPIO_1[30],Location,PIN_N22,Yes
+-,GPIO_1[31],Location,PIN_N21,Yes
+-,GPIO_1[32],Location,PIN_P15,Yes
+-,GPIO_1[33],Location,PIN_N15,Yes
+-,GPIO_1[34],Location,PIN_P17,Yes
+-,GPIO_1[35],Location,PIN_P18,Yes
+-,GPIO_0[0],I/O Standard,LVTTL,Yes
+-,GPIO_0[1],I/O Standard,LVTTL,Yes
+-,GPIO_0[2],I/O Standard,LVTTL,Yes
+-,GPIO_0[3],I/O Standard,LVTTL,Yes
+-,GPIO_0[4],I/O Standard,LVTTL,Yes
+-,GPIO_0[5],I/O Standard,LVTTL,Yes
+-,GPIO_0[6],I/O Standard,LVTTL,Yes
+-,GPIO_0[7],I/O Standard,LVTTL,Yes
+-,GPIO_0[8],I/O Standard,LVTTL,Yes
+-,GPIO_0[9],I/O Standard,LVTTL,Yes
+-,GPIO_0[10],I/O Standard,LVTTL,Yes
+-,GPIO_0[11],I/O Standard,LVTTL,Yes
+-,GPIO_0[12],I/O Standard,LVTTL,Yes
+-,GPIO_0[13],I/O Standard,LVTTL,Yes
+-,GPIO_0[14],I/O Standard,LVTTL,Yes
+-,GPIO_0[15],I/O Standard,LVTTL,Yes
+-,GPIO_0[16],I/O Standard,LVTTL,Yes
+-,GPIO_0[17],I/O Standard,LVTTL,Yes
+-,GPIO_0[18],I/O Standard,LVTTL,Yes
+-,GPIO_0[19],I/O Standard,LVTTL,Yes
+-,GPIO_0[20],I/O Standard,LVTTL,Yes
+-,GPIO_0[21],I/O Standard,LVTTL,Yes
+-,GPIO_0[22],I/O Standard,LVTTL,Yes
+-,GPIO_0[23],I/O Standard,LVTTL,Yes
+-,GPIO_0[24],I/O Standard,LVTTL,Yes
+-,GPIO_0[25],I/O Standard,LVTTL,Yes
+-,GPIO_0[26],I/O Standard,LVTTL,Yes
+-,GPIO_0[27],I/O Standard,LVTTL,Yes
+-,GPIO_0[28],I/O Standard,LVTTL,Yes
+-,GPIO_0[29],I/O Standard,LVTTL,Yes
+-,GPIO_0[30],I/O Standard,LVTTL,Yes
+-,GPIO_0[31],I/O Standard,LVTTL,Yes
+-,GPIO_0[32],I/O Standard,LVTTL,Yes
+-,GPIO_0[33],I/O Standard,LVTTL,Yes
+-,GPIO_0[34],I/O Standard,LVTTL,Yes
+-,GPIO_0[35],I/O Standard,LVTTL,Yes
+-,GPIO_1[0],I/O Standard,LVTTL,Yes
+-,GPIO_1[1],I/O Standard,LVTTL,Yes
+-,GPIO_1[2],I/O Standard,LVTTL,Yes
+-,GPIO_1[3],I/O Standard,LVTTL,Yes
+-,GPIO_1[4],I/O Standard,LVTTL,Yes
+-,GPIO_1[5],I/O Standard,LVTTL,Yes
+-,GPIO_1[6],I/O Standard,LVTTL,Yes
+-,GPIO_1[7],I/O Standard,LVTTL,Yes
+-,GPIO_1[8],I/O Standard,LVTTL,Yes
+-,GPIO_1[9],I/O Standard,LVTTL,Yes
+-,GPIO_1[10],I/O Standard,LVTTL,Yes
+-,GPIO_1[11],I/O Standard,LVTTL,Yes
+-,GPIO_1[12],I/O Standard,LVTTL,Yes
+-,GPIO_1[13],I/O Standard,LVTTL,Yes
+-,GPIO_1[14],I/O Standard,LVTTL,Yes
+-,GPIO_1[15],I/O Standard,LVTTL,Yes
+-,GPIO_1[16],I/O Standard,LVTTL,Yes
+-,GPIO_1[17],I/O Standard,LVTTL,Yes
+-,GPIO_1[18],I/O Standard,LVTTL,Yes
+-,GPIO_1[19],I/O Standard,LVTTL,Yes
+-,GPIO_1[20],I/O Standard,LVTTL,Yes
+-,GPIO_1[21],I/O Standard,LVTTL,Yes
+-,GPIO_1[22],I/O Standard,LVTTL,Yes
+-,GPIO_1[23],I/O Standard,LVTTL,Yes
+-,GPIO_1[24],I/O Standard,LVTTL,Yes
+-,GPIO_1[25],I/O Standard,LVTTL,Yes
+-,GPIO_1[26],I/O Standard,LVTTL,Yes
+-,GPIO_1[27],I/O Standard,LVTTL,Yes
+-,GPIO_1[28],I/O Standard,LVTTL,Yes
+-,GPIO_1[29],I/O Standard,LVTTL,Yes
+-,GPIO_1[30],I/O Standard,LVTTL,Yes
+-,GPIO_1[31],I/O Standard,LVTTL,Yes
+-,GPIO_1[32],I/O Standard,LVTTL,Yes
+-,GPIO_1[33],I/O Standard,LVTTL,Yes
+-,GPIO_1[34],I/O Standard,LVTTL,Yes
+-,GPIO_1[35],I/O Standard,LVTTL,Yes
+-,SW[0],Location,PIN_L22,Yes
+-,SW[1],Location,PIN_L21,Yes
+-,SW[2],Location,PIN_M22,Yes
+-,SW[3],Location,PIN_V12,Yes
+-,SW[4],Location,PIN_W12,Yes
+-,SW[5],Location,PIN_U12,Yes
+-,SW[6],Location,PIN_U11,Yes
+-,SW[7],Location,PIN_M2,Yes
+-,SW[8],Location,PIN_M1,Yes
+-,SW[9],Location,PIN_L2,Yes
+-,SW[0],I/O Standard,LVTTL,Yes
+-,SW[1],I/O Standard,LVTTL,Yes
+-,SW[2],I/O Standard,LVTTL,Yes
+-,SW[3],I/O Standard,LVTTL,Yes
+-,SW[4],I/O Standard,LVTTL,Yes
+-,SW[5],I/O Standard,LVTTL,Yes
+-,SW[6],I/O Standard,LVTTL,Yes
+-,SW[7],I/O Standard,LVTTL,Yes
+-,SW[8],I/O Standard,LVTTL,Yes
+-,SW[9],I/O Standard,LVTTL,Yes
+-,HEX0[0],Location,PIN_J2,Yes
+-,HEX0[1],Location,PIN_J1,Yes
+-,HEX0[2],Location,PIN_H2,Yes
+-,HEX0[3],Location,PIN_H1,Yes
+-,HEX0[4],Location,PIN_F2,Yes
+-,HEX0[5],Location,PIN_F1,Yes
+-,HEX0[6],Location,PIN_E2,Yes
+-,HEX1[0],Location,PIN_E1,Yes
+-,HEX1[1],Location,PIN_H6,Yes
+-,HEX1[2],Location,PIN_H5,Yes
+-,HEX1[3],Location,PIN_H4,Yes
+-,HEX1[4],Location,PIN_G3,Yes
+-,HEX1[5],Location,PIN_D2,Yes
+-,HEX1[6],Location,PIN_D1,Yes
+-,HEX2[0],Location,PIN_G5,Yes
+-,HEX2[1],Location,PIN_G6,Yes
+-,HEX2[2],Location,PIN_C2,Yes
+-,HEX2[3],Location,PIN_C1,Yes
+-,HEX2[4],Location,PIN_E3,Yes
+-,HEX2[5],Location,PIN_E4,Yes
+-,HEX2[6],Location,PIN_D3,Yes
+-,HEX3[0],Location,PIN_F4,Yes
+-,HEX3[1],Location,PIN_D5,Yes
+-,HEX3[2],Location,PIN_D6,Yes
+-,HEX3[3],Location,PIN_J4,Yes
+-,HEX3[4],Location,PIN_L8,Yes
+-,HEX3[5],Location,PIN_F3,Yes
+-,HEX3[6],Location,PIN_D4,Yes
+-,HEX0[0],I/O Standard,LVTTL,Yes
+-,HEX0[1],I/O Standard,LVTTL,Yes
+-,HEX0[2],I/O Standard,LVTTL,Yes
+-,HEX0[3],I/O Standard,LVTTL,Yes
+-,HEX0[4],I/O Standard,LVTTL,Yes
+-,HEX0[5],I/O Standard,LVTTL,Yes
+-,HEX0[6],I/O Standard,LVTTL,Yes
+-,HEX1[0],I/O Standard,LVTTL,Yes
+-,HEX1[1],I/O Standard,LVTTL,Yes
+-,HEX1[2],I/O Standard,LVTTL,Yes
+-,HEX1[3],I/O Standard,LVTTL,Yes
+-,HEX1[4],I/O Standard,LVTTL,Yes
+-,HEX1[5],I/O Standard,LVTTL,Yes
+-,HEX1[6],I/O Standard,LVTTL,Yes
+-,HEX2[0],I/O Standard,LVTTL,Yes
+-,HEX2[1],I/O Standard,LVTTL,Yes
+-,HEX2[2],I/O Standard,LVTTL,Yes
+-,HEX2[3],I/O Standard,LVTTL,Yes
+-,HEX2[4],I/O Standard,LVTTL,Yes
+-,HEX2[5],I/O Standard,LVTTL,Yes
+-,HEX2[6],I/O Standard,LVTTL,Yes
+-,HEX3[0],I/O Standard,LVTTL,Yes
+-,HEX3[1],I/O Standard,LVTTL,Yes
+-,HEX3[2],I/O Standard,LVTTL,Yes
+-,HEX3[3],I/O Standard,LVTTL,Yes
+-,HEX3[4],I/O Standard,LVTTL,Yes
+-,HEX3[5],I/O Standard,LVTTL,Yes
+-,HEX3[6],I/O Standard,LVTTL,Yes
+-,KEY[0],Location,PIN_R22,Yes
+-,KEY[1],Location,PIN_R21,Yes
+-,KEY[2],Location,PIN_T22,Yes
+-,KEY[3],Location,PIN_T21,Yes
+-,LEDR[0],Location,PIN_R20,Yes
+-,LEDR[1],Location,PIN_R19,Yes
+-,LEDR[2],Location,PIN_U19,Yes
+-,LEDR[3],Location,PIN_Y19,Yes
+-,LEDR[4],Location,PIN_T18,Yes
+-,LEDR[5],Location,PIN_V19,Yes
+-,LEDR[6],Location,PIN_Y18,Yes
+-,LEDR[7],Location,PIN_U18,Yes
+-,LEDR[8],Location,PIN_R18,Yes
+-,LEDR[9],Location,PIN_R17,Yes
+-,LEDG[0],Location,PIN_U22,Yes
+-,LEDG[1],Location,PIN_U21,Yes
+-,LEDG[2],Location,PIN_V22,Yes
+-,LEDG[3],Location,PIN_V21,Yes
+-,LEDG[4],Location,PIN_W22,Yes
+-,LEDG[5],Location,PIN_W21,Yes
+-,LEDG[6],Location,PIN_Y22,Yes
+-,LEDG[7],Location,PIN_Y21,Yes
+-,KEY[0],I/O Standard,LVTTL,Yes
+-,KEY[1],I/O Standard,LVTTL,Yes
+-,KEY[2],I/O Standard,LVTTL,Yes
+-,KEY[3],I/O Standard,LVTTL,Yes
+-,LEDR[0],I/O Standard,LVTTL,Yes
+-,LEDR[1],I/O Standard,LVTTL,Yes
+-,LEDR[2],I/O Standard,LVTTL,Yes
+-,LEDR[3],I/O Standard,LVTTL,Yes
+-,LEDR[4],I/O Standard,LVTTL,Yes
+-,LEDR[5],I/O Standard,LVTTL,Yes
+-,LEDR[6],I/O Standard,LVTTL,Yes
+-,LEDR[7],I/O Standard,LVTTL,Yes
+-,LEDR[8],I/O Standard,LVTTL,Yes
+-,LEDR[9],I/O Standard,LVTTL,Yes
+-,LEDG[0],I/O Standard,LVTTL,Yes
+-,LEDG[1],I/O Standard,LVTTL,Yes
+-,LEDG[2],I/O Standard,LVTTL,Yes
+-,LEDG[3],I/O Standard,LVTTL,Yes
+-,LEDG[4],I/O Standard,LVTTL,Yes
+-,LEDG[5],I/O Standard,LVTTL,Yes
+-,LEDG[6],I/O Standard,LVTTL,Yes
+-,LEDG[7],I/O Standard,LVTTL,Yes
+-,CLOCK_27[0],Location,PIN_D12,Yes
+-,CLOCK_27[1],Location,PIN_E12,Yes
+-,CLOCK_24[0],Location,PIN_B12,Yes
+-,CLOCK_24[1],Location,PIN_A12,Yes
+-,CLOCK_50,Location,PIN_L1,Yes
+-,EXT_CLOCK,Location,PIN_M21,Yes
+-,CLOCK_27[1],I/O Standard,LVTTL,Yes
+-,CLOCK_24[0],I/O Standard,LVTTL,Yes
+-,CLOCK_24[1],I/O Standard,LVTTL,Yes
+-,CLOCK_50,I/O Standard,LVTTL,Yes
+-,EXT_CLOCK,I/O Standard,LVTTL,Yes
+-,PS2_CLK,Location,PIN_H15,Yes
+-,PS2_DAT,Location,PIN_J14,Yes
+-,UART_RXD,Location,PIN_F14,Yes
+-,UART_TXD,Location,PIN_G12,Yes
+-,PS2_CLK,I/O Standard,LVTTL,Yes
+-,PS2_DAT,I/O Standard,LVTTL,Yes
+-,UART_RXD,I/O Standard,LVTTL,Yes
+-,UART_TXD,I/O Standard,LVTTL,Yes
+-,TDI,Location,PIN_E8,Yes
+-,TCS,Location,PIN_D8,Yes
+-,TCK,Location,PIN_C7,Yes
+-,TDO,Location,PIN_D7,Yes
+-,TDI,I/O Standard,LVTTL,Yes
+-,TCS,I/O Standard,LVTTL,Yes
+-,TCK,I/O Standard,LVTTL,Yes
+-,TDO,I/O Standard,LVTTL,Yes
+-,VGA_R[0],Location,PIN_D9,Yes
+-,VGA_R[1],Location,PIN_C9,Yes
+-,VGA_R[2],Location,PIN_A7,Yes
+-,VGA_R[3],Location,PIN_B7,Yes
+-,VGA_G[0],Location,PIN_B8,Yes
+-,VGA_G[1],Location,PIN_C10,Yes
+-,VGA_G[2],Location,PIN_B9,Yes
+-,VGA_G[3],Location,PIN_A8,Yes
+-,VGA_B[0],Location,PIN_A9,Yes
+-,VGA_B[1],Location,PIN_D11,Yes
+-,VGA_B[2],Location,PIN_A10,Yes
+-,VGA_B[3],Location,PIN_B10,Yes
+-,VGA_HS,Location,PIN_A11,Yes
+-,VGA_VS,Location,PIN_B11,Yes
+-,VGA_R[0],I/O Standard,LVTTL,Yes
+-,VGA_R[1],I/O Standard,LVTTL,Yes
+-,VGA_R[2],I/O Standard,LVTTL,Yes
+-,VGA_R[3],I/O Standard,LVTTL,Yes
+-,VGA_G[0],I/O Standard,LVTTL,Yes
+-,VGA_G[1],I/O Standard,LVTTL,Yes
+-,VGA_G[2],I/O Standard,LVTTL,Yes
+-,VGA_G[3],I/O Standard,LVTTL,Yes
+-,VGA_B[0],I/O Standard,LVTTL,Yes
+-,VGA_B[1],I/O Standard,LVTTL,Yes
+-,VGA_B[2],I/O Standard,LVTTL,Yes
+-,VGA_B[3],I/O Standard,LVTTL,Yes
+-,VGA_HS,I/O Standard,LVTTL,Yes
+-,VGA_VS,I/O Standard,LVTTL,Yes
+-,I2C_SCLK,Location,PIN_A3,Yes
+-,I2C_SDAT,Location,PIN_B3,Yes
+-,AUD_ADCLRCK,Location,PIN_A6,Yes
+-,AUD_ADCDAT,Location,PIN_B6,Yes
+-,AUD_DACLRCK,Location,PIN_A5,Yes
+-,AUD_DACDAT,Location,PIN_B5,Yes
+-,AUD_XCK,Location,PIN_B4,Yes
+-,AUD_BCLK,Location,PIN_A4,Yes
+-,I2C_SCLK,I/O Standard,LVTTL,Yes
+-,I2C_SDAT,I/O Standard,LVTTL,Yes
+-,AUD_ADCLRCK,I/O Standard,LVTTL,Yes
+-,AUD_ADCDAT,I/O Standard,LVTTL,Yes
+-,AUD_DACLRCK,I/O Standard,LVTTL,Yes
+-,AUD_DACDAT,I/O Standard,LVTTL,Yes
+-,AUD_XCK,I/O Standard,LVTTL,Yes
+-,AUD_BCLK,I/O Standard,LVTTL,Yes
+-,DRAM_ADDR[0],Location,PIN_W4,Yes
+-,DRAM_ADDR[1],Location,PIN_W5,Yes
+-,DRAM_ADDR[2],Location,PIN_Y3,Yes
+-,DRAM_ADDR[3],Location,PIN_Y4,Yes
+-,DRAM_ADDR[4],Location,PIN_R6,Yes
+-,DRAM_ADDR[5],Location,PIN_R5,Yes
+-,DRAM_ADDR[6],Location,PIN_P6,Yes
+-,DRAM_ADDR[7],Location,PIN_P5,Yes
+-,DRAM_ADDR[8],Location,PIN_P3,Yes
+-,DRAM_ADDR[9],Location,PIN_N4,Yes
+-,DRAM_ADDR[10],Location,PIN_W3,Yes
+-,DRAM_ADDR[11],Location,PIN_N6,Yes
+-,DRAM_BA_0,Location,PIN_U3,Yes
+-,DRAM_BA_1,Location,PIN_V4,Yes
+-,DRAM_CAS_N,Location,PIN_T3,Yes
+-,DRAM_CKE,Location,PIN_N3,Yes
+-,DRAM_CLK,Location,PIN_U4,Yes
+-,DRAM_CS_N,Location,PIN_T6,Yes
+-,DRAM_DQ[0],Location,PIN_U1,Yes
+-,DRAM_DQ[1],Location,PIN_U2,Yes
+-,DRAM_DQ[2],Location,PIN_V1,Yes
+-,DRAM_DQ[3],Location,PIN_V2,Yes
+-,DRAM_DQ[4],Location,PIN_W1,Yes
+-,DRAM_DQ[5],Location,PIN_W2,Yes
+-,DRAM_DQ[6],Location,PIN_Y1,Yes
+-,DRAM_DQ[7],Location,PIN_Y2,Yes
+-,DRAM_DQ[8],Location,PIN_N1,Yes
+-,DRAM_DQ[9],Location,PIN_N2,Yes
+-,DRAM_DQ[10],Location,PIN_P1,Yes
+-,DRAM_DQ[11],Location,PIN_P2,Yes
+-,DRAM_DQ[12],Location,PIN_R1,Yes
+-,DRAM_DQ[13],Location,PIN_R2,Yes
+-,DRAM_DQ[14],Location,PIN_T1,Yes
+-,DRAM_DQ[15],Location,PIN_T2,Yes
+-,DRAM_LDQM,Location,PIN_R7,Yes
+-,DRAM_RAS_N,Location,PIN_T5,Yes
+-,DRAM_UDQM,Location,PIN_M5,Yes
+-,DRAM_WE_N,Location,PIN_R8,Yes
+-,FL_ADDR[0],Location,PIN_AB20,Yes
+-,FL_ADDR[1],Location,PIN_AA14,Yes
+-,FL_ADDR[2],Location,PIN_Y16,Yes
+-,FL_ADDR[3],Location,PIN_R15,Yes
+-,FL_ADDR[4],Location,PIN_T15,Yes
+-,FL_ADDR[5],Location,PIN_U15,Yes
+-,FL_ADDR[6],Location,PIN_V15,Yes
+-,FL_ADDR[7],Location,PIN_W15,Yes
+-,FL_ADDR[8],Location,PIN_R14,Yes
+-,FL_ADDR[9],Location,PIN_Y13,Yes
+-,FL_ADDR[10],Location,PIN_R12,Yes
+-,FL_ADDR[11],Location,PIN_T12,Yes
+-,FL_ADDR[12],Location,PIN_AB14,Yes
+-,FL_ADDR[13],Location,PIN_AA13,Yes
+-,FL_ADDR[14],Location,PIN_AB13,Yes
+-,FL_ADDR[15],Location,PIN_AA12,Yes
+-,FL_ADDR[16],Location,PIN_AB12,Yes
+-,FL_ADDR[17],Location,PIN_AA20,Yes
+-,FL_ADDR[18],Location,PIN_U14,Yes
+-,FL_ADDR[19],Location,PIN_V14,Yes
+-,FL_ADDR[20],Location,PIN_U13,Yes
+-,FL_ADDR[21],Location,PIN_R13,Yes
+-,FL_DQ[0],Location,PIN_AB16,Yes
+-,FL_DQ[1],Location,PIN_AA16,Yes
+-,FL_DQ[2],Location,PIN_AB17,Yes
+-,FL_DQ[3],Location,PIN_AA17,Yes
+-,FL_DQ[4],Location,PIN_AB18,Yes
+-,FL_DQ[5],Location,PIN_AA18,Yes
+-,FL_DQ[6],Location,PIN_AB19,Yes
+-,FL_DQ[7],Location,PIN_AA19,Yes
+-,FL_OE_N,Location,PIN_AA15,Yes
+-,FL_RST_N,Location,PIN_W14,Yes
+-,FL_WE_N,Location,PIN_Y14,Yes
+-,FL_CE_N,Location,PIN_AB15,Yes
+-,SRAM_ADDR[0],Location,PIN_AA3,Yes
+-,SRAM_ADDR[1],Location,PIN_AB3,Yes
+-,SRAM_ADDR[2],Location,PIN_AA4,Yes
+-,SRAM_ADDR[3],Location,PIN_AB4,Yes
+-,SRAM_ADDR[4],Location,PIN_AA5,Yes
+-,SRAM_ADDR[5],Location,PIN_AB10,Yes
+-,SRAM_ADDR[6],Location,PIN_AA11,Yes
+-,SRAM_ADDR[7],Location,PIN_AB11,Yes
+-,SRAM_ADDR[8],Location,PIN_V11,Yes
+-,SRAM_ADDR[9],Location,PIN_W11,Yes
+-,SRAM_ADDR[10],Location,PIN_R11,Yes
+-,SRAM_ADDR[11],Location,PIN_T11,Yes
+-,SRAM_ADDR[12],Location,PIN_Y10,Yes
+-,SRAM_ADDR[13],Location,PIN_U10,Yes
+-,SRAM_ADDR[14],Location,PIN_R10,Yes
+-,SRAM_ADDR[15],Location,PIN_T7,Yes
+-,SRAM_ADDR[16],Location,PIN_Y6,Yes
+-,SRAM_ADDR[17],Location,PIN_Y5,Yes
+-,SRAM_CE_N,Location,PIN_AB5,Yes
+-,SRAM_DQ[0],Location,PIN_AA6,Yes
+-,SRAM_DQ[1],Location,PIN_AB6,Yes
+-,SRAM_DQ[2],Location,PIN_AA7,Yes
+-,SRAM_DQ[3],Location,PIN_AB7,Yes
+-,SRAM_DQ[4],Location,PIN_AA8,Yes
+-,SRAM_DQ[5],Location,PIN_AB8,Yes
+-,SRAM_DQ[6],Location,PIN_AA9,Yes
+-,SRAM_DQ[7],Location,PIN_AB9,Yes
+-,SRAM_DQ[8],Location,PIN_Y9,Yes
+-,SRAM_DQ[9],Location,PIN_W9,Yes
+-,SRAM_DQ[10],Location,PIN_V9,Yes
+-,SRAM_DQ[11],Location,PIN_U9,Yes
+-,SRAM_DQ[12],Location,PIN_R9,Yes
+-,SRAM_DQ[13],Location,PIN_W8,Yes
+-,SRAM_DQ[14],Location,PIN_V8,Yes
+-,SRAM_DQ[15],Location,PIN_U8,Yes
+-,SRAM_LB_N,Location,PIN_Y7,Yes
+-,SRAM_OE_N,Location,PIN_T8,Yes
+-,SRAM_UB_N,Location,PIN_W7,Yes
+-,SRAM_WE_N,Location,PIN_AA10,Yes
+-,SD_nCS,Location,PIN_U20,Yes
+-,SD_MOSI,Location,PIN_Y20,Yes
+-,SD_SCLK,Location,PIN_V20,Yes
+-,SD_MISO,Location,PIN_W20,Yes
+-
++ ++# Note: The column header names should not be changed if you wish to import this .csv file into the Quartus II software. ++ ++From,To,Assignment Name,Value,Enabled ++,GPIO_0[0],Location,PIN_A13,Yes ++,GPIO_0[1],Location,PIN_B13,Yes ++,GPIO_0[2],Location,PIN_A14,Yes ++,GPIO_0[3],Location,PIN_B14,Yes ++,GPIO_0[4],Location,PIN_A15,Yes ++,GPIO_0[5],Location,PIN_B15,Yes ++,GPIO_0[6],Location,PIN_A16,Yes ++,GPIO_0[7],Location,PIN_B16,Yes ++,GPIO_0[8],Location,PIN_A17,Yes ++,GPIO_0[9],Location,PIN_B17,Yes ++,GPIO_0[10],Location,PIN_A18,Yes ++,GPIO_0[11],Location,PIN_B18,Yes ++,GPIO_0[12],Location,PIN_A19,Yes ++,GPIO_0[13],Location,PIN_B19,Yes ++,GPIO_0[14],Location,PIN_A20,Yes ++,GPIO_0[15],Location,PIN_B20,Yes ++,GPIO_0[16],Location,PIN_C21,Yes ++,GPIO_0[17],Location,PIN_C22,Yes ++,GPIO_0[18],Location,PIN_D21,Yes ++,GPIO_0[19],Location,PIN_D22,Yes ++,GPIO_0[20],Location,PIN_E21,Yes ++,GPIO_0[21],Location,PIN_E22,Yes ++,GPIO_0[22],Location,PIN_F21,Yes ++,GPIO_0[23],Location,PIN_F22,Yes ++,GPIO_0[24],Location,PIN_G21,Yes ++,GPIO_0[25],Location,PIN_G22,Yes ++,GPIO_0[26],Location,PIN_J21,Yes ++,GPIO_0[27],Location,PIN_J22,Yes ++,GPIO_0[28],Location,PIN_K21,Yes ++,GPIO_0[29],Location,PIN_K22,Yes ++,GPIO_0[30],Location,PIN_J19,Yes ++,GPIO_0[31],Location,PIN_J20,Yes ++,GPIO_0[32],Location,PIN_J18,Yes ++,GPIO_0[33],Location,PIN_K20,Yes ++,GPIO_0[34],Location,PIN_L19,Yes ++,GPIO_0[35],Location,PIN_L18,Yes ++,GPIO_1[0],Location,PIN_H12,Yes ++,GPIO_1[1],Location,PIN_H13,Yes ++,GPIO_1[2],Location,PIN_H14,Yes ++,GPIO_1[3],Location,PIN_G15,Yes ++,GPIO_1[4],Location,PIN_E14,Yes ++,GPIO_1[5],Location,PIN_E15,Yes ++,GPIO_1[6],Location,PIN_F15,Yes ++,GPIO_1[7],Location,PIN_G16,Yes ++,GPIO_1[8],Location,PIN_F12,Yes ++,GPIO_1[9],Location,PIN_F13,Yes ++,GPIO_1[10],Location,PIN_C14,Yes ++,GPIO_1[11],Location,PIN_D14,Yes ++,GPIO_1[12],Location,PIN_D15,Yes ++,GPIO_1[13],Location,PIN_D16,Yes ++,GPIO_1[14],Location,PIN_C17,Yes ++,GPIO_1[15],Location,PIN_C18,Yes ++,GPIO_1[16],Location,PIN_C19,Yes ++,GPIO_1[17],Location,PIN_C20,Yes ++,GPIO_1[18],Location,PIN_D19,Yes ++,GPIO_1[19],Location,PIN_D20,Yes ++,GPIO_1[20],Location,PIN_E20,Yes ++,GPIO_1[21],Location,PIN_F20,Yes ++,GPIO_1[22],Location,PIN_E19,Yes ++,GPIO_1[23],Location,PIN_E18,Yes ++,GPIO_1[24],Location,PIN_G20,Yes ++,GPIO_1[25],Location,PIN_G18,Yes ++,GPIO_1[26],Location,PIN_G17,Yes ++,GPIO_1[27],Location,PIN_H17,Yes ++,GPIO_1[28],Location,PIN_J15,Yes ++,GPIO_1[29],Location,PIN_H18,Yes ++,GPIO_1[30],Location,PIN_N22,Yes ++,GPIO_1[31],Location,PIN_N21,Yes ++,GPIO_1[32],Location,PIN_P15,Yes ++,GPIO_1[33],Location,PIN_N15,Yes ++,GPIO_1[34],Location,PIN_P17,Yes ++,GPIO_1[35],Location,PIN_P18,Yes ++,GPIO_0[0],I/O Standard,LVTTL,Yes ++,GPIO_0[1],I/O Standard,LVTTL,Yes ++,GPIO_0[2],I/O Standard,LVTTL,Yes ++,GPIO_0[3],I/O Standard,LVTTL,Yes ++,GPIO_0[4],I/O Standard,LVTTL,Yes ++,GPIO_0[5],I/O Standard,LVTTL,Yes ++,GPIO_0[6],I/O Standard,LVTTL,Yes ++,GPIO_0[7],I/O Standard,LVTTL,Yes ++,GPIO_0[8],I/O Standard,LVTTL,Yes ++,GPIO_0[9],I/O Standard,LVTTL,Yes ++,GPIO_0[10],I/O Standard,LVTTL,Yes ++,GPIO_0[11],I/O Standard,LVTTL,Yes ++,GPIO_0[12],I/O Standard,LVTTL,Yes ++,GPIO_0[13],I/O Standard,LVTTL,Yes ++,GPIO_0[14],I/O Standard,LVTTL,Yes ++,GPIO_0[15],I/O Standard,LVTTL,Yes ++,GPIO_0[16],I/O Standard,LVTTL,Yes ++,GPIO_0[17],I/O Standard,LVTTL,Yes ++,GPIO_0[18],I/O Standard,LVTTL,Yes ++,GPIO_0[19],I/O Standard,LVTTL,Yes ++,GPIO_0[20],I/O Standard,LVTTL,Yes ++,GPIO_0[21],I/O Standard,LVTTL,Yes ++,GPIO_0[22],I/O Standard,LVTTL,Yes ++,GPIO_0[23],I/O Standard,LVTTL,Yes ++,GPIO_0[24],I/O Standard,LVTTL,Yes ++,GPIO_0[25],I/O Standard,LVTTL,Yes ++,GPIO_0[26],I/O Standard,LVTTL,Yes ++,GPIO_0[27],I/O Standard,LVTTL,Yes ++,GPIO_0[28],I/O Standard,LVTTL,Yes ++,GPIO_0[29],I/O Standard,LVTTL,Yes ++,GPIO_0[30],I/O Standard,LVTTL,Yes ++,GPIO_0[31],I/O Standard,LVTTL,Yes ++,GPIO_0[32],I/O Standard,LVTTL,Yes ++,GPIO_0[33],I/O Standard,LVTTL,Yes ++,GPIO_0[34],I/O Standard,LVTTL,Yes ++,GPIO_0[35],I/O Standard,LVTTL,Yes ++,GPIO_1[0],I/O Standard,LVTTL,Yes ++,GPIO_1[1],I/O Standard,LVTTL,Yes ++,GPIO_1[2],I/O Standard,LVTTL,Yes ++,GPIO_1[3],I/O Standard,LVTTL,Yes ++,GPIO_1[4],I/O Standard,LVTTL,Yes ++,GPIO_1[5],I/O Standard,LVTTL,Yes ++,GPIO_1[6],I/O Standard,LVTTL,Yes ++,GPIO_1[7],I/O Standard,LVTTL,Yes ++,GPIO_1[8],I/O Standard,LVTTL,Yes ++,GPIO_1[9],I/O Standard,LVTTL,Yes ++,GPIO_1[10],I/O Standard,LVTTL,Yes ++,GPIO_1[11],I/O Standard,LVTTL,Yes ++,GPIO_1[12],I/O Standard,LVTTL,Yes ++,GPIO_1[13],I/O Standard,LVTTL,Yes ++,GPIO_1[14],I/O Standard,LVTTL,Yes ++,GPIO_1[15],I/O Standard,LVTTL,Yes ++,GPIO_1[16],I/O Standard,LVTTL,Yes ++,GPIO_1[17],I/O Standard,LVTTL,Yes ++,GPIO_1[18],I/O Standard,LVTTL,Yes ++,GPIO_1[19],I/O Standard,LVTTL,Yes ++,GPIO_1[20],I/O Standard,LVTTL,Yes ++,GPIO_1[21],I/O Standard,LVTTL,Yes ++,GPIO_1[22],I/O Standard,LVTTL,Yes ++,GPIO_1[23],I/O Standard,LVTTL,Yes ++,GPIO_1[24],I/O Standard,LVTTL,Yes ++,GPIO_1[25],I/O Standard,LVTTL,Yes ++,GPIO_1[26],I/O Standard,LVTTL,Yes ++,GPIO_1[27],I/O Standard,LVTTL,Yes ++,GPIO_1[28],I/O Standard,LVTTL,Yes ++,GPIO_1[29],I/O Standard,LVTTL,Yes ++,GPIO_1[30],I/O Standard,LVTTL,Yes ++,GPIO_1[31],I/O Standard,LVTTL,Yes ++,GPIO_1[32],I/O Standard,LVTTL,Yes ++,GPIO_1[33],I/O Standard,LVTTL,Yes ++,GPIO_1[34],I/O Standard,LVTTL,Yes ++,GPIO_1[35],I/O Standard,LVTTL,Yes ++,SW[0],Location,PIN_L22,Yes ++,SW[1],Location,PIN_L21,Yes ++,SW[2],Location,PIN_M22,Yes ++,SW[3],Location,PIN_V12,Yes ++,SW[4],Location,PIN_W12,Yes ++,SW[5],Location,PIN_U12,Yes ++,SW[6],Location,PIN_U11,Yes ++,SW[7],Location,PIN_M2,Yes ++,SW[8],Location,PIN_M1,Yes ++,SW[9],Location,PIN_L2,Yes ++,SW[0],I/O Standard,LVTTL,Yes ++,SW[1],I/O Standard,LVTTL,Yes ++,SW[2],I/O Standard,LVTTL,Yes ++,SW[3],I/O Standard,LVTTL,Yes ++,SW[4],I/O Standard,LVTTL,Yes ++,SW[5],I/O Standard,LVTTL,Yes ++,SW[6],I/O Standard,LVTTL,Yes ++,SW[7],I/O Standard,LVTTL,Yes ++,SW[8],I/O Standard,LVTTL,Yes ++,SW[9],I/O Standard,LVTTL,Yes ++,HEX0[0],Location,PIN_J2,Yes ++,HEX0[1],Location,PIN_J1,Yes ++,HEX0[2],Location,PIN_H2,Yes ++,HEX0[3],Location,PIN_H1,Yes ++,HEX0[4],Location,PIN_F2,Yes ++,HEX0[5],Location,PIN_F1,Yes ++,HEX0[6],Location,PIN_E2,Yes ++,HEX1[0],Location,PIN_E1,Yes ++,HEX1[1],Location,PIN_H6,Yes ++,HEX1[2],Location,PIN_H5,Yes ++,HEX1[3],Location,PIN_H4,Yes ++,HEX1[4],Location,PIN_G3,Yes ++,HEX1[5],Location,PIN_D2,Yes ++,HEX1[6],Location,PIN_D1,Yes ++,HEX2[0],Location,PIN_G5,Yes ++,HEX2[1],Location,PIN_G6,Yes ++,HEX2[2],Location,PIN_C2,Yes ++,HEX2[3],Location,PIN_C1,Yes ++,HEX2[4],Location,PIN_E3,Yes ++,HEX2[5],Location,PIN_E4,Yes ++,HEX2[6],Location,PIN_D3,Yes ++,HEX3[0],Location,PIN_F4,Yes ++,HEX3[1],Location,PIN_D5,Yes ++,HEX3[2],Location,PIN_D6,Yes ++,HEX3[3],Location,PIN_J4,Yes ++,HEX3[4],Location,PIN_L8,Yes ++,HEX3[5],Location,PIN_F3,Yes ++,HEX3[6],Location,PIN_D4,Yes ++,HEX0[0],I/O Standard,LVTTL,Yes ++,HEX0[1],I/O Standard,LVTTL,Yes ++,HEX0[2],I/O Standard,LVTTL,Yes ++,HEX0[3],I/O Standard,LVTTL,Yes ++,HEX0[4],I/O Standard,LVTTL,Yes ++,HEX0[5],I/O Standard,LVTTL,Yes ++,HEX0[6],I/O Standard,LVTTL,Yes ++,HEX1[0],I/O Standard,LVTTL,Yes ++,HEX1[1],I/O Standard,LVTTL,Yes ++,HEX1[2],I/O Standard,LVTTL,Yes ++,HEX1[3],I/O Standard,LVTTL,Yes ++,HEX1[4],I/O Standard,LVTTL,Yes ++,HEX1[5],I/O Standard,LVTTL,Yes ++,HEX1[6],I/O Standard,LVTTL,Yes ++,HEX2[0],I/O Standard,LVTTL,Yes ++,HEX2[1],I/O Standard,LVTTL,Yes ++,HEX2[2],I/O Standard,LVTTL,Yes ++,HEX2[3],I/O Standard,LVTTL,Yes ++,HEX2[4],I/O Standard,LVTTL,Yes ++,HEX2[5],I/O Standard,LVTTL,Yes ++,HEX2[6],I/O Standard,LVTTL,Yes ++,HEX3[0],I/O Standard,LVTTL,Yes ++,HEX3[1],I/O Standard,LVTTL,Yes ++,HEX3[2],I/O Standard,LVTTL,Yes ++,HEX3[3],I/O Standard,LVTTL,Yes ++,HEX3[4],I/O Standard,LVTTL,Yes ++,HEX3[5],I/O Standard,LVTTL,Yes ++,HEX3[6],I/O Standard,LVTTL,Yes ++,KEY[0],Location,PIN_R22,Yes ++,KEY[1],Location,PIN_R21,Yes ++,KEY[2],Location,PIN_T22,Yes ++,KEY[3],Location,PIN_T21,Yes ++,LEDR[0],Location,PIN_R20,Yes ++,LEDR[1],Location,PIN_R19,Yes ++,LEDR[2],Location,PIN_U19,Yes ++,LEDR[3],Location,PIN_Y19,Yes ++,LEDR[4],Location,PIN_T18,Yes ++,LEDR[5],Location,PIN_V19,Yes ++,LEDR[6],Location,PIN_Y18,Yes ++,LEDR[7],Location,PIN_U18,Yes ++,LEDR[8],Location,PIN_R18,Yes ++,LEDR[9],Location,PIN_R17,Yes ++,LEDG[0],Location,PIN_U22,Yes ++,LEDG[1],Location,PIN_U21,Yes ++,LEDG[2],Location,PIN_V22,Yes ++,LEDG[3],Location,PIN_V21,Yes ++,LEDG[4],Location,PIN_W22,Yes ++,LEDG[5],Location,PIN_W21,Yes ++,LEDG[6],Location,PIN_Y22,Yes ++,LEDG[7],Location,PIN_Y21,Yes ++,KEY[0],I/O Standard,LVTTL,Yes ++,KEY[1],I/O Standard,LVTTL,Yes ++,KEY[2],I/O Standard,LVTTL,Yes ++,KEY[3],I/O Standard,LVTTL,Yes ++,LEDR[0],I/O Standard,LVTTL,Yes ++,LEDR[1],I/O Standard,LVTTL,Yes ++,LEDR[2],I/O Standard,LVTTL,Yes ++,LEDR[3],I/O Standard,LVTTL,Yes ++,LEDR[4],I/O Standard,LVTTL,Yes ++,LEDR[5],I/O Standard,LVTTL,Yes ++,LEDR[6],I/O Standard,LVTTL,Yes ++,LEDR[7],I/O Standard,LVTTL,Yes ++,LEDR[8],I/O Standard,LVTTL,Yes ++,LEDR[9],I/O Standard,LVTTL,Yes ++,LEDG[0],I/O Standard,LVTTL,Yes ++,LEDG[1],I/O Standard,LVTTL,Yes ++,LEDG[2],I/O Standard,LVTTL,Yes ++,LEDG[3],I/O Standard,LVTTL,Yes ++,LEDG[4],I/O Standard,LVTTL,Yes ++,LEDG[5],I/O Standard,LVTTL,Yes ++,LEDG[6],I/O Standard,LVTTL,Yes ++,LEDG[7],I/O Standard,LVTTL,Yes ++,CLOCK_27[0],Location,PIN_D12,Yes ++,CLOCK_27[1],Location,PIN_E12,Yes ++,CLOCK_24[0],Location,PIN_B12,Yes ++,CLOCK_24[1],Location,PIN_A12,Yes ++,CLOCK_50,Location,PIN_L1,Yes ++,EXT_CLOCK,Location,PIN_M21,Yes ++,CLOCK_27[1],I/O Standard,LVTTL,Yes ++,CLOCK_24[0],I/O Standard,LVTTL,Yes ++,CLOCK_24[1],I/O Standard,LVTTL,Yes ++,CLOCK_50,I/O Standard,LVTTL,Yes ++,EXT_CLOCK,I/O Standard,LVTTL,Yes ++,PS2_CLK,Location,PIN_H15,Yes ++,PS2_DAT,Location,PIN_J14,Yes ++,UART_RXD,Location,PIN_F14,Yes ++,UART_TXD,Location,PIN_G12,Yes ++,PS2_CLK,I/O Standard,LVTTL,Yes ++,PS2_DAT,I/O Standard,LVTTL,Yes ++,UART_RXD,I/O Standard,LVTTL,Yes ++,UART_TXD,I/O Standard,LVTTL,Yes ++,TDI,Location,PIN_E8,Yes ++,TCS,Location,PIN_D8,Yes ++,TCK,Location,PIN_C7,Yes ++,TDO,Location,PIN_D7,Yes ++,TDI,I/O Standard,LVTTL,Yes ++,TCS,I/O Standard,LVTTL,Yes ++,TCK,I/O Standard,LVTTL,Yes ++,TDO,I/O Standard,LVTTL,Yes ++,VGA_R[0],Location,PIN_D9,Yes ++,VGA_R[1],Location,PIN_C9,Yes ++,VGA_R[2],Location,PIN_A7,Yes ++,VGA_R[3],Location,PIN_B7,Yes ++,VGA_G[0],Location,PIN_B8,Yes ++,VGA_G[1],Location,PIN_C10,Yes ++,VGA_G[2],Location,PIN_B9,Yes ++,VGA_G[3],Location,PIN_A8,Yes ++,VGA_B[0],Location,PIN_A9,Yes ++,VGA_B[1],Location,PIN_D11,Yes ++,VGA_B[2],Location,PIN_A10,Yes ++,VGA_B[3],Location,PIN_B10,Yes ++,VGA_HS,Location,PIN_A11,Yes ++,VGA_VS,Location,PIN_B11,Yes ++,VGA_R[0],I/O Standard,LVTTL,Yes ++,VGA_R[1],I/O Standard,LVTTL,Yes ++,VGA_R[2],I/O Standard,LVTTL,Yes ++,VGA_R[3],I/O Standard,LVTTL,Yes ++,VGA_G[0],I/O Standard,LVTTL,Yes ++,VGA_G[1],I/O Standard,LVTTL,Yes ++,VGA_G[2],I/O Standard,LVTTL,Yes ++,VGA_G[3],I/O Standard,LVTTL,Yes ++,VGA_B[0],I/O Standard,LVTTL,Yes ++,VGA_B[1],I/O Standard,LVTTL,Yes ++,VGA_B[2],I/O Standard,LVTTL,Yes ++,VGA_B[3],I/O Standard,LVTTL,Yes ++,VGA_HS,I/O Standard,LVTTL,Yes ++,VGA_VS,I/O Standard,LVTTL,Yes ++,I2C_SCLK,Location,PIN_A3,Yes ++,I2C_SDAT,Location,PIN_B3,Yes ++,AUD_ADCLRCK,Location,PIN_A6,Yes ++,AUD_ADCDAT,Location,PIN_B6,Yes ++,AUD_DACLRCK,Location,PIN_A5,Yes ++,AUD_DACDAT,Location,PIN_B5,Yes ++,AUD_XCK,Location,PIN_B4,Yes ++,AUD_BCLK,Location,PIN_A4,Yes ++,I2C_SCLK,I/O Standard,LVTTL,Yes ++,I2C_SDAT,I/O Standard,LVTTL,Yes ++,AUD_ADCLRCK,I/O Standard,LVTTL,Yes ++,AUD_ADCDAT,I/O Standard,LVTTL,Yes ++,AUD_DACLRCK,I/O Standard,LVTTL,Yes ++,AUD_DACDAT,I/O Standard,LVTTL,Yes ++,AUD_XCK,I/O Standard,LVTTL,Yes ++,AUD_BCLK,I/O Standard,LVTTL,Yes ++,DRAM_ADDR[0],Location,PIN_W4,Yes ++,DRAM_ADDR[1],Location,PIN_W5,Yes ++,DRAM_ADDR[2],Location,PIN_Y3,Yes ++,DRAM_ADDR[3],Location,PIN_Y4,Yes ++,DRAM_ADDR[4],Location,PIN_R6,Yes ++,DRAM_ADDR[5],Location,PIN_R5,Yes ++,DRAM_ADDR[6],Location,PIN_P6,Yes ++,DRAM_ADDR[7],Location,PIN_P5,Yes ++,DRAM_ADDR[8],Location,PIN_P3,Yes ++,DRAM_ADDR[9],Location,PIN_N4,Yes ++,DRAM_ADDR[10],Location,PIN_W3,Yes ++,DRAM_ADDR[11],Location,PIN_N6,Yes ++,DRAM_BA_0,Location,PIN_U3,Yes ++,DRAM_BA_1,Location,PIN_V4,Yes ++,DRAM_CAS_N,Location,PIN_T3,Yes ++,DRAM_CKE,Location,PIN_N3,Yes ++,DRAM_CLK,Location,PIN_U4,Yes ++,DRAM_CS_N,Location,PIN_T6,Yes ++,DRAM_DQ[0],Location,PIN_U1,Yes ++,DRAM_DQ[1],Location,PIN_U2,Yes ++,DRAM_DQ[2],Location,PIN_V1,Yes ++,DRAM_DQ[3],Location,PIN_V2,Yes ++,DRAM_DQ[4],Location,PIN_W1,Yes ++,DRAM_DQ[5],Location,PIN_W2,Yes ++,DRAM_DQ[6],Location,PIN_Y1,Yes ++,DRAM_DQ[7],Location,PIN_Y2,Yes ++,DRAM_DQ[8],Location,PIN_N1,Yes ++,DRAM_DQ[9],Location,PIN_N2,Yes ++,DRAM_DQ[10],Location,PIN_P1,Yes ++,DRAM_DQ[11],Location,PIN_P2,Yes ++,DRAM_DQ[12],Location,PIN_R1,Yes ++,DRAM_DQ[13],Location,PIN_R2,Yes ++,DRAM_DQ[14],Location,PIN_T1,Yes ++,DRAM_DQ[15],Location,PIN_T2,Yes ++,DRAM_LDQM,Location,PIN_R7,Yes ++,DRAM_RAS_N,Location,PIN_T5,Yes ++,DRAM_UDQM,Location,PIN_M5,Yes ++,DRAM_WE_N,Location,PIN_R8,Yes ++,FL_ADDR[0],Location,PIN_AB20,Yes ++,FL_ADDR[1],Location,PIN_AA14,Yes ++,FL_ADDR[2],Location,PIN_Y16,Yes ++,FL_ADDR[3],Location,PIN_R15,Yes ++,FL_ADDR[4],Location,PIN_T15,Yes ++,FL_ADDR[5],Location,PIN_U15,Yes ++,FL_ADDR[6],Location,PIN_V15,Yes ++,FL_ADDR[7],Location,PIN_W15,Yes ++,FL_ADDR[8],Location,PIN_R14,Yes ++,FL_ADDR[9],Location,PIN_Y13,Yes ++,FL_ADDR[10],Location,PIN_R12,Yes ++,FL_ADDR[11],Location,PIN_T12,Yes ++,FL_ADDR[12],Location,PIN_AB14,Yes ++,FL_ADDR[13],Location,PIN_AA13,Yes ++,FL_ADDR[14],Location,PIN_AB13,Yes ++,FL_ADDR[15],Location,PIN_AA12,Yes ++,FL_ADDR[16],Location,PIN_AB12,Yes ++,FL_ADDR[17],Location,PIN_AA20,Yes ++,FL_ADDR[18],Location,PIN_U14,Yes ++,FL_ADDR[19],Location,PIN_V14,Yes ++,FL_ADDR[20],Location,PIN_U13,Yes ++,FL_ADDR[21],Location,PIN_R13,Yes ++,FL_DQ[0],Location,PIN_AB16,Yes ++,FL_DQ[1],Location,PIN_AA16,Yes ++,FL_DQ[2],Location,PIN_AB17,Yes ++,FL_DQ[3],Location,PIN_AA17,Yes ++,FL_DQ[4],Location,PIN_AB18,Yes ++,FL_DQ[5],Location,PIN_AA18,Yes ++,FL_DQ[6],Location,PIN_AB19,Yes ++,FL_DQ[7],Location,PIN_AA19,Yes ++,FL_OE_N,Location,PIN_AA15,Yes ++,FL_RST_N,Location,PIN_W14,Yes ++,FL_WE_N,Location,PIN_Y14,Yes ++,FL_CE_N,Location,PIN_AB15,Yes ++,SRAM_ADDR[0],Location,PIN_AA3,Yes ++,SRAM_ADDR[1],Location,PIN_AB3,Yes ++,SRAM_ADDR[2],Location,PIN_AA4,Yes ++,SRAM_ADDR[3],Location,PIN_AB4,Yes ++,SRAM_ADDR[4],Location,PIN_AA5,Yes ++,SRAM_ADDR[5],Location,PIN_AB10,Yes ++,SRAM_ADDR[6],Location,PIN_AA11,Yes ++,SRAM_ADDR[7],Location,PIN_AB11,Yes ++,SRAM_ADDR[8],Location,PIN_V11,Yes ++,SRAM_ADDR[9],Location,PIN_W11,Yes ++,SRAM_ADDR[10],Location,PIN_R11,Yes ++,SRAM_ADDR[11],Location,PIN_T11,Yes ++,SRAM_ADDR[12],Location,PIN_Y10,Yes ++,SRAM_ADDR[13],Location,PIN_U10,Yes ++,SRAM_ADDR[14],Location,PIN_R10,Yes ++,SRAM_ADDR[15],Location,PIN_T7,Yes ++,SRAM_ADDR[16],Location,PIN_Y6,Yes ++,SRAM_ADDR[17],Location,PIN_Y5,Yes ++,SRAM_CE_N,Location,PIN_AB5,Yes ++,SRAM_DQ[0],Location,PIN_AA6,Yes ++,SRAM_DQ[1],Location,PIN_AB6,Yes ++,SRAM_DQ[2],Location,PIN_AA7,Yes ++,SRAM_DQ[3],Location,PIN_AB7,Yes ++,SRAM_DQ[4],Location,PIN_AA8,Yes ++,SRAM_DQ[5],Location,PIN_AB8,Yes ++,SRAM_DQ[6],Location,PIN_AA9,Yes ++,SRAM_DQ[7],Location,PIN_AB9,Yes ++,SRAM_DQ[8],Location,PIN_Y9,Yes ++,SRAM_DQ[9],Location,PIN_W9,Yes ++,SRAM_DQ[10],Location,PIN_V9,Yes ++,SRAM_DQ[11],Location,PIN_U9,Yes ++,SRAM_DQ[12],Location,PIN_R9,Yes ++,SRAM_DQ[13],Location,PIN_W8,Yes ++,SRAM_DQ[14],Location,PIN_V8,Yes ++,SRAM_DQ[15],Location,PIN_U8,Yes ++,SRAM_LB_N,Location,PIN_Y7,Yes ++,SRAM_OE_N,Location,PIN_T8,Yes ++,SRAM_UB_N,Location,PIN_W7,Yes ++,SRAM_WE_N,Location,PIN_AA10,Yes ++,SD_nCS,Location,PIN_U20,Yes ++,SD_MOSI,Location,PIN_Y20,Yes ++,SD_SCLK,Location,PIN_V20,Yes ++,SD_MISO,Location,PIN_W20,Yes ++ +diff --git a/T65/T65.vhd b/T65/T65.vhd +index 4a21d79..09253fe 100644 +--- a/T65/T65.vhd ++++ b/T65/T65.vhd +@@ -1,564 +1,564 @@ +--- ****
+--- T65(b) core. In an effort to merge and maintain bug fixes ....
+---
+---
+--- Ver 301 more merging
+--- Ver 300 Bugfixes by ehenciak added, started tidyup *bust*
+--- MikeJ March 2005
+--- Latest version from www.fpgaarcade.com (original www.opencores.org)
+---
+--- ****
+---
+--- 65xx compatible microprocessor core
+---
+--- Version : 0246
+---
+--- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org)
+---
+--- All rights reserved
+---
+--- Redistribution and use in source and synthezised forms, with or without
+--- modification, are permitted provided that the following conditions are met:
+---
+--- Redistributions of source code must retain the above copyright notice,
+--- this list of conditions and the following disclaimer.
+---
+--- Redistributions in synthesized form must reproduce the above copyright
+--- notice, this list of conditions and the following disclaimer in the
+--- documentation and/or other materials provided with the distribution.
+---
+--- Neither the name of the author nor the names of other contributors may
+--- be used to endorse or promote products derived from this software without
+--- specific prior written permission.
+---
+--- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+--- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
+--- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+--- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+--- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+--- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+--- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+--- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+--- POSSIBILITY OF SUCH DAMAGE.
+---
+--- Please report bugs to the author, but before you do so, please
+--- make sure that this is not a derivative work and that
+--- you have the latest version of this file.
+---
+--- The latest version of this file can be found at:
+--- http://www.opencores.org/cvsweb.shtml/t65/
+---
+--- Limitations :
+---
+--- 65C02 and 65C816 modes are incomplete
+--- Undocumented instructions are not supported
+--- Some interface signals behaves incorrect
+---
+--- File history :
+---
+--- 0246 : First release
+---
+-
+-library IEEE;
+- use IEEE.std_logic_1164.all;
+- use IEEE.numeric_std.all;
+- use work.T65_Pack.all;
+-
+--- ehenciak 2-23-2005 : Added the enable signal so that one doesn't have to use
+--- the ready signal to limit the CPU.
+-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)
+- );
+-end T65;
+-
+-architecture rtl of T65 is
+-
+- -- Registers
+- signal ABC, X, Y, D : std_logic_vector(15 downto 0);
+- signal P, AD, DL : std_logic_vector(7 downto 0) := x"00";
+- 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 : std_logic_vector(3 downto 0);
+- signal Write_Data_r : std_logic_vector(2 downto 0);
+- signal Set_Addr_To_r : std_logic_vector(1 downto 0);
+- signal PCAdder : unsigned(8 downto 0);
+-
+- signal RstCycle : std_logic;
+- signal IRQCycle : std_logic;
+- signal NMICycle : std_logic;
+-
+- signal B_o : 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 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 : std_logic_vector(3 downto 0);
+- signal Set_BusA_To : std_logic_vector(2 downto 0);
+- signal Set_Addr_To : std_logic_vector(1 downto 0);
+- signal Write_Data : std_logic_vector(2 downto 0);
+- 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 really_rdy : std_logic;
+- signal R_W_n_i : std_logic;
+-
+-begin
+- -- ehenciak : gate Rdy with read/write to make an "OK, it's
+- -- really OK to stop the processor now if Rdy is
+- -- deasserted" signal
+- really_rdy <= Rdy or not(R_W_n_i);
+-
+- -- ehenciak : Drive R_W_n_i off chip.
+- R_W_n <= R_W_n_i;
+-
+- Sync <= '1' when MCycle = "000" else '0';
+- EF <= EF_i;
+- MF <= MF_i;
+- XF <= XF_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 /= "00" else '0'; -- Incorrect !!!!!!!!!!!!
+- VPA <= '1' when Jump(1) = '0' else '0'; -- Incorrect !!!!!!!!!!!!
+-
+- mcode : T65_MCode
+- port map(
+- Mode => Mode_r,
+- IR => IR,
+- MCycle => MCycle,
+- P => P,
+- 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 : 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
+- );
+-
+- process (Res_n, Clk)
+- begin
+- if Res_n = '0' then
+- PC <= (others => '0'); -- Program Counter
+- IR <= "00000000";
+- S <= (others => '0'); -- Dummy !!!!!!!!!!!!!!!!!!!!!
+- D <= (others => '0');
+- PBR <= (others => '0');
+- DBR <= (others => '0');
+-
+- Mode_r <= (others => '0');
+- ALU_Op_r <= "1100";
+- Write_Data_r <= "000";
+- Set_Addr_To_r <= "00";
+-
+- R_W_n_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
+- R_W_n_i <= not Write or RstCycle;
+-
+- D <= (others => '1'); -- Dummy
+- 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;
+- end if;
+-
+- ALU_Op_r <= ALU_Op;
+- Write_Data_r <= Write_Data;
+- if Break = '1' then
+- Set_Addr_To_r <= "00";
+- 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 LDS = '1' then
+- S(7 downto 0) <= unsigned(ALU_Q);
+- 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 (Clk)
+- begin
+- if Clk'event and Clk = '1' then
+- 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
+- P <= P_Out;
+- end if;
+- end if;
+- if SaveP = '1' then
+- P <= P_Out;
+- end if;
+- if LDP = '1' then
+- P <= ALU_Q;
+- end if;
+- if IR(4 downto 0) = "11000" then
+- case IR(7 downto 5) is
+- when "000" =>
+- P(Flag_C) <= '0';
+- when "001" =>
+- P(Flag_C) <= '1';
+- when "010" =>
+- P(Flag_I) <= '0';
+- when "011" =>
+- P(Flag_I) <= '1';
+- when "101" =>
+- P(Flag_V) <= '0';
+- when "110" =>
+- P(Flag_D) <= '0';
+- when "111" =>
+- P(Flag_D) <= '1';
+- when others =>
+- end case;
+- end if;
+-
+- --if IR = "00000000" and MCycle = "011" and RstCycle = '0' and NMICycle = '0' and IRQCycle = '0' then
+- -- P(Flag_B) <= '1';
+- --end if;
+- --if IR = "00000000" and MCycle = "100" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then
+- -- P(Flag_I) <= '1';
+- -- P(Flag_B) <= B_o;
+- --end if;
+-
+- -- B=1 always on the 6502
+- P(Flag_B) <= '1';
+- if IR = "00000000" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then
+- if MCycle = "011" then
+- -- B=0 in *copy* of P pushed onto the stack
+- P(Flag_B) <= '0';
+- elsif MCycle = "100" then
+- P(Flag_I) <= '1';
+- end if;
+- end if;
+-
+- if SO_n_o = '1' and SO_n = '0' then
+- P(Flag_V) <= '1';
+- end if;
+- if RstCycle = '1' and Mode_r /= "00" then
+- P(Flag_1) <= '1';
+- P(Flag_D) <= '0';
+- P(Flag_I) <= '1';
+- end if;
+- P(Flag_1) <= '1';
+-
+- B_o <= P(Flag_B);
+- SO_n_o <= SO_n;
+- IRQ_n_o <= IRQ_n;
+- NMI_n_o <= NMI_n;
+- end if;
+- end if;
+- end if;
+- end process;
+-
+----------------------------------------------------------------------------
+---
+--- Buses
+---
+----------------------------------------------------------------------------
+-
+- process (Res_n, Clk)
+- begin
+- if Res_n = '0' then
+- BusA_r <= (others => '0');
+- BusB <= (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
+- if (Rdy = '1') then
+- BusA_r <= BusA;
+- BusB <= DI;
+-
+- 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;
+-
+- -- ehenciak : modified to use Y register as well (bugfix)
+- 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' then
+- BAL(2 downto 0) <= "010";
+- else
+- BAL(2 downto 0) <= "110";
+- end if;
+- if Set_addr_To_r = "11" 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 "000",
+- ABC(7 downto 0) when "001",
+- X(7 downto 0) when "010",
+- Y(7 downto 0) when "011",
+- std_logic_vector(S(7 downto 0)) when "100",
+- P when "101",
+- (others => '-') when others;
+-
+- with Set_Addr_To_r select
+- A <= "0000000000000001" & std_logic_vector(S(7 downto 0)) when "01",
+- DBR & "00000000" & AD when "10",
+- "00000000" & BAH & BAL(7 downto 0) when "11",
+- PBR & std_logic_vector(PC(15 downto 8)) & std_logic_vector(PCAdder(7 downto 0)) when others;
+-
+- with Write_Data_r select
+- DO <= DL when "000",
+- ABC(7 downto 0) when "001",
+- X(7 downto 0) when "010",
+- Y(7 downto 0) when "011",
+- std_logic_vector(S(7 downto 0)) when "100",
+- P when "101",
+- std_logic_vector(PC(7 downto 0)) when "110",
+- std_logic_vector(PC(15 downto 8)) when others;
+-
+--------------------------------------------------------------------------
+---
+--- Main state machine
+---
+--------------------------------------------------------------------------
+-
+- process (Res_n, Clk)
+- begin
+- if Res_n = '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' then
+- NMICycle <= '1';
+- 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;
+-
+- if NMICycle = '1' then
+- NMIAct <= '0';
+- end if;
+- if NMI_n_o = '1' and NMI_n = '0' then
+- NMIAct <= '1';
+- end if;
+- end if;
+- end if;
+- end if;
+- end process;
+-
+-end;
++-- **** ++-- T65(b) core. In an effort to merge and maintain bug fixes .... ++-- ++-- ++-- Ver 301 more merging ++-- Ver 300 Bugfixes by ehenciak added, started tidyup *bust* ++-- MikeJ March 2005 ++-- Latest version from www.fpgaarcade.com (original www.opencores.org) ++-- ++-- **** ++-- ++-- 65xx compatible microprocessor core ++-- ++-- Version : 0246 ++-- ++-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) ++-- ++-- All rights reserved ++-- ++-- Redistribution and use in source and synthezised forms, with or without ++-- modification, are permitted provided that the following conditions are met: ++-- ++-- Redistributions of source code must retain the above copyright notice, ++-- this list of conditions and the following disclaimer. ++-- ++-- Redistributions in synthesized form must reproduce the above copyright ++-- notice, this list of conditions and the following disclaimer in the ++-- documentation and/or other materials provided with the distribution. ++-- ++-- Neither the name of the author nor the names of other contributors may ++-- be used to endorse or promote products derived from this software without ++-- specific prior written permission. ++-- ++-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE ++-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++-- POSSIBILITY OF SUCH DAMAGE. ++-- ++-- Please report bugs to the author, but before you do so, please ++-- make sure that this is not a derivative work and that ++-- you have the latest version of this file. ++-- ++-- The latest version of this file can be found at: ++-- http://www.opencores.org/cvsweb.shtml/t65/ ++-- ++-- Limitations : ++-- ++-- 65C02 and 65C816 modes are incomplete ++-- Undocumented instructions are not supported ++-- Some interface signals behaves incorrect ++-- ++-- File history : ++-- ++-- 0246 : First release ++-- ++ ++library IEEE; ++ use IEEE.std_logic_1164.all; ++ use IEEE.numeric_std.all; ++ use work.T65_Pack.all; ++ ++-- ehenciak 2-23-2005 : Added the enable signal so that one doesn't have to use ++-- the ready signal to limit the CPU. ++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) ++ ); ++end T65; ++ ++architecture rtl of T65 is ++ ++ -- Registers ++ signal ABC, X, Y, D : std_logic_vector(15 downto 0); ++ signal P, AD, DL : std_logic_vector(7 downto 0) := x"00"; ++ 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 : std_logic_vector(3 downto 0); ++ signal Write_Data_r : std_logic_vector(2 downto 0); ++ signal Set_Addr_To_r : std_logic_vector(1 downto 0); ++ signal PCAdder : unsigned(8 downto 0); ++ ++ signal RstCycle : std_logic; ++ signal IRQCycle : std_logic; ++ signal NMICycle : std_logic; ++ ++ signal B_o : 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 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 : std_logic_vector(3 downto 0); ++ signal Set_BusA_To : std_logic_vector(2 downto 0); ++ signal Set_Addr_To : std_logic_vector(1 downto 0); ++ signal Write_Data : std_logic_vector(2 downto 0); ++ 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 really_rdy : std_logic; ++ signal R_W_n_i : std_logic; ++ ++begin ++ -- ehenciak : gate Rdy with read/write to make an "OK, it's ++ -- really OK to stop the processor now if Rdy is ++ -- deasserted" signal ++ really_rdy <= Rdy or not(R_W_n_i); ++ ++ -- ehenciak : Drive R_W_n_i off chip. ++ R_W_n <= R_W_n_i; ++ ++ Sync <= '1' when MCycle = "000" else '0'; ++ EF <= EF_i; ++ MF <= MF_i; ++ XF <= XF_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 /= "00" else '0'; -- Incorrect !!!!!!!!!!!! ++ VPA <= '1' when Jump(1) = '0' else '0'; -- Incorrect !!!!!!!!!!!! ++ ++ mcode : T65_MCode ++ port map( ++ Mode => Mode_r, ++ IR => IR, ++ MCycle => MCycle, ++ P => P, ++ 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 : 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 ++ ); ++ ++ process (Res_n, Clk) ++ begin ++ if Res_n = '0' then ++ PC <= (others => '0'); -- Program Counter ++ IR <= "00000000"; ++ S <= (others => '0'); -- Dummy !!!!!!!!!!!!!!!!!!!!! ++ D <= (others => '0'); ++ PBR <= (others => '0'); ++ DBR <= (others => '0'); ++ ++ Mode_r <= (others => '0'); ++ ALU_Op_r <= "1100"; ++ Write_Data_r <= "000"; ++ Set_Addr_To_r <= "00"; ++ ++ R_W_n_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 ++ R_W_n_i <= not Write or RstCycle; ++ ++ D <= (others => '1'); -- Dummy ++ 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; ++ end if; ++ ++ ALU_Op_r <= ALU_Op; ++ Write_Data_r <= Write_Data; ++ if Break = '1' then ++ Set_Addr_To_r <= "00"; ++ 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 LDS = '1' then ++ S(7 downto 0) <= unsigned(ALU_Q); ++ 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 (Clk) ++ begin ++ if Clk'event and Clk = '1' then ++ 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 ++ P <= P_Out; ++ end if; ++ end if; ++ if SaveP = '1' then ++ P <= P_Out; ++ end if; ++ if LDP = '1' then ++ P <= ALU_Q; ++ end if; ++ if IR(4 downto 0) = "11000" then ++ case IR(7 downto 5) is ++ when "000" => ++ P(Flag_C) <= '0'; ++ when "001" => ++ P(Flag_C) <= '1'; ++ when "010" => ++ P(Flag_I) <= '0'; ++ when "011" => ++ P(Flag_I) <= '1'; ++ when "101" => ++ P(Flag_V) <= '0'; ++ when "110" => ++ P(Flag_D) <= '0'; ++ when "111" => ++ P(Flag_D) <= '1'; ++ when others => ++ end case; ++ end if; ++ ++ --if IR = "00000000" and MCycle = "011" and RstCycle = '0' and NMICycle = '0' and IRQCycle = '0' then ++ -- P(Flag_B) <= '1'; ++ --end if; ++ --if IR = "00000000" and MCycle = "100" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then ++ -- P(Flag_I) <= '1'; ++ -- P(Flag_B) <= B_o; ++ --end if; ++ ++ -- B=1 always on the 6502 ++ P(Flag_B) <= '1'; ++ if IR = "00000000" and RstCycle = '0' and (NMICycle = '1' or IRQCycle = '1') then ++ if MCycle = "011" then ++ -- B=0 in *copy* of P pushed onto the stack ++ P(Flag_B) <= '0'; ++ elsif MCycle = "100" then ++ P(Flag_I) <= '1'; ++ end if; ++ end if; ++ ++ if SO_n_o = '1' and SO_n = '0' then ++ P(Flag_V) <= '1'; ++ end if; ++ if RstCycle = '1' and Mode_r /= "00" then ++ P(Flag_1) <= '1'; ++ P(Flag_D) <= '0'; ++ P(Flag_I) <= '1'; ++ end if; ++ P(Flag_1) <= '1'; ++ ++ B_o <= P(Flag_B); ++ SO_n_o <= SO_n; ++ IRQ_n_o <= IRQ_n; ++ NMI_n_o <= NMI_n; ++ end if; ++ end if; ++ end if; ++ end process; ++ ++--------------------------------------------------------------------------- ++-- ++-- Buses ++-- ++--------------------------------------------------------------------------- ++ ++ process (Res_n, Clk) ++ begin ++ if Res_n = '0' then ++ BusA_r <= (others => '0'); ++ BusB <= (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 ++ if (Rdy = '1') then ++ BusA_r <= BusA; ++ BusB <= DI; ++ ++ 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; ++ ++ -- ehenciak : modified to use Y register as well (bugfix) ++ 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' then ++ BAL(2 downto 0) <= "010"; ++ else ++ BAL(2 downto 0) <= "110"; ++ end if; ++ if Set_addr_To_r = "11" 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 "000", ++ ABC(7 downto 0) when "001", ++ X(7 downto 0) when "010", ++ Y(7 downto 0) when "011", ++ std_logic_vector(S(7 downto 0)) when "100", ++ P when "101", ++ (others => '-') when others; ++ ++ with Set_Addr_To_r select ++ A <= "0000000000000001" & std_logic_vector(S(7 downto 0)) when "01", ++ DBR & "00000000" & AD when "10", ++ "00000000" & BAH & BAL(7 downto 0) when "11", ++ PBR & std_logic_vector(PC(15 downto 8)) & std_logic_vector(PCAdder(7 downto 0)) when others; ++ ++ with Write_Data_r select ++ DO <= DL when "000", ++ ABC(7 downto 0) when "001", ++ X(7 downto 0) when "010", ++ Y(7 downto 0) when "011", ++ std_logic_vector(S(7 downto 0)) when "100", ++ P when "101", ++ std_logic_vector(PC(7 downto 0)) when "110", ++ std_logic_vector(PC(15 downto 8)) when others; ++ ++------------------------------------------------------------------------- ++-- ++-- Main state machine ++-- ++------------------------------------------------------------------------- ++ ++ process (Res_n, Clk) ++ begin ++ if Res_n = '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' then ++ NMICycle <= '1'; ++ 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; ++ ++ if NMICycle = '1' then ++ NMIAct <= '0'; ++ end if; ++ if NMI_n_o = '1' and NMI_n = '0' then ++ NMIAct <= '1'; ++ end if; ++ end if; ++ end if; ++ end if; ++ end process; ++ ++end; +diff --git a/T65/T65_ALU.vhd b/T65/T65_ALU.vhd +index d9d25e1..b1f6d63 100644 +--- a/T65/T65_ALU.vhd ++++ b/T65/T65_ALU.vhd +@@ -1,260 +1,260 @@ +--- ****
+--- T65(b) core. In an effort to merge and maintain bug fixes ....
+---
+---
+--- Ver 300 Bugfixes by ehenciak added
+--- MikeJ March 2005
+--- Latest version from www.fpgaarcade.com (original www.opencores.org)
+---
+--- ****
+---
+--- 6502 compatible microprocessor core
+---
+--- Version : 0245
+---
+--- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org)
+---
+--- All rights reserved
+---
+--- Redistribution and use in source and synthezised forms, with or without
+--- modification, are permitted provided that the following conditions are met:
+---
+--- Redistributions of source code must retain the above copyright notice,
+--- this list of conditions and the following disclaimer.
+---
+--- Redistributions in synthesized form must reproduce the above copyright
+--- notice, this list of conditions and the following disclaimer in the
+--- documentation and/or other materials provided with the distribution.
+---
+--- Neither the name of the author nor the names of other contributors may
+--- be used to endorse or promote products derived from this software without
+--- specific prior written permission.
+---
+--- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+--- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
+--- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+--- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+--- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+--- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+--- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+--- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+--- POSSIBILITY OF SUCH DAMAGE.
+---
+--- Please report bugs to the author, but before you do so, please
+--- make sure that this is not a derivative work and that
+--- you have the latest version of this file.
+---
+--- The latest version of this file can be found at:
+--- http://www.opencores.org/cvsweb.shtml/t65/
+---
+--- Limitations :
+---
+--- File history :
+---
+--- 0245 : First version
+---
+-
+-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 std_logic_vector(3 downto 0);
+- 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);
+-
+-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;
+- begin
+- C := P_In(Flag_C) 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);
+-
+- 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)
+- variable Q_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;
+- case Op(3 downto 0) is
+- when "0000" =>
+- -- ORA
+- Q_t := BusA or BusB;
+- when "0001" =>
+- -- AND
+- Q_t := BusA and BusB;
+- when "0010" =>
+- -- EOR
+- Q_t := BusA xor BusB;
+- when "0011" =>
+- -- ADC
+- P_Out(Flag_V) <= ADC_V;
+- P_Out(Flag_C) <= ADC_C;
+- Q_t := ADC_Q;
+- when "0101" | "1101" =>
+- -- LDA
+- when "0110" =>
+- -- CMP
+- P_Out(Flag_C) <= SBC_C;
+- when "0111" =>
+- -- SBC
+- P_Out(Flag_V) <= SBC_V;
+- P_Out(Flag_C) <= SBC_C;
+- Q_t := SBC_Q;
+- when "1000" =>
+- -- ASL
+- Q_t := BusA(6 downto 0) & "0";
+- P_Out(Flag_C) <= BusA(7);
+- when "1001" =>
+- -- ROL
+- Q_t := BusA(6 downto 0) & P_In(Flag_C);
+- P_Out(Flag_C) <= BusA(7);
+- when "1010" =>
+- -- LSR
+- Q_t := "0" & BusA(7 downto 1);
+- P_Out(Flag_C) <= BusA(0);
+- when "1011" =>
+- -- ROR
+- Q_t := P_In(Flag_C) & BusA(7 downto 1);
+- P_Out(Flag_C) <= BusA(0);
+- when "1100" =>
+- -- BIT
+- P_Out(Flag_V) <= BusB(6);
+- when "1110" =>
+- -- DEC
+- Q_t := std_logic_vector(unsigned(BusA) - 1);
+- when "1111" =>
+- -- INC
+- Q_t := std_logic_vector(unsigned(BusA) + 1);
+- when others =>
+- end case;
+-
+- case Op(3 downto 0) is
+- when "0011" =>
+- P_Out(Flag_N) <= ADC_N;
+- P_Out(Flag_Z) <= ADC_Z;
+- when "0110" | "0111" =>
+- P_Out(Flag_N) <= SBC_N;
+- P_Out(Flag_Z) <= SBC_Z;
+- when "0100" =>
+- when "1100" =>
+- 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 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;
+-
+- Q <= Q_t;
+- end process;
+-
+-end;
++-- **** ++-- T65(b) core. In an effort to merge and maintain bug fixes .... ++-- ++-- ++-- Ver 300 Bugfixes by ehenciak added ++-- MikeJ March 2005 ++-- Latest version from www.fpgaarcade.com (original www.opencores.org) ++-- ++-- **** ++-- ++-- 6502 compatible microprocessor core ++-- ++-- Version : 0245 ++-- ++-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) ++-- ++-- All rights reserved ++-- ++-- Redistribution and use in source and synthezised forms, with or without ++-- modification, are permitted provided that the following conditions are met: ++-- ++-- Redistributions of source code must retain the above copyright notice, ++-- this list of conditions and the following disclaimer. ++-- ++-- Redistributions in synthesized form must reproduce the above copyright ++-- notice, this list of conditions and the following disclaimer in the ++-- documentation and/or other materials provided with the distribution. ++-- ++-- Neither the name of the author nor the names of other contributors may ++-- be used to endorse or promote products derived from this software without ++-- specific prior written permission. ++-- ++-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE ++-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++-- POSSIBILITY OF SUCH DAMAGE. ++-- ++-- Please report bugs to the author, but before you do so, please ++-- make sure that this is not a derivative work and that ++-- you have the latest version of this file. ++-- ++-- The latest version of this file can be found at: ++-- http://www.opencores.org/cvsweb.shtml/t65/ ++-- ++-- Limitations : ++-- ++-- File history : ++-- ++-- 0245 : First version ++-- ++ ++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 std_logic_vector(3 downto 0); ++ 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); ++ ++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; ++ begin ++ C := P_In(Flag_C) 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); ++ ++ 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) ++ variable Q_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; ++ case Op(3 downto 0) is ++ when "0000" => ++ -- ORA ++ Q_t := BusA or BusB; ++ when "0001" => ++ -- AND ++ Q_t := BusA and BusB; ++ when "0010" => ++ -- EOR ++ Q_t := BusA xor BusB; ++ when "0011" => ++ -- ADC ++ P_Out(Flag_V) <= ADC_V; ++ P_Out(Flag_C) <= ADC_C; ++ Q_t := ADC_Q; ++ when "0101" | "1101" => ++ -- LDA ++ when "0110" => ++ -- CMP ++ P_Out(Flag_C) <= SBC_C; ++ when "0111" => ++ -- SBC ++ P_Out(Flag_V) <= SBC_V; ++ P_Out(Flag_C) <= SBC_C; ++ Q_t := SBC_Q; ++ when "1000" => ++ -- ASL ++ Q_t := BusA(6 downto 0) & "0"; ++ P_Out(Flag_C) <= BusA(7); ++ when "1001" => ++ -- ROL ++ Q_t := BusA(6 downto 0) & P_In(Flag_C); ++ P_Out(Flag_C) <= BusA(7); ++ when "1010" => ++ -- LSR ++ Q_t := "0" & BusA(7 downto 1); ++ P_Out(Flag_C) <= BusA(0); ++ when "1011" => ++ -- ROR ++ Q_t := P_In(Flag_C) & BusA(7 downto 1); ++ P_Out(Flag_C) <= BusA(0); ++ when "1100" => ++ -- BIT ++ P_Out(Flag_V) <= BusB(6); ++ when "1110" => ++ -- DEC ++ Q_t := std_logic_vector(unsigned(BusA) - 1); ++ when "1111" => ++ -- INC ++ Q_t := std_logic_vector(unsigned(BusA) + 1); ++ when others => ++ end case; ++ ++ case Op(3 downto 0) is ++ when "0011" => ++ P_Out(Flag_N) <= ADC_N; ++ P_Out(Flag_Z) <= ADC_Z; ++ when "0110" | "0111" => ++ P_Out(Flag_N) <= SBC_N; ++ P_Out(Flag_Z) <= SBC_Z; ++ when "0100" => ++ when "1100" => ++ 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 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; ++ ++ Q <= Q_t; ++ end process; ++ ++end; +diff --git a/T65/T65_MCode.vhd b/T65/T65_MCode.vhd +index 3fd40d8..6c6c864 100644 +--- a/T65/T65_MCode.vhd ++++ b/T65/T65_MCode.vhd +@@ -1,1052 +1,1052 @@ +--- ****
+--- T65(b) core. In an effort to merge and maintain bug fixes ....
+---
+---
+--- Ver 302 minor timing fixes
+--- Ver 301 Jump timing fixed
+--- Ver 300 Bugfixes by ehenciak added
+--- MikeJ March 2005
+--- Latest version from www.fpgaarcade.com (original www.opencores.org)
+---
+--- ****
+---
+--- 65xx compatible microprocessor core
+---
+--- Version : 0246 + fix
+---
+--- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org)
+---
+--- All rights reserved
+---
+--- Redistribution and use in source and synthezised forms, with or without
+--- modification, are permitted provided that the following conditions are met:
+---
+--- Redistributions of source code must retain the above copyright notice,
+--- this list of conditions and the following disclaimer.
+---
+--- Redistributions in synthesized form must reproduce the above copyright
+--- notice, this list of conditions and the following disclaimer in the
+--- documentation and/or other materials provided with the distribution.
+---
+--- Neither the name of the author nor the names of other contributors may
+--- be used to endorse or promote products derived from this software without
+--- specific prior written permission.
+---
+--- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+--- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
+--- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+--- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+--- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+--- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+--- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+--- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+--- POSSIBILITY OF SUCH DAMAGE.
+---
+--- Please report bugs to the author, but before you do so, please
+--- make sure that this is not a derivative work and that
+--- you have the latest version of this file.
+---
+--- The latest version of this file can be found at:
+--- http://www.opencores.org/cvsweb.shtml/t65/
+---
+--- Limitations :
+---
+--- 65C02
+--- supported : inc, dec, phx, plx, phy, ply
+--- missing : bra, ora, lda, cmp, sbc, tsb*2, trb*2, stz*2, bit*2, wai, stp, jmp, bbr*8, bbs*8
+---
+--- File history :
+---
+--- 0246 : First release
+---
+-
+-library IEEE;
+-use IEEE.std_logic_1164.all;
+-use IEEE.numeric_std.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 std_logic_vector(2 downto 0);
+- P : in std_logic_vector(7 downto 0);
+- LCycle : out std_logic_vector(2 downto 0);
+- ALU_Op : out std_logic_vector(3 downto 0);
+- Set_BusA_To : out std_logic_vector(2 downto 0); -- DI,A,X,Y,S,P
+- Set_Addr_To : out std_logic_vector(1 downto 0); -- PC Adder,S,AD,BA
+- Write_Data : out std_logic_vector(2 downto 0); -- DL,A,X,Y,S,P,PCL,PCH
+- 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;
+-
+-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 <= "001";
+- Set_BusA_To <= "001"; -- A
+- Set_Addr_To <= (others => '0');
+- Write_Data <= (others => '0');
+- 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';
+-
+- case IR(7 downto 5) is
+- when "100" =>
+- --{{{
+- case IR(1 downto 0) is
+- when "00" =>
+- Set_BusA_To <= "011"; -- Y
+- Write_Data <= "011"; -- Y
+- when "10" =>
+- Set_BusA_To <= "010"; -- X
+- Write_Data <= "010"; -- X
+- when others =>
+- Write_Data <= "001"; -- A
+- end case;
+- --}}}
+- when "101" =>
+- --{{{
+- case IR(1 downto 0) is
+- when "00" =>
+- if IR(4) /= '1' or IR(2) /= '0' then
+- LDY <= '1';
+- end if;
+- when "10" =>
+- LDX <= '1';
+- when others =>
+- LDA <= '1';
+- end case;
+- Set_BusA_To <= "000"; -- DI
+- --}}}
+- when "110" =>
+- --{{{
+- case IR(1 downto 0) is
+- when "00" =>
+- if IR(4) = '0' then
+- LDY <= '1';
+- end if;
+- Set_BusA_To <= "011"; -- Y
+- when others =>
+- Set_BusA_To <= "001"; -- A
+- end case;
+- --}}}
+- when "111" =>
+- --{{{
+- case IR(1 downto 0) is
+- when "00" =>
+- if IR(4) = '0' then
+- LDX <= '1';
+- end if;
+- Set_BusA_To <= "010"; -- X
+- when others =>
+- Set_BusA_To <= "001"; -- A
+- end case;
+- --}}}
+- when others =>
+- end case;
+-
+- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then
+- Set_BusA_To <= "000"; -- DI
+- end if;
+-
+- case IR(4 downto 0) is
+- when "00000" | "01000" | "01010" | "11000" | "11010" =>
+- --{{{
+- -- Implied
+- case IR is
+- when "00000000" =>
+- -- BRK
+- LCycle <= "110";
+- case to_integer(unsigned(MCycle)) is
+- when 1 =>
+- Set_Addr_To <= "01"; -- S
+- Write_Data <= "111"; -- PCH
+- Write <= '1';
+- when 2 =>
+- Dec_S <= '1';
+- Set_Addr_To <= "01"; -- S
+- Write_Data <= "110"; -- PCL
+- Write <= '1';
+- when 3 =>
+- Dec_S <= '1';
+- Set_Addr_To <= "01"; -- S
+- Write_Data <= "101"; -- P
+- Write <= '1';
+- when 4 =>
+- Dec_S <= '1';
+- Set_Addr_To <= "11"; -- BA
+- when 5 =>
+- LDDI <= '1';
+- Set_Addr_To <= "11"; -- BA
+- when 6 =>
+- Jump <= "10"; -- DIDL
+- when others =>
+- end case;
+- when "00100000" =>
+- -- JSR
+- LCycle <= "101";
+- case to_integer(unsigned(MCycle)) is
+- when 1 =>
+- Jump <= "01";
+- LDDI <= '1';
+- Set_Addr_To <= "01"; -- S
+- when 2 =>
+- Set_Addr_To <= "01"; -- S
+- Write_Data <= "111"; -- PCH
+- Write <= '1';
+- when 3 =>
+- Dec_S <= '1';
+- Set_Addr_To <= "01"; -- S
+- Write_Data <= "110"; -- PCL
+- Write <= '1';
+- when 4 =>
+- Dec_S <= '1';
+- when 5 =>
+- Jump <= "10"; -- DIDL
+- when others =>
+- end case;
+- when "01000000" =>
+- -- RTI
+- LCycle <= "101";
+- case to_integer(unsigned(MCycle)) is
+- when 1 =>
+- Set_Addr_To <= "01"; -- S
+- when 2 =>
+- Inc_S <= '1';
+- Set_Addr_To <= "01"; -- S
+- when 3 =>
+- Inc_S <= '1';
+- Set_Addr_To <= "01"; -- S
+- Set_BusA_To <= "000"; -- DI
+- when 4 =>
+- LDP <= '1';
+- Inc_S <= '1';
+- LDDI <= '1';
+- Set_Addr_To <= "01"; -- S
+- when 5 =>
+- Jump <= "10"; -- DIDL
+- when others =>
+- end case;
+- when "01100000" =>
+- -- RTS
+- LCycle <= "101";
+- case to_integer(unsigned(MCycle)) is
+- when 1 =>
+- Set_Addr_To <= "01"; -- S
+- when 2 =>
+- Inc_S <= '1';
+- Set_Addr_To <= "01"; -- S
+- when 3 =>
+- Inc_S <= '1';
+- LDDI <= '1';
+- Set_Addr_To <= "01"; -- S
+- when 4 =>
+- Jump <= "10"; -- DIDL
+- when 5 =>
+- Jump <= "01";
+- when others =>
+- end case;
+- when "00001000" | "01001000" | "01011010" | "11011010" =>
+- -- PHP, PHA, PHY*, PHX*
+- LCycle <= "010";
+- if Mode = "00" and IR(1) = '1' then
+- LCycle <= "001";
+- end if;
+- case to_integer(unsigned(MCycle)) is
+- when 1 =>
+- case IR(7 downto 4) is
+- when "0000" =>
+- Write_Data <= "101"; -- P
+- when "0100" =>
+- Write_Data <= "001"; -- A
+- when "0101" =>
+- Write_Data <= "011"; -- Y
+- when "1101" =>
+- Write_Data <= "010"; -- X
+- when others =>
+- end case;
+- Write <= '1';
+- Set_Addr_To <= "01"; -- S
+- when 2 =>
+- Dec_S <= '1';
+- when others =>
+- end case;
+- when "00101000" | "01101000" | "01111010" | "11111010" =>
+- -- PLP, PLA, PLY*, PLX*
+- LCycle <= "011";
+- if Mode = "00" and IR(1) = '1' then
+- LCycle <= "001";
+- end if;
+- case IR(7 downto 4) is
+- when "0010" =>
+- LDP <= '1';
+- when "0110" =>
+- LDA <= '1';
+- when "0111" =>
+- if Mode /= "00" then
+- LDY <= '1';
+- end if;
+- when "1111" =>
+- if Mode /= "00" then
+- LDX <= '1';
+- end if;
+- when others =>
+- end case;
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- SaveP <= '1';
+- when 1 =>
+- Set_Addr_To <= "01"; -- S
+- when 2 =>
+- Inc_S <= '1';
+- Set_Addr_To <= "01"; -- S
+- when 3 =>
+- Set_BusA_To <= "000"; -- DI
+- when others =>
+- end case;
+- when "10100000" | "11000000" | "11100000" =>
+- -- LDY, CPY, CPX
+- -- Immediate
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Jump <= "01";
+- when others =>
+- end case;
+- when "10001000" =>
+- -- DEY
+- LDY <= '1';
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Set_BusA_To <= "011"; -- Y
+- when others =>
+- end case;
+- when "11001010" =>
+- -- DEX
+- LDX <= '1';
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Set_BusA_To <= "010"; -- X
+- when others =>
+- end case;
+- when "00011010" | "00111010" =>
+- -- INC*, DEC*
+- if Mode /= "00" then
+- LDA <= '1'; -- A
+- end if;
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Set_BusA_To <= "100"; -- S
+- when others =>
+- end case;
+- when "00001010" | "00101010" | "01001010" | "01101010" =>
+- -- ASL, ROL, LSR, ROR
+- LDA <= '1'; -- A
+- Set_BusA_To <= "001"; -- A
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- when others =>
+- end case;
+- when "10001010" | "10011000" =>
+- -- TYA, TXA
+- LDA <= '1'; -- A
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- when others =>
+- end case;
+- when "10101010" | "10101000" =>
+- -- TAX, TAY
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Set_BusA_To <= "001"; -- A
+- when others =>
+- end case;
+- when "10011010" =>
+- -- TXS
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- LDS <= '1';
+- when 1 =>
+- when others =>
+- end case;
+- when "10111010" =>
+- -- TSX
+- LDX <= '1';
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Set_BusA_To <= "100"; -- S
+- when others =>
+- end case;
+-
+- -- when "00011000" | "00111000" | "01011000" | "01111000" | "10111000" | "11011000" | "11111000" | "11001000" | "11101000" =>
+- -- -- CLC, SEC, CLI, SEI, CLV, CLD, SED, INY, INX
+- -- case to_integer(unsigned(MCycle)) is
+- -- when 1 =>
+- -- when others =>
+- -- end case;
+- when others =>
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when others =>
+- end case;
+- end case;
+- --}}}
+-
+- when "00001" | "00011" =>
+- --{{{
+- -- Zero Page Indexed Indirect (d,x)
+- LCycle <= "101";
+- if IR(7 downto 6) /= "10" then
+- LDA <= '1';
+- end if;
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Jump <= "01";
+- LDAD <= '1';
+- Set_Addr_To <= "10"; -- AD
+- when 2 =>
+- ADAdd <= '1';
+- Set_Addr_To <= "10"; -- AD
+- when 3 =>
+- BAAdd <= "01"; -- DB Inc
+- LDBAL <= '1';
+- Set_Addr_To <= "10"; -- AD
+- when 4 =>
+- LDBAH <= '1';
+- if IR(7 downto 5) = "100" then
+- Write <= '1';
+- end if;
+- Set_Addr_To <= "11"; -- BA
+- when 5 =>
+- when others =>
+- end case;
+- --}}}
+-
+- when "01001" | "01011" =>
+- --{{{
+- -- Immediate
+- LDA <= '1';
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Jump <= "01";
+- when others =>
+- end case;
+-
+- --}}}
+-
+- when "00010" | "10010" =>
+- --{{{
+- -- Immediate, KIL
+- LDX <= '1';
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- if IR = "10100010" then
+- -- LDX
+- Jump <= "01";
+- else
+- -- KIL !!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+- end if;
+- when others =>
+- end case;
+- --}}}
+-
+- when "00100" =>
+- --{{{
+- -- Zero Page
+- LCycle <= "010";
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- if IR(7 downto 5) = "001" then
+- SaveP <= '1';
+- end if;
+- when 1 =>
+- Jump <= "01";
+- LDAD <= '1';
+- if IR(7 downto 5) = "100" then
+- Write <= '1';
+- end if;
+- Set_Addr_To <= "10"; -- AD
+- when 2 =>
+- when others =>
+- end case;
+- --}}}
+-
+- when "00101" | "00110" | "00111" =>
+- --{{{
+- -- Zero Page
+- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then
+- -- Read-Modify-Write
+- LCycle <= "100";
+- case to_integer(unsigned(MCycle)) is
+- when 1 =>
+- Jump <= "01";
+- LDAD <= '1';
+- Set_Addr_To <= "10"; -- AD
+- when 2 =>
+- LDDI <= '1';
+- Write <= '1';
+- Set_Addr_To <= "10"; -- AD
+- when 3 =>
+- LDALU <= '1';
+- SaveP <= '1';
+- Write <= '1';
+- Set_Addr_To <= "10"; -- AD
+- when 4 =>
+- when others =>
+- end case;
+- else
+- LCycle <= "010";
+- if IR(7 downto 6) /= "10" then
+- LDA <= '1';
+- end if;
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Jump <= "01";
+- LDAD <= '1';
+- if IR(7 downto 5) = "100" then
+- Write <= '1';
+- end if;
+- Set_Addr_To <= "10"; -- AD
+- when 2 =>
+- when others =>
+- end case;
+- end if;
+- --}}}
+-
+- when "01100" =>
+- --{{{
+- -- Absolute
+- if IR(7 downto 6) = "01" and IR(4 downto 0) = "01100" then
+- -- JMP
+- if IR(5) = '0' then
+- --LCycle <= "011";
+- LCycle <= "010";
+- case to_integer(unsigned(MCycle)) is
+- when 1 =>
+- Jump <= "01";
+- LDDI <= '1';
+- when 2 =>
+- Jump <= "10"; -- DIDL
+- when others =>
+- end case;
+- else
+- --LCycle <= "101";
+- LCycle <= "100"; -- mikej
+- case to_integer(unsigned(MCycle)) is
+- when 1 =>
+- Jump <= "01";
+- LDDI <= '1';
+- LDBAL <= '1';
+- when 2 =>
+- LDBAH <= '1';
+- if Mode /= "00" then
+- Jump <= "10"; -- DIDL
+- end if;
+- if Mode = "00" then
+- Set_Addr_To <= "11"; -- BA
+- end if;
+- when 3 =>
+- LDDI <= '1';
+- if Mode = "00" then
+- Set_Addr_To <= "11"; -- BA
+- BAAdd <= "01"; -- DB Inc
+- else
+- Jump <= "01";
+- end if;
+- when 4 =>
+- Jump <= "10"; -- DIDL
+- when others =>
+- end case;
+- end if;
+- else
+- LCycle <= "011";
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- if IR(7 downto 5) = "001" then
+- SaveP <= '1';
+- end if;
+- when 1 =>
+- Jump <= "01";
+- LDBAL <= '1';
+- when 2 =>
+- Jump <= "01";
+- LDBAH <= '1';
+- if IR(7 downto 5) = "100" then
+- Write <= '1';
+- end if;
+- Set_Addr_To <= "11"; -- BA
+- when 3 =>
+- when others =>
+- end case;
+- end if;
+- --}}}
+-
+- when "01101" | "01110" | "01111" =>
+- --{{{
+- -- Absolute
+- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then
+- -- Read-Modify-Write
+- LCycle <= "101";
+- case to_integer(unsigned(MCycle)) is
+- when 1 =>
+- Jump <= "01";
+- LDBAL <= '1';
+- when 2 =>
+- Jump <= "01";
+- LDBAH <= '1';
+- Set_Addr_To <= "11"; -- BA
+- when 3 =>
+- LDDI <= '1';
+- Write <= '1';
+- Set_Addr_To <= "11"; -- BA
+- when 4 =>
+- Write <= '1';
+- LDALU <= '1';
+- SaveP <= '1';
+- Set_Addr_To <= "11"; -- BA
+- when 5 =>
+- SaveP <= '0'; -- MIKEJ was 1
+- when others =>
+- end case;
+- else
+- LCycle <= "011";
+- if IR(7 downto 6) /= "10" then
+- LDA <= '1';
+- end if;
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Jump <= "01";
+- LDBAL <= '1';
+- when 2 =>
+- Jump <= "01";
+- LDBAH <= '1';
+- if IR(7 downto 5) = "100" then
+- Write <= '1';
+- end if;
+- Set_Addr_To <= "11"; -- BA
+- when 3 =>
+- when others =>
+- end case;
+- end if;
+- --}}}
+-
+- 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 <= "011"; -- We're done @ T3 if branching...upper
+- -- level logic will stop at T2 if no page cross
+- -- (See the Break signal)
+- else
+-
+- LCycle <= "001";
+-
+- end if;
+-
+- -- This decodes the current microcycle and takes the
+- -- proper course of action...
+- case to_integer(unsigned(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 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 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 3 =>
+-
+-
+- when others => null; -- Do nothing.
+-
+- end case;
+- --}}}
+-
+- when "10001" | "10011" =>
+- --{{{
+- -- Zero Page Indirect Indexed (d),y
+- LCycle <= "101";
+- if IR(7 downto 6) /= "10" then
+- LDA <= '1';
+- end if;
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Jump <= "01";
+- LDAD <= '1';
+- Set_Addr_To <= "10"; -- AD
+- when 2 =>
+- LDBAL <= '1';
+- BAAdd <= "01"; -- DB Inc
+- Set_Addr_To <= "10"; -- AD
+- when 3 =>
+- Set_BusA_To <= "011"; -- Y
+- BAAdd <= "10"; -- BA Add
+- LDBAH <= '1';
+- Set_Addr_To <= "11"; -- BA
+- when 4 =>
+- BAAdd <= "11"; -- BA Adj
+- if IR(7 downto 5) = "100" then
+- Write <= '1';
+- else
+- BreakAtNA <= '1';
+- end if;
+- Set_Addr_To <= "11"; -- BA
+- when 5 =>
+- when others =>
+- end case;
+- --}}}
+-
+- when "10100" | "10101" | "10110" | "10111" =>
+- --{{{
+- -- Zero Page, X
+- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then
+- -- Read-Modify-Write
+- LCycle <= "101";
+- case to_integer(unsigned(MCycle)) is
+- when 1 =>
+- Jump <= "01";
+- LDAD <= '1';
+- Set_Addr_To <= "10"; -- AD
+- when 2 =>
+- ADAdd <= '1';
+- Set_Addr_To <= "10"; -- AD
+- when 3 =>
+- LDDI <= '1';
+- Write <= '1';
+- Set_Addr_To <= "10"; -- AD
+- when 4 =>
+- LDALU <= '1';
+- SaveP <= '1';
+- Write <= '1';
+- Set_Addr_To <= "10"; -- AD
+- when 5 =>
+- when others =>
+- end case;
+- else
+- LCycle <= "011";
+- if IR(7 downto 6) /= "10" then
+- LDA <= '1';
+- end if;
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Jump <= "01";
+- LDAD <= '1';
+- Set_Addr_To <= "10"; -- AD
+- when 2 =>
+- ADAdd <= '1';
+- -- Added this check for Y reg. use...
+- if (IR(3 downto 0) = "0110") then
+- AddY <= '1';
+- end if;
+-
+- if IR(7 downto 5) = "100" then
+- Write <= '1';
+- end if;
+- Set_Addr_To <= "10"; -- AD
+- when 3 => null;
+- when others =>
+- end case;
+- end if;
+- --}}}
+-
+- when "11001" | "11011" =>
+- --{{{
+- -- Absolute Y
+- LCycle <= "100";
+- if IR(7 downto 6) /= "10" then
+- LDA <= '1';
+- end if;
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Jump <= "01";
+- LDBAL <= '1';
+- when 2 =>
+- Jump <= "01";
+- Set_BusA_To <= "011"; -- Y
+- BAAdd <= "10"; -- BA Add
+- LDBAH <= '1';
+- Set_Addr_To <= "11"; -- BA
+- when 3 =>
+- BAAdd <= "11"; -- BA adj
+- if IR(7 downto 5) = "100" then
+- Write <= '1';
+- else
+- BreakAtNA <= '1';
+- end if;
+- Set_Addr_To <= "11"; -- BA
+- when 4 =>
+- when others =>
+- end case;
+- --}}}
+-
+- when "11100" | "11101" | "11110" | "11111" =>
+- --{{{
+- -- Absolute X
+-
+- if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then
+- -- Read-Modify-Write
+- LCycle <= "110";
+- case to_integer(unsigned(MCycle)) is
+- when 1 =>
+- Jump <= "01";
+- LDBAL <= '1';
+- when 2 =>
+- Jump <= "01";
+- Set_BusA_To <= "010"; -- X
+- BAAdd <= "10"; -- BA Add
+- LDBAH <= '1';
+- Set_Addr_To <= "11"; -- BA
+- when 3 =>
+- BAAdd <= "11"; -- BA adj
+- Set_Addr_To <= "11"; -- BA
+- when 4 =>
+- LDDI <= '1';
+- Write <= '1';
+- Set_Addr_To <= "11"; -- BA
+- when 5 =>
+- LDALU <= '1';
+- SaveP <= '1';
+- Write <= '1';
+- Set_Addr_To <= "11"; -- BA
+- when 6 =>
+- when others =>
+- end case;
+- else
+- LCycle <= "100";
+- if IR(7 downto 6) /= "10" then
+- LDA <= '1';
+- end if;
+- case to_integer(unsigned(MCycle)) is
+- when 0 =>
+- when 1 =>
+- Jump <= "01";
+- LDBAL <= '1';
+- when 2 =>
+- Jump <= "01";
+- -- mikej
+- -- special case 0xBE which uses Y reg as index!!
+- if (IR = "10111110") then
+- Set_BusA_To <= "011"; -- Y
+- else
+- Set_BusA_To <= "010"; -- X
+- end if;
+- BAAdd <= "10"; -- BA Add
+- LDBAH <= '1';
+- Set_Addr_To <= "11"; -- BA
+- when 3 =>
+- BAAdd <= "11"; -- BA adj
+- if IR(7 downto 5) = "100" then
+- Write <= '1';
+- else
+- BreakAtNA <= '1';
+- end if;
+- Set_Addr_To <= "11"; -- BA
+- when 4 =>
+- when others =>
+- end case;
+- end if;
+- --}}}
+- when others =>
+- end case;
+- end process;
+-
+- process (IR, MCycle)
+- 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
+- when "000" | "001" | "011" =>
+- case IR(7 downto 5) is
+- when "110" | "111" =>
+- -- CP
+- ALU_Op <= "0110";
+- when "101" =>
+- -- LD
+- ALU_Op <= "0101";
+- when "001" =>
+- -- BIT
+- ALU_Op <= "1100";
+- when others =>
+- -- NOP/ST
+- ALU_Op <= "0100";
+- end case;
+- when "010" =>
+- case IR(7 downto 5) is
+- when "111" | "110" =>
+- -- IN
+- ALU_Op <= "1111";
+- when "100" =>
+- -- DEY
+- ALU_Op <= "1110";
+- when others =>
+- -- LD
+- ALU_Op <= "1101";
+- end case;
+- when "110" =>
+- case IR(7 downto 5) is
+- when "100" =>
+- -- TYA
+- ALU_Op <= "1101";
+- when others =>
+- ALU_Op <= "----";
+- end case;
+- when others =>
+- case IR(7 downto 5) is
+- when "101" =>
+- -- LD
+- ALU_Op <= "1101";
+- when others =>
+- ALU_Op <= "0100";
+- end case;
+- end case;
+- --}}}
+- when "01" => -- OR
+- --{{{
+- ALU_Op(3) <= '0';
+- ALU_Op(2 downto 0) <= IR(7 downto 5);
+- --}}}
+- when "10" =>
+- --{{{
+- ALU_Op(3) <= '1';
+- ALU_Op(2 downto 0) <= IR(7 downto 5);
+- case IR(7 downto 5) is
+- when "000" =>
+- if IR(4 downto 2) = "110" then
+- -- INC
+- ALU_Op <= "1111";
+- end if;
+- when "001" =>
+- if IR(4 downto 2) = "110" then
+- -- DEC
+- ALU_Op <= "1110";
+- end if;
+- when "100" =>
+- if IR(4 downto 2) = "010" then
+- -- TXA
+- ALU_Op <= "0101";
+- else
+- ALU_Op <= "0100";
+- end if;
+- when others =>
+- end case;
+- --}}}
+- when others =>
+- --{{{
+- case IR(7 downto 5) is
+- when "100" =>
+- ALU_Op <= "0100";
+- when others =>
+- if MCycle = "000" then
+- ALU_Op(3) <= '0';
+- ALU_Op(2 downto 0) <= IR(7 downto 5);
+- else
+- ALU_Op(3) <= '1';
+- ALU_Op(2 downto 0) <= IR(7 downto 5);
+- end if;
+- end case;
+- --}}}
+- end case;
+- end process;
+-
+-end;
++-- **** ++-- T65(b) core. In an effort to merge and maintain bug fixes .... ++-- ++-- ++-- Ver 302 minor timing fixes ++-- Ver 301 Jump timing fixed ++-- Ver 300 Bugfixes by ehenciak added ++-- MikeJ March 2005 ++-- Latest version from www.fpgaarcade.com (original www.opencores.org) ++-- ++-- **** ++-- ++-- 65xx compatible microprocessor core ++-- ++-- Version : 0246 + fix ++-- ++-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) ++-- ++-- All rights reserved ++-- ++-- Redistribution and use in source and synthezised forms, with or without ++-- modification, are permitted provided that the following conditions are met: ++-- ++-- Redistributions of source code must retain the above copyright notice, ++-- this list of conditions and the following disclaimer. ++-- ++-- Redistributions in synthesized form must reproduce the above copyright ++-- notice, this list of conditions and the following disclaimer in the ++-- documentation and/or other materials provided with the distribution. ++-- ++-- Neither the name of the author nor the names of other contributors may ++-- be used to endorse or promote products derived from this software without ++-- specific prior written permission. ++-- ++-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE ++-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++-- POSSIBILITY OF SUCH DAMAGE. ++-- ++-- Please report bugs to the author, but before you do so, please ++-- make sure that this is not a derivative work and that ++-- you have the latest version of this file. ++-- ++-- The latest version of this file can be found at: ++-- http://www.opencores.org/cvsweb.shtml/t65/ ++-- ++-- Limitations : ++-- ++-- 65C02 ++-- supported : inc, dec, phx, plx, phy, ply ++-- missing : bra, ora, lda, cmp, sbc, tsb*2, trb*2, stz*2, bit*2, wai, stp, jmp, bbr*8, bbs*8 ++-- ++-- File history : ++-- ++-- 0246 : First release ++-- ++ ++library IEEE; ++use IEEE.std_logic_1164.all; ++use IEEE.numeric_std.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 std_logic_vector(2 downto 0); ++ P : in std_logic_vector(7 downto 0); ++ LCycle : out std_logic_vector(2 downto 0); ++ ALU_Op : out std_logic_vector(3 downto 0); ++ Set_BusA_To : out std_logic_vector(2 downto 0); -- DI,A,X,Y,S,P ++ Set_Addr_To : out std_logic_vector(1 downto 0); -- PC Adder,S,AD,BA ++ Write_Data : out std_logic_vector(2 downto 0); -- DL,A,X,Y,S,P,PCL,PCH ++ 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; ++ ++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 <= "001"; ++ Set_BusA_To <= "001"; -- A ++ Set_Addr_To <= (others => '0'); ++ Write_Data <= (others => '0'); ++ 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'; ++ ++ case IR(7 downto 5) is ++ when "100" => ++ --{{{ ++ case IR(1 downto 0) is ++ when "00" => ++ Set_BusA_To <= "011"; -- Y ++ Write_Data <= "011"; -- Y ++ when "10" => ++ Set_BusA_To <= "010"; -- X ++ Write_Data <= "010"; -- X ++ when others => ++ Write_Data <= "001"; -- A ++ end case; ++ --}}} ++ when "101" => ++ --{{{ ++ case IR(1 downto 0) is ++ when "00" => ++ if IR(4) /= '1' or IR(2) /= '0' then ++ LDY <= '1'; ++ end if; ++ when "10" => ++ LDX <= '1'; ++ when others => ++ LDA <= '1'; ++ end case; ++ Set_BusA_To <= "000"; -- DI ++ --}}} ++ when "110" => ++ --{{{ ++ case IR(1 downto 0) is ++ when "00" => ++ if IR(4) = '0' then ++ LDY <= '1'; ++ end if; ++ Set_BusA_To <= "011"; -- Y ++ when others => ++ Set_BusA_To <= "001"; -- A ++ end case; ++ --}}} ++ when "111" => ++ --{{{ ++ case IR(1 downto 0) is ++ when "00" => ++ if IR(4) = '0' then ++ LDX <= '1'; ++ end if; ++ Set_BusA_To <= "010"; -- X ++ when others => ++ Set_BusA_To <= "001"; -- A ++ end case; ++ --}}} ++ when others => ++ end case; ++ ++ if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then ++ Set_BusA_To <= "000"; -- DI ++ end if; ++ ++ case IR(4 downto 0) is ++ when "00000" | "01000" | "01010" | "11000" | "11010" => ++ --{{{ ++ -- Implied ++ case IR is ++ when "00000000" => ++ -- BRK ++ LCycle <= "110"; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Set_Addr_To <= "01"; -- S ++ Write_Data <= "111"; -- PCH ++ Write <= '1'; ++ when 2 => ++ Dec_S <= '1'; ++ Set_Addr_To <= "01"; -- S ++ Write_Data <= "110"; -- PCL ++ Write <= '1'; ++ when 3 => ++ Dec_S <= '1'; ++ Set_Addr_To <= "01"; -- S ++ Write_Data <= "101"; -- P ++ Write <= '1'; ++ when 4 => ++ Dec_S <= '1'; ++ Set_Addr_To <= "11"; -- BA ++ when 5 => ++ LDDI <= '1'; ++ Set_Addr_To <= "11"; -- BA ++ when 6 => ++ Jump <= "10"; -- DIDL ++ when others => ++ end case; ++ when "00100000" => ++ -- JSR ++ LCycle <= "101"; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDDI <= '1'; ++ Set_Addr_To <= "01"; -- S ++ when 2 => ++ Set_Addr_To <= "01"; -- S ++ Write_Data <= "111"; -- PCH ++ Write <= '1'; ++ when 3 => ++ Dec_S <= '1'; ++ Set_Addr_To <= "01"; -- S ++ Write_Data <= "110"; -- PCL ++ Write <= '1'; ++ when 4 => ++ Dec_S <= '1'; ++ when 5 => ++ Jump <= "10"; -- DIDL ++ when others => ++ end case; ++ when "01000000" => ++ -- RTI ++ LCycle <= "101"; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Set_Addr_To <= "01"; -- S ++ when 2 => ++ Inc_S <= '1'; ++ Set_Addr_To <= "01"; -- S ++ when 3 => ++ Inc_S <= '1'; ++ Set_Addr_To <= "01"; -- S ++ Set_BusA_To <= "000"; -- DI ++ when 4 => ++ LDP <= '1'; ++ Inc_S <= '1'; ++ LDDI <= '1'; ++ Set_Addr_To <= "01"; -- S ++ when 5 => ++ Jump <= "10"; -- DIDL ++ when others => ++ end case; ++ when "01100000" => ++ -- RTS ++ LCycle <= "101"; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Set_Addr_To <= "01"; -- S ++ when 2 => ++ Inc_S <= '1'; ++ Set_Addr_To <= "01"; -- S ++ when 3 => ++ Inc_S <= '1'; ++ LDDI <= '1'; ++ Set_Addr_To <= "01"; -- S ++ when 4 => ++ Jump <= "10"; -- DIDL ++ when 5 => ++ Jump <= "01"; ++ when others => ++ end case; ++ when "00001000" | "01001000" | "01011010" | "11011010" => ++ -- PHP, PHA, PHY*, PHX* ++ LCycle <= "010"; ++ if Mode = "00" and IR(1) = '1' then ++ LCycle <= "001"; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ case IR(7 downto 4) is ++ when "0000" => ++ Write_Data <= "101"; -- P ++ when "0100" => ++ Write_Data <= "001"; -- A ++ when "0101" => ++ Write_Data <= "011"; -- Y ++ when "1101" => ++ Write_Data <= "010"; -- X ++ when others => ++ end case; ++ Write <= '1'; ++ Set_Addr_To <= "01"; -- S ++ when 2 => ++ Dec_S <= '1'; ++ when others => ++ end case; ++ when "00101000" | "01101000" | "01111010" | "11111010" => ++ -- PLP, PLA, PLY*, PLX* ++ LCycle <= "011"; ++ if Mode = "00" and IR(1) = '1' then ++ LCycle <= "001"; ++ end if; ++ case IR(7 downto 4) is ++ when "0010" => ++ LDP <= '1'; ++ when "0110" => ++ LDA <= '1'; ++ when "0111" => ++ if Mode /= "00" then ++ LDY <= '1'; ++ end if; ++ when "1111" => ++ if Mode /= "00" then ++ LDX <= '1'; ++ end if; ++ when others => ++ end case; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ SaveP <= '1'; ++ when 1 => ++ Set_Addr_To <= "01"; -- S ++ when 2 => ++ Inc_S <= '1'; ++ Set_Addr_To <= "01"; -- S ++ when 3 => ++ Set_BusA_To <= "000"; -- DI ++ when others => ++ end case; ++ when "10100000" | "11000000" | "11100000" => ++ -- LDY, CPY, CPX ++ -- Immediate ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ when others => ++ end case; ++ when "10001000" => ++ -- DEY ++ LDY <= '1'; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Set_BusA_To <= "011"; -- Y ++ when others => ++ end case; ++ when "11001010" => ++ -- DEX ++ LDX <= '1'; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Set_BusA_To <= "010"; -- X ++ when others => ++ end case; ++ when "00011010" | "00111010" => ++ -- INC*, DEC* ++ if Mode /= "00" then ++ LDA <= '1'; -- A ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Set_BusA_To <= "100"; -- S ++ when others => ++ end case; ++ when "00001010" | "00101010" | "01001010" | "01101010" => ++ -- ASL, ROL, LSR, ROR ++ LDA <= '1'; -- A ++ Set_BusA_To <= "001"; -- A ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ when others => ++ end case; ++ when "10001010" | "10011000" => ++ -- TYA, TXA ++ LDA <= '1'; -- A ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ when others => ++ end case; ++ when "10101010" | "10101000" => ++ -- TAX, TAY ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Set_BusA_To <= "001"; -- A ++ when others => ++ end case; ++ when "10011010" => ++ -- TXS ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ LDS <= '1'; ++ when 1 => ++ when others => ++ end case; ++ when "10111010" => ++ -- TSX ++ LDX <= '1'; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Set_BusA_To <= "100"; -- S ++ when others => ++ end case; ++ ++ -- when "00011000" | "00111000" | "01011000" | "01111000" | "10111000" | "11011000" | "11111000" | "11001000" | "11101000" => ++ -- -- CLC, SEC, CLI, SEI, CLV, CLD, SED, INY, INX ++ -- case to_integer(unsigned(MCycle)) is ++ -- when 1 => ++ -- when others => ++ -- end case; ++ when others => ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when others => ++ end case; ++ end case; ++ --}}} ++ ++ when "00001" | "00011" => ++ --{{{ ++ -- Zero Page Indexed Indirect (d,x) ++ LCycle <= "101"; ++ if IR(7 downto 6) /= "10" then ++ LDA <= '1'; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ LDAD <= '1'; ++ Set_Addr_To <= "10"; -- AD ++ when 2 => ++ ADAdd <= '1'; ++ Set_Addr_To <= "10"; -- AD ++ when 3 => ++ BAAdd <= "01"; -- DB Inc ++ LDBAL <= '1'; ++ Set_Addr_To <= "10"; -- AD ++ when 4 => ++ LDBAH <= '1'; ++ if IR(7 downto 5) = "100" then ++ Write <= '1'; ++ end if; ++ Set_Addr_To <= "11"; -- BA ++ when 5 => ++ when others => ++ end case; ++ --}}} ++ ++ when "01001" | "01011" => ++ --{{{ ++ -- Immediate ++ LDA <= '1'; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ when others => ++ end case; ++ ++ --}}} ++ ++ when "00010" | "10010" => ++ --{{{ ++ -- Immediate, KIL ++ LDX <= '1'; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ if IR = "10100010" then ++ -- LDX ++ Jump <= "01"; ++ else ++ -- KIL !!!!!!!!!!!!!!!!!!!!!!!!!!!!! ++ end if; ++ when others => ++ end case; ++ --}}} ++ ++ when "00100" => ++ --{{{ ++ -- Zero Page ++ LCycle <= "010"; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ if IR(7 downto 5) = "001" then ++ SaveP <= '1'; ++ end if; ++ when 1 => ++ Jump <= "01"; ++ LDAD <= '1'; ++ if IR(7 downto 5) = "100" then ++ Write <= '1'; ++ end if; ++ Set_Addr_To <= "10"; -- AD ++ when 2 => ++ when others => ++ end case; ++ --}}} ++ ++ when "00101" | "00110" | "00111" => ++ --{{{ ++ -- Zero Page ++ if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then ++ -- Read-Modify-Write ++ LCycle <= "100"; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDAD <= '1'; ++ Set_Addr_To <= "10"; -- AD ++ when 2 => ++ LDDI <= '1'; ++ Write <= '1'; ++ Set_Addr_To <= "10"; -- AD ++ when 3 => ++ LDALU <= '1'; ++ SaveP <= '1'; ++ Write <= '1'; ++ Set_Addr_To <= "10"; -- AD ++ when 4 => ++ when others => ++ end case; ++ else ++ LCycle <= "010"; ++ if IR(7 downto 6) /= "10" then ++ LDA <= '1'; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ LDAD <= '1'; ++ if IR(7 downto 5) = "100" then ++ Write <= '1'; ++ end if; ++ Set_Addr_To <= "10"; -- AD ++ when 2 => ++ when others => ++ end case; ++ end if; ++ --}}} ++ ++ when "01100" => ++ --{{{ ++ -- Absolute ++ if IR(7 downto 6) = "01" and IR(4 downto 0) = "01100" then ++ -- JMP ++ if IR(5) = '0' then ++ --LCycle <= "011"; ++ LCycle <= "010"; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDDI <= '1'; ++ when 2 => ++ Jump <= "10"; -- DIDL ++ when others => ++ end case; ++ else ++ --LCycle <= "101"; ++ LCycle <= "100"; -- mikej ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDDI <= '1'; ++ LDBAL <= '1'; ++ when 2 => ++ LDBAH <= '1'; ++ if Mode /= "00" then ++ Jump <= "10"; -- DIDL ++ end if; ++ if Mode = "00" then ++ Set_Addr_To <= "11"; -- BA ++ end if; ++ when 3 => ++ LDDI <= '1'; ++ if Mode = "00" then ++ Set_Addr_To <= "11"; -- BA ++ BAAdd <= "01"; -- DB Inc ++ else ++ Jump <= "01"; ++ end if; ++ when 4 => ++ Jump <= "10"; -- DIDL ++ when others => ++ end case; ++ end if; ++ else ++ LCycle <= "011"; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ if IR(7 downto 5) = "001" then ++ SaveP <= '1'; ++ end if; ++ when 1 => ++ Jump <= "01"; ++ LDBAL <= '1'; ++ when 2 => ++ Jump <= "01"; ++ LDBAH <= '1'; ++ if IR(7 downto 5) = "100" then ++ Write <= '1'; ++ end if; ++ Set_Addr_To <= "11"; -- BA ++ when 3 => ++ when others => ++ end case; ++ end if; ++ --}}} ++ ++ when "01101" | "01110" | "01111" => ++ --{{{ ++ -- Absolute ++ if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then ++ -- Read-Modify-Write ++ LCycle <= "101"; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDBAL <= '1'; ++ when 2 => ++ Jump <= "01"; ++ LDBAH <= '1'; ++ Set_Addr_To <= "11"; -- BA ++ when 3 => ++ LDDI <= '1'; ++ Write <= '1'; ++ Set_Addr_To <= "11"; -- BA ++ when 4 => ++ Write <= '1'; ++ LDALU <= '1'; ++ SaveP <= '1'; ++ Set_Addr_To <= "11"; -- BA ++ when 5 => ++ SaveP <= '0'; -- MIKEJ was 1 ++ when others => ++ end case; ++ else ++ LCycle <= "011"; ++ if IR(7 downto 6) /= "10" then ++ LDA <= '1'; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ LDBAL <= '1'; ++ when 2 => ++ Jump <= "01"; ++ LDBAH <= '1'; ++ if IR(7 downto 5) = "100" then ++ Write <= '1'; ++ end if; ++ Set_Addr_To <= "11"; -- BA ++ when 3 => ++ when others => ++ end case; ++ end if; ++ --}}} ++ ++ 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 <= "011"; -- We're done @ T3 if branching...upper ++ -- level logic will stop at T2 if no page cross ++ -- (See the Break signal) ++ else ++ ++ LCycle <= "001"; ++ ++ end if; ++ ++ -- This decodes the current microcycle and takes the ++ -- proper course of action... ++ case to_integer(unsigned(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 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 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 3 => ++ ++ ++ when others => null; -- Do nothing. ++ ++ end case; ++ --}}} ++ ++ when "10001" | "10011" => ++ --{{{ ++ -- Zero Page Indirect Indexed (d),y ++ LCycle <= "101"; ++ if IR(7 downto 6) /= "10" then ++ LDA <= '1'; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ LDAD <= '1'; ++ Set_Addr_To <= "10"; -- AD ++ when 2 => ++ LDBAL <= '1'; ++ BAAdd <= "01"; -- DB Inc ++ Set_Addr_To <= "10"; -- AD ++ when 3 => ++ Set_BusA_To <= "011"; -- Y ++ BAAdd <= "10"; -- BA Add ++ LDBAH <= '1'; ++ Set_Addr_To <= "11"; -- BA ++ when 4 => ++ BAAdd <= "11"; -- BA Adj ++ if IR(7 downto 5) = "100" then ++ Write <= '1'; ++ else ++ BreakAtNA <= '1'; ++ end if; ++ Set_Addr_To <= "11"; -- BA ++ when 5 => ++ when others => ++ end case; ++ --}}} ++ ++ when "10100" | "10101" | "10110" | "10111" => ++ --{{{ ++ -- Zero Page, X ++ if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then ++ -- Read-Modify-Write ++ LCycle <= "101"; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDAD <= '1'; ++ Set_Addr_To <= "10"; -- AD ++ when 2 => ++ ADAdd <= '1'; ++ Set_Addr_To <= "10"; -- AD ++ when 3 => ++ LDDI <= '1'; ++ Write <= '1'; ++ Set_Addr_To <= "10"; -- AD ++ when 4 => ++ LDALU <= '1'; ++ SaveP <= '1'; ++ Write <= '1'; ++ Set_Addr_To <= "10"; -- AD ++ when 5 => ++ when others => ++ end case; ++ else ++ LCycle <= "011"; ++ if IR(7 downto 6) /= "10" then ++ LDA <= '1'; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ LDAD <= '1'; ++ Set_Addr_To <= "10"; -- AD ++ when 2 => ++ ADAdd <= '1'; ++ -- Added this check for Y reg. use... ++ if (IR(3 downto 0) = "0110") then ++ AddY <= '1'; ++ end if; ++ ++ if IR(7 downto 5) = "100" then ++ Write <= '1'; ++ end if; ++ Set_Addr_To <= "10"; -- AD ++ when 3 => null; ++ when others => ++ end case; ++ end if; ++ --}}} ++ ++ when "11001" | "11011" => ++ --{{{ ++ -- Absolute Y ++ LCycle <= "100"; ++ if IR(7 downto 6) /= "10" then ++ LDA <= '1'; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ LDBAL <= '1'; ++ when 2 => ++ Jump <= "01"; ++ Set_BusA_To <= "011"; -- Y ++ BAAdd <= "10"; -- BA Add ++ LDBAH <= '1'; ++ Set_Addr_To <= "11"; -- BA ++ when 3 => ++ BAAdd <= "11"; -- BA adj ++ if IR(7 downto 5) = "100" then ++ Write <= '1'; ++ else ++ BreakAtNA <= '1'; ++ end if; ++ Set_Addr_To <= "11"; -- BA ++ when 4 => ++ when others => ++ end case; ++ --}}} ++ ++ when "11100" | "11101" | "11110" | "11111" => ++ --{{{ ++ -- Absolute X ++ ++ if IR(7 downto 6) /= "10" and IR(1 downto 0) = "10" then ++ -- Read-Modify-Write ++ LCycle <= "110"; ++ case to_integer(unsigned(MCycle)) is ++ when 1 => ++ Jump <= "01"; ++ LDBAL <= '1'; ++ when 2 => ++ Jump <= "01"; ++ Set_BusA_To <= "010"; -- X ++ BAAdd <= "10"; -- BA Add ++ LDBAH <= '1'; ++ Set_Addr_To <= "11"; -- BA ++ when 3 => ++ BAAdd <= "11"; -- BA adj ++ Set_Addr_To <= "11"; -- BA ++ when 4 => ++ LDDI <= '1'; ++ Write <= '1'; ++ Set_Addr_To <= "11"; -- BA ++ when 5 => ++ LDALU <= '1'; ++ SaveP <= '1'; ++ Write <= '1'; ++ Set_Addr_To <= "11"; -- BA ++ when 6 => ++ when others => ++ end case; ++ else ++ LCycle <= "100"; ++ if IR(7 downto 6) /= "10" then ++ LDA <= '1'; ++ end if; ++ case to_integer(unsigned(MCycle)) is ++ when 0 => ++ when 1 => ++ Jump <= "01"; ++ LDBAL <= '1'; ++ when 2 => ++ Jump <= "01"; ++ -- mikej ++ -- special case 0xBE which uses Y reg as index!! ++ if (IR = "10111110") then ++ Set_BusA_To <= "011"; -- Y ++ else ++ Set_BusA_To <= "010"; -- X ++ end if; ++ BAAdd <= "10"; -- BA Add ++ LDBAH <= '1'; ++ Set_Addr_To <= "11"; -- BA ++ when 3 => ++ BAAdd <= "11"; -- BA adj ++ if IR(7 downto 5) = "100" then ++ Write <= '1'; ++ else ++ BreakAtNA <= '1'; ++ end if; ++ Set_Addr_To <= "11"; -- BA ++ when 4 => ++ when others => ++ end case; ++ end if; ++ --}}} ++ when others => ++ end case; ++ end process; ++ ++ process (IR, MCycle) ++ 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 ++ when "000" | "001" | "011" => ++ case IR(7 downto 5) is ++ when "110" | "111" => ++ -- CP ++ ALU_Op <= "0110"; ++ when "101" => ++ -- LD ++ ALU_Op <= "0101"; ++ when "001" => ++ -- BIT ++ ALU_Op <= "1100"; ++ when others => ++ -- NOP/ST ++ ALU_Op <= "0100"; ++ end case; ++ when "010" => ++ case IR(7 downto 5) is ++ when "111" | "110" => ++ -- IN ++ ALU_Op <= "1111"; ++ when "100" => ++ -- DEY ++ ALU_Op <= "1110"; ++ when others => ++ -- LD ++ ALU_Op <= "1101"; ++ end case; ++ when "110" => ++ case IR(7 downto 5) is ++ when "100" => ++ -- TYA ++ ALU_Op <= "1101"; ++ when others => ++ ALU_Op <= "----"; ++ end case; ++ when others => ++ case IR(7 downto 5) is ++ when "101" => ++ -- LD ++ ALU_Op <= "1101"; ++ when others => ++ ALU_Op <= "0100"; ++ end case; ++ end case; ++ --}}} ++ when "01" => -- OR ++ --{{{ ++ ALU_Op(3) <= '0'; ++ ALU_Op(2 downto 0) <= IR(7 downto 5); ++ --}}} ++ when "10" => ++ --{{{ ++ ALU_Op(3) <= '1'; ++ ALU_Op(2 downto 0) <= IR(7 downto 5); ++ case IR(7 downto 5) is ++ when "000" => ++ if IR(4 downto 2) = "110" then ++ -- INC ++ ALU_Op <= "1111"; ++ end if; ++ when "001" => ++ if IR(4 downto 2) = "110" then ++ -- DEC ++ ALU_Op <= "1110"; ++ end if; ++ when "100" => ++ if IR(4 downto 2) = "010" then ++ -- TXA ++ ALU_Op <= "0101"; ++ else ++ ALU_Op <= "0100"; ++ end if; ++ when others => ++ end case; ++ --}}} ++ when others => ++ --{{{ ++ case IR(7 downto 5) is ++ when "100" => ++ ALU_Op <= "0100"; ++ when others => ++ if MCycle = "000" then ++ ALU_Op(3) <= '0'; ++ ALU_Op(2 downto 0) <= IR(7 downto 5); ++ else ++ ALU_Op(3) <= '1'; ++ ALU_Op(2 downto 0) <= IR(7 downto 5); ++ end if; ++ end case; ++ --}}} ++ end case; ++ end process; ++ ++end; +diff --git a/T65/T65_Pack.vhd b/T65/T65_Pack.vhd +index f8d603c..e025e1b 100644 +--- a/T65/T65_Pack.vhd ++++ b/T65/T65_Pack.vhd +@@ -1,117 +1,117 @@ +--- ****
+--- T65(b) core. In an effort to merge and maintain bug fixes ....
+---
+---
+--- Ver 300 Bugfixes by ehenciak added
+--- MikeJ March 2005
+--- Latest version from www.fpgaarcade.com (original www.opencores.org)
+---
+--- ****
+---
+--- 65xx compatible microprocessor core
+---
+--- Version : 0246
+---
+--- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org)
+---
+--- All rights reserved
+---
+--- Redistribution and use in source and synthezised forms, with or without
+--- modification, are permitted provided that the following conditions are met:
+---
+--- Redistributions of source code must retain the above copyright notice,
+--- this list of conditions and the following disclaimer.
+---
+--- Redistributions in synthesized form must reproduce the above copyright
+--- notice, this list of conditions and the following disclaimer in the
+--- documentation and/or other materials provided with the distribution.
+---
+--- Neither the name of the author nor the names of other contributors may
+--- be used to endorse or promote products derived from this software without
+--- specific prior written permission.
+---
+--- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+--- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
+--- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+--- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+--- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+--- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+--- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+--- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+--- POSSIBILITY OF SUCH DAMAGE.
+---
+--- Please report bugs to the author, but before you do so, please
+--- make sure that this is not a derivative work and that
+--- you have the latest version of this file.
+---
+--- The latest version of this file can be found at:
+--- http://www.opencores.org/cvsweb.shtml/t65/
+---
+--- Limitations :
+---
+--- File history :
+---
+-
+-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;
+-
+- component T65_MCode
+- 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 std_logic_vector(2 downto 0);
+- P : in std_logic_vector(7 downto 0);
+- LCycle : out std_logic_vector(2 downto 0);
+- ALU_Op : out std_logic_vector(3 downto 0);
+- Set_BusA_To : out std_logic_vector(2 downto 0); -- DI,A,X,Y,S,P
+- Set_Addr_To : out std_logic_vector(1 downto 0); -- PC Adder,S,AD,BA
+- Write_Data : out std_logic_vector(2 downto 0); -- DL,A,X,Y,S,P,PCL,PCH
+- 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 component;
+-
+- component T65_ALU
+- port(
+- Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816
+- Op : in std_logic_vector(3 downto 0);
+- 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 component;
+-
+-end;
++-- **** ++-- T65(b) core. In an effort to merge and maintain bug fixes .... ++-- ++-- ++-- Ver 300 Bugfixes by ehenciak added ++-- MikeJ March 2005 ++-- Latest version from www.fpgaarcade.com (original www.opencores.org) ++-- ++-- **** ++-- ++-- 65xx compatible microprocessor core ++-- ++-- Version : 0246 ++-- ++-- Copyright (c) 2002 Daniel Wallner (jesus@opencores.org) ++-- ++-- All rights reserved ++-- ++-- Redistribution and use in source and synthezised forms, with or without ++-- modification, are permitted provided that the following conditions are met: ++-- ++-- Redistributions of source code must retain the above copyright notice, ++-- this list of conditions and the following disclaimer. ++-- ++-- Redistributions in synthesized form must reproduce the above copyright ++-- notice, this list of conditions and the following disclaimer in the ++-- documentation and/or other materials provided with the distribution. ++-- ++-- Neither the name of the author nor the names of other contributors may ++-- be used to endorse or promote products derived from this software without ++-- specific prior written permission. ++-- ++-- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" ++-- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, ++-- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR ++-- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE ++-- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR ++-- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF ++-- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS ++-- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN ++-- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ++-- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE ++-- POSSIBILITY OF SUCH DAMAGE. ++-- ++-- Please report bugs to the author, but before you do so, please ++-- make sure that this is not a derivative work and that ++-- you have the latest version of this file. ++-- ++-- The latest version of this file can be found at: ++-- http://www.opencores.org/cvsweb.shtml/t65/ ++-- ++-- Limitations : ++-- ++-- File history : ++-- ++ ++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; ++ ++ component T65_MCode ++ 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 std_logic_vector(2 downto 0); ++ P : in std_logic_vector(7 downto 0); ++ LCycle : out std_logic_vector(2 downto 0); ++ ALU_Op : out std_logic_vector(3 downto 0); ++ Set_BusA_To : out std_logic_vector(2 downto 0); -- DI,A,X,Y,S,P ++ Set_Addr_To : out std_logic_vector(1 downto 0); -- PC Adder,S,AD,BA ++ Write_Data : out std_logic_vector(2 downto 0); -- DL,A,X,Y,S,P,PCL,PCH ++ 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 component; ++ ++ component T65_ALU ++ port( ++ Mode : in std_logic_vector(1 downto 0); -- "00" => 6502, "01" => 65C02, "10" => 65C816 ++ Op : in std_logic_vector(3 downto 0); ++ 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 component; ++ ++end; +diff --git a/bbc_micro.qpf b/bbc_micro.qpf +index 52e0fd0..c2ade9e 100644 +--- a/bbc_micro.qpf ++++ b/bbc_micro.qpf +@@ -1,30 +1,30 @@ +-# -------------------------------------------------------------------------- #
+-#
+-# Copyright (C) 1991-2009 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.
+-#
+-# -------------------------------------------------------------------------- #
+-#
+-# Quartus II
+-# Version 9.1 Build 222 10/21/2009 SJ Web Edition
+-# Date created = 20:48:44 July 12, 2011
+-#
+-# -------------------------------------------------------------------------- #
+-
+-QUARTUS_VERSION = "9.1"
+-DATE = "20:48:44 July 12, 2011"
+-
+-# Revisions
+-
+-PROJECT_REVISION = "bbc_micro_de1"
++# -------------------------------------------------------------------------- # ++# ++# Copyright (C) 1991-2009 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. ++# ++# -------------------------------------------------------------------------- # ++# ++# Quartus II ++# Version 9.1 Build 222 10/21/2009 SJ Web Edition ++# Date created = 20:48:44 July 12, 2011 ++# ++# -------------------------------------------------------------------------- # ++ ++QUARTUS_VERSION = "9.1" ++DATE = "20:48:44 July 12, 2011" ++ ++# Revisions ++ ++PROJECT_REVISION = "bbc_micro_de1" +diff --git a/bbc_micro_de1.qsf b/bbc_micro_de1.qsf +index be8b1f2..0ae4816 100644 +--- a/bbc_micro_de1.qsf ++++ b/bbc_micro_de1.qsf +@@ -1,537 +1,537 @@ +-# -------------------------------------------------------------------------- #
+-#
+-# Copyright (C) 1991-2009 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.
+-#
+-# -------------------------------------------------------------------------- #
+-#
+-# Quartus II
+-# Version 9.1 Build 222 10/21/2009 SJ Web Edition
+-# Date created = 20:48:44 July 12, 2011
+-#
+-# -------------------------------------------------------------------------- #
+-#
+-# Notes:
+-#
+-# 1) The default values for assignments are stored in the file:
+-# bbc_micro_de1_assignment_defaults.qdf
+-# If this file doesn't exist, see file:
+-# assignment_defaults.qdf
+-#
+-# 2) Altera recommends that you do not modify this file. This
+-# file is updated automatically by the Quartus II software
+-# and any changes you make may be lost or overwritten.
+-#
+-# -------------------------------------------------------------------------- #
+-
+-
+-set_global_assignment -name FAMILY "Cyclone II"
+-set_global_assignment -name DEVICE EP2C20F484C7
+-set_global_assignment -name TOP_LEVEL_ENTITY bbc_micro_de1
+-set_global_assignment -name ORIGINAL_QUARTUS_VERSION 9.1
+-set_global_assignment -name PROJECT_CREATION_TIME_DATE "20:48:44 JULY 12, 2011"
+-set_global_assignment -name LAST_QUARTUS_VERSION 9.1
+-set_global_assignment -name USE_GENERATED_PHYSICAL_CONSTRAINTS OFF -section_id eda_blast_fpga
+-set_global_assignment -name DEVICE_FILTER_PACKAGE FBGA
+-set_global_assignment -name DEVICE_FILTER_PIN_COUNT 484
+-set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 7
+-set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
+-set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
+-set_location_assignment PIN_A13 -to GPIO_0[0]
+-set_location_assignment PIN_B13 -to GPIO_0[1]
+-set_location_assignment PIN_A14 -to GPIO_0[2]
+-set_location_assignment PIN_B14 -to GPIO_0[3]
+-set_location_assignment PIN_A15 -to GPIO_0[4]
+-set_location_assignment PIN_B15 -to GPIO_0[5]
+-set_location_assignment PIN_A16 -to GPIO_0[6]
+-set_location_assignment PIN_B16 -to GPIO_0[7]
+-set_location_assignment PIN_A17 -to GPIO_0[8]
+-set_location_assignment PIN_B17 -to GPIO_0[9]
+-set_location_assignment PIN_A18 -to GPIO_0[10]
+-set_location_assignment PIN_B18 -to GPIO_0[11]
+-set_location_assignment PIN_A19 -to GPIO_0[12]
+-set_location_assignment PIN_B19 -to GPIO_0[13]
+-set_location_assignment PIN_A20 -to GPIO_0[14]
+-set_location_assignment PIN_B20 -to GPIO_0[15]
+-set_location_assignment PIN_C21 -to GPIO_0[16]
+-set_location_assignment PIN_C22 -to GPIO_0[17]
+-set_location_assignment PIN_D21 -to GPIO_0[18]
+-set_location_assignment PIN_D22 -to GPIO_0[19]
+-set_location_assignment PIN_E21 -to GPIO_0[20]
+-set_location_assignment PIN_E22 -to GPIO_0[21]
+-set_location_assignment PIN_F21 -to GPIO_0[22]
+-set_location_assignment PIN_F22 -to GPIO_0[23]
+-set_location_assignment PIN_G21 -to GPIO_0[24]
+-set_location_assignment PIN_G22 -to GPIO_0[25]
+-set_location_assignment PIN_J21 -to GPIO_0[26]
+-set_location_assignment PIN_J22 -to GPIO_0[27]
+-set_location_assignment PIN_K21 -to GPIO_0[28]
+-set_location_assignment PIN_K22 -to GPIO_0[29]
+-set_location_assignment PIN_J19 -to GPIO_0[30]
+-set_location_assignment PIN_J20 -to GPIO_0[31]
+-set_location_assignment PIN_J18 -to GPIO_0[32]
+-set_location_assignment PIN_K20 -to GPIO_0[33]
+-set_location_assignment PIN_L19 -to GPIO_0[34]
+-set_location_assignment PIN_L18 -to GPIO_0[35]
+-set_location_assignment PIN_H12 -to GPIO_1[0]
+-set_location_assignment PIN_H13 -to GPIO_1[1]
+-set_location_assignment PIN_H14 -to GPIO_1[2]
+-set_location_assignment PIN_G15 -to GPIO_1[3]
+-set_location_assignment PIN_E14 -to GPIO_1[4]
+-set_location_assignment PIN_E15 -to GPIO_1[5]
+-set_location_assignment PIN_F15 -to GPIO_1[6]
+-set_location_assignment PIN_G16 -to GPIO_1[7]
+-set_location_assignment PIN_F12 -to GPIO_1[8]
+-set_location_assignment PIN_F13 -to GPIO_1[9]
+-set_location_assignment PIN_C14 -to GPIO_1[10]
+-set_location_assignment PIN_D14 -to GPIO_1[11]
+-set_location_assignment PIN_D15 -to GPIO_1[12]
+-set_location_assignment PIN_D16 -to GPIO_1[13]
+-set_location_assignment PIN_C17 -to GPIO_1[14]
+-set_location_assignment PIN_C18 -to GPIO_1[15]
+-set_location_assignment PIN_C19 -to GPIO_1[16]
+-set_location_assignment PIN_C20 -to GPIO_1[17]
+-set_location_assignment PIN_D19 -to GPIO_1[18]
+-set_location_assignment PIN_D20 -to GPIO_1[19]
+-set_location_assignment PIN_E20 -to GPIO_1[20]
+-set_location_assignment PIN_F20 -to GPIO_1[21]
+-set_location_assignment PIN_E19 -to GPIO_1[22]
+-set_location_assignment PIN_E18 -to GPIO_1[23]
+-set_location_assignment PIN_G20 -to GPIO_1[24]
+-set_location_assignment PIN_G18 -to GPIO_1[25]
+-set_location_assignment PIN_G17 -to GPIO_1[26]
+-set_location_assignment PIN_H17 -to GPIO_1[27]
+-set_location_assignment PIN_J15 -to GPIO_1[28]
+-set_location_assignment PIN_H18 -to GPIO_1[29]
+-set_location_assignment PIN_N22 -to GPIO_1[30]
+-set_location_assignment PIN_N21 -to GPIO_1[31]
+-set_location_assignment PIN_P15 -to GPIO_1[32]
+-set_location_assignment PIN_N15 -to GPIO_1[33]
+-set_location_assignment PIN_P17 -to GPIO_1[34]
+-set_location_assignment PIN_P18 -to GPIO_1[35]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[2]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[3]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[4]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[5]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[6]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[7]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[8]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[9]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[10]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[11]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[12]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[13]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[14]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[15]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[16]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[17]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[18]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[19]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[20]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[21]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[22]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[23]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[24]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[25]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[26]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[27]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[28]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[29]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[30]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[31]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[32]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[33]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[34]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[35]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[2]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[3]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[4]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[5]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[6]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[7]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[8]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[9]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[10]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[11]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[12]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[13]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[14]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[15]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[16]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[17]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[18]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[19]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[20]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[21]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[22]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[23]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[24]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[25]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[26]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[27]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[28]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[29]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[30]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[31]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[32]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[33]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[34]
+-set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[35]
+-set_location_assignment PIN_L22 -to SW[0]
+-set_location_assignment PIN_L21 -to SW[1]
+-set_location_assignment PIN_M22 -to SW[2]
+-set_location_assignment PIN_V12 -to SW[3]
+-set_location_assignment PIN_W12 -to SW[4]
+-set_location_assignment PIN_U12 -to SW[5]
+-set_location_assignment PIN_U11 -to SW[6]
+-set_location_assignment PIN_M2 -to SW[7]
+-set_location_assignment PIN_M1 -to SW[8]
+-set_location_assignment PIN_L2 -to SW[9]
+-set_instance_assignment -name IO_STANDARD LVTTL -to SW[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to SW[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to SW[2]
+-set_instance_assignment -name IO_STANDARD LVTTL -to SW[3]
+-set_instance_assignment -name IO_STANDARD LVTTL -to SW[4]
+-set_instance_assignment -name IO_STANDARD LVTTL -to SW[5]
+-set_instance_assignment -name IO_STANDARD LVTTL -to SW[6]
+-set_instance_assignment -name IO_STANDARD LVTTL -to SW[7]
+-set_instance_assignment -name IO_STANDARD LVTTL -to SW[8]
+-set_instance_assignment -name IO_STANDARD LVTTL -to SW[9]
+-set_location_assignment PIN_J2 -to HEX0[0]
+-set_location_assignment PIN_J1 -to HEX0[1]
+-set_location_assignment PIN_H2 -to HEX0[2]
+-set_location_assignment PIN_H1 -to HEX0[3]
+-set_location_assignment PIN_F2 -to HEX0[4]
+-set_location_assignment PIN_F1 -to HEX0[5]
+-set_location_assignment PIN_E2 -to HEX0[6]
+-set_location_assignment PIN_E1 -to HEX1[0]
+-set_location_assignment PIN_H6 -to HEX1[1]
+-set_location_assignment PIN_H5 -to HEX1[2]
+-set_location_assignment PIN_H4 -to HEX1[3]
+-set_location_assignment PIN_G3 -to HEX1[4]
+-set_location_assignment PIN_D2 -to HEX1[5]
+-set_location_assignment PIN_D1 -to HEX1[6]
+-set_location_assignment PIN_G5 -to HEX2[0]
+-set_location_assignment PIN_G6 -to HEX2[1]
+-set_location_assignment PIN_C2 -to HEX2[2]
+-set_location_assignment PIN_C1 -to HEX2[3]
+-set_location_assignment PIN_E3 -to HEX2[4]
+-set_location_assignment PIN_E4 -to HEX2[5]
+-set_location_assignment PIN_D3 -to HEX2[6]
+-set_location_assignment PIN_F4 -to HEX3[0]
+-set_location_assignment PIN_D5 -to HEX3[1]
+-set_location_assignment PIN_D6 -to HEX3[2]
+-set_location_assignment PIN_J4 -to HEX3[3]
+-set_location_assignment PIN_L8 -to HEX3[4]
+-set_location_assignment PIN_F3 -to HEX3[5]
+-set_location_assignment PIN_D4 -to HEX3[6]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[2]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[3]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[4]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[5]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[6]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[2]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[3]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[4]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[5]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[6]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[2]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[3]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[4]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[5]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[6]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[2]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[3]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[4]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[5]
+-set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[6]
+-set_location_assignment PIN_R22 -to KEY[0]
+-set_location_assignment PIN_R21 -to KEY[1]
+-set_location_assignment PIN_T22 -to KEY[2]
+-set_location_assignment PIN_T21 -to KEY[3]
+-set_location_assignment PIN_R20 -to LEDR[0]
+-set_location_assignment PIN_R19 -to LEDR[1]
+-set_location_assignment PIN_U19 -to LEDR[2]
+-set_location_assignment PIN_Y19 -to LEDR[3]
+-set_location_assignment PIN_T18 -to LEDR[4]
+-set_location_assignment PIN_V19 -to LEDR[5]
+-set_location_assignment PIN_Y18 -to LEDR[6]
+-set_location_assignment PIN_U18 -to LEDR[7]
+-set_location_assignment PIN_R18 -to LEDR[8]
+-set_location_assignment PIN_R17 -to LEDR[9]
+-set_location_assignment PIN_U22 -to LEDG[0]
+-set_location_assignment PIN_U21 -to LEDG[1]
+-set_location_assignment PIN_V22 -to LEDG[2]
+-set_location_assignment PIN_V21 -to LEDG[3]
+-set_location_assignment PIN_W22 -to LEDG[4]
+-set_location_assignment PIN_W21 -to LEDG[5]
+-set_location_assignment PIN_Y22 -to LEDG[6]
+-set_location_assignment PIN_Y21 -to LEDG[7]
+-set_instance_assignment -name IO_STANDARD LVTTL -to KEY[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to KEY[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to KEY[2]
+-set_instance_assignment -name IO_STANDARD LVTTL -to KEY[3]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[2]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[3]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[4]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[5]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[6]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[7]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[8]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[9]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[2]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[3]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[4]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[5]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[6]
+-set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[7]
+-set_location_assignment PIN_D12 -to CLOCK_27[0]
+-set_location_assignment PIN_E12 -to CLOCK_27[1]
+-set_location_assignment PIN_B12 -to CLOCK_24[0]
+-set_location_assignment PIN_A12 -to CLOCK_24[1]
+-set_location_assignment PIN_L1 -to CLOCK_50
+-set_location_assignment PIN_M21 -to EXT_CLOCK
+-set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_27[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_24[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_24[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_50
+-set_instance_assignment -name IO_STANDARD LVTTL -to EXT_CLOCK
+-set_location_assignment PIN_H15 -to PS2_CLK
+-set_location_assignment PIN_J14 -to PS2_DAT
+-set_location_assignment PIN_F14 -to UART_RXD
+-set_location_assignment PIN_G12 -to UART_TXD
+-set_instance_assignment -name IO_STANDARD LVTTL -to PS2_CLK
+-set_instance_assignment -name IO_STANDARD LVTTL -to PS2_DAT
+-set_instance_assignment -name IO_STANDARD LVTTL -to UART_RXD
+-set_instance_assignment -name IO_STANDARD LVTTL -to UART_TXD
+-set_location_assignment PIN_E8 -to TDI
+-set_location_assignment PIN_D8 -to TCS
+-set_location_assignment PIN_C7 -to TCK
+-set_location_assignment PIN_D7 -to TDO
+-set_instance_assignment -name IO_STANDARD LVTTL -to TDI
+-set_instance_assignment -name IO_STANDARD LVTTL -to TCS
+-set_instance_assignment -name IO_STANDARD LVTTL -to TCK
+-set_instance_assignment -name IO_STANDARD LVTTL -to TDO
+-set_location_assignment PIN_D9 -to VGA_R[0]
+-set_location_assignment PIN_C9 -to VGA_R[1]
+-set_location_assignment PIN_A7 -to VGA_R[2]
+-set_location_assignment PIN_B7 -to VGA_R[3]
+-set_location_assignment PIN_B8 -to VGA_G[0]
+-set_location_assignment PIN_C10 -to VGA_G[1]
+-set_location_assignment PIN_B9 -to VGA_G[2]
+-set_location_assignment PIN_A8 -to VGA_G[3]
+-set_location_assignment PIN_A9 -to VGA_B[0]
+-set_location_assignment PIN_D11 -to VGA_B[1]
+-set_location_assignment PIN_A10 -to VGA_B[2]
+-set_location_assignment PIN_B10 -to VGA_B[3]
+-set_location_assignment PIN_A11 -to VGA_HS
+-set_location_assignment PIN_B11 -to VGA_VS
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[2]
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[3]
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[2]
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[3]
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[0]
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[1]
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[2]
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[3]
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_HS
+-set_instance_assignment -name IO_STANDARD LVTTL -to VGA_VS
+-set_location_assignment PIN_A3 -to I2C_SCLK
+-set_location_assignment PIN_B3 -to I2C_SDAT
+-set_location_assignment PIN_A6 -to AUD_ADCLRCK
+-set_location_assignment PIN_B6 -to AUD_ADCDAT
+-set_location_assignment PIN_A5 -to AUD_DACLRCK
+-set_location_assignment PIN_B5 -to AUD_DACDAT
+-set_location_assignment PIN_B4 -to AUD_XCK
+-set_location_assignment PIN_A4 -to AUD_BCLK
+-set_instance_assignment -name IO_STANDARD LVTTL -to I2C_SCLK
+-set_instance_assignment -name IO_STANDARD LVTTL -to I2C_SDAT
+-set_instance_assignment -name IO_STANDARD LVTTL -to AUD_ADCLRCK
+-set_instance_assignment -name IO_STANDARD LVTTL -to AUD_ADCDAT
+-set_instance_assignment -name IO_STANDARD LVTTL -to AUD_DACLRCK
+-set_instance_assignment -name IO_STANDARD LVTTL -to AUD_DACDAT
+-set_instance_assignment -name IO_STANDARD LVTTL -to AUD_XCK
+-set_instance_assignment -name IO_STANDARD LVTTL -to AUD_BCLK
+-set_location_assignment PIN_W4 -to DRAM_ADDR[0]
+-set_location_assignment PIN_W5 -to DRAM_ADDR[1]
+-set_location_assignment PIN_Y3 -to DRAM_ADDR[2]
+-set_location_assignment PIN_Y4 -to DRAM_ADDR[3]
+-set_location_assignment PIN_R6 -to DRAM_ADDR[4]
+-set_location_assignment PIN_R5 -to DRAM_ADDR[5]
+-set_location_assignment PIN_P6 -to DRAM_ADDR[6]
+-set_location_assignment PIN_P5 -to DRAM_ADDR[7]
+-set_location_assignment PIN_P3 -to DRAM_ADDR[8]
+-set_location_assignment PIN_N4 -to DRAM_ADDR[9]
+-set_location_assignment PIN_W3 -to DRAM_ADDR[10]
+-set_location_assignment PIN_N6 -to DRAM_ADDR[11]
+-set_location_assignment PIN_U3 -to DRAM_BA_0
+-set_location_assignment PIN_V4 -to DRAM_BA_1
+-set_location_assignment PIN_T3 -to DRAM_CAS_N
+-set_location_assignment PIN_N3 -to DRAM_CKE
+-set_location_assignment PIN_U4 -to DRAM_CLK
+-set_location_assignment PIN_T6 -to DRAM_CS_N
+-set_location_assignment PIN_U1 -to DRAM_DQ[0]
+-set_location_assignment PIN_U2 -to DRAM_DQ[1]
+-set_location_assignment PIN_V1 -to DRAM_DQ[2]
+-set_location_assignment PIN_V2 -to DRAM_DQ[3]
+-set_location_assignment PIN_W1 -to DRAM_DQ[4]
+-set_location_assignment PIN_W2 -to DRAM_DQ[5]
+-set_location_assignment PIN_Y1 -to DRAM_DQ[6]
+-set_location_assignment PIN_Y2 -to DRAM_DQ[7]
+-set_location_assignment PIN_N1 -to DRAM_DQ[8]
+-set_location_assignment PIN_N2 -to DRAM_DQ[9]
+-set_location_assignment PIN_P1 -to DRAM_DQ[10]
+-set_location_assignment PIN_P2 -to DRAM_DQ[11]
+-set_location_assignment PIN_R1 -to DRAM_DQ[12]
+-set_location_assignment PIN_R2 -to DRAM_DQ[13]
+-set_location_assignment PIN_T1 -to DRAM_DQ[14]
+-set_location_assignment PIN_T2 -to DRAM_DQ[15]
+-set_location_assignment PIN_R7 -to DRAM_LDQM
+-set_location_assignment PIN_T5 -to DRAM_RAS_N
+-set_location_assignment PIN_M5 -to DRAM_UDQM
+-set_location_assignment PIN_R8 -to DRAM_WE_N
+-set_location_assignment PIN_AB20 -to FL_ADDR[0]
+-set_location_assignment PIN_AA14 -to FL_ADDR[1]
+-set_location_assignment PIN_Y16 -to FL_ADDR[2]
+-set_location_assignment PIN_R15 -to FL_ADDR[3]
+-set_location_assignment PIN_T15 -to FL_ADDR[4]
+-set_location_assignment PIN_U15 -to FL_ADDR[5]
+-set_location_assignment PIN_V15 -to FL_ADDR[6]
+-set_location_assignment PIN_W15 -to FL_ADDR[7]
+-set_location_assignment PIN_R14 -to FL_ADDR[8]
+-set_location_assignment PIN_Y13 -to FL_ADDR[9]
+-set_location_assignment PIN_R12 -to FL_ADDR[10]
+-set_location_assignment PIN_T12 -to FL_ADDR[11]
+-set_location_assignment PIN_AB14 -to FL_ADDR[12]
+-set_location_assignment PIN_AA13 -to FL_ADDR[13]
+-set_location_assignment PIN_AB13 -to FL_ADDR[14]
+-set_location_assignment PIN_AA12 -to FL_ADDR[15]
+-set_location_assignment PIN_AB12 -to FL_ADDR[16]
+-set_location_assignment PIN_AA20 -to FL_ADDR[17]
+-set_location_assignment PIN_U14 -to FL_ADDR[18]
+-set_location_assignment PIN_V14 -to FL_ADDR[19]
+-set_location_assignment PIN_U13 -to FL_ADDR[20]
+-set_location_assignment PIN_R13 -to FL_ADDR[21]
+-set_location_assignment PIN_AB16 -to FL_DQ[0]
+-set_location_assignment PIN_AA16 -to FL_DQ[1]
+-set_location_assignment PIN_AB17 -to FL_DQ[2]
+-set_location_assignment PIN_AA17 -to FL_DQ[3]
+-set_location_assignment PIN_AB18 -to FL_DQ[4]
+-set_location_assignment PIN_AA18 -to FL_DQ[5]
+-set_location_assignment PIN_AB19 -to FL_DQ[6]
+-set_location_assignment PIN_AA19 -to FL_DQ[7]
+-set_location_assignment PIN_AA15 -to FL_OE_N
+-set_location_assignment PIN_W14 -to FL_RST_N
+-set_location_assignment PIN_Y14 -to FL_WE_N
+-set_location_assignment PIN_AA3 -to SRAM_ADDR[0]
+-set_location_assignment PIN_AB3 -to SRAM_ADDR[1]
+-set_location_assignment PIN_AA4 -to SRAM_ADDR[2]
+-set_location_assignment PIN_AB4 -to SRAM_ADDR[3]
+-set_location_assignment PIN_AA5 -to SRAM_ADDR[4]
+-set_location_assignment PIN_AB10 -to SRAM_ADDR[5]
+-set_location_assignment PIN_AA11 -to SRAM_ADDR[6]
+-set_location_assignment PIN_AB11 -to SRAM_ADDR[7]
+-set_location_assignment PIN_V11 -to SRAM_ADDR[8]
+-set_location_assignment PIN_W11 -to SRAM_ADDR[9]
+-set_location_assignment PIN_R11 -to SRAM_ADDR[10]
+-set_location_assignment PIN_T11 -to SRAM_ADDR[11]
+-set_location_assignment PIN_Y10 -to SRAM_ADDR[12]
+-set_location_assignment PIN_U10 -to SRAM_ADDR[13]
+-set_location_assignment PIN_R10 -to SRAM_ADDR[14]
+-set_location_assignment PIN_T7 -to SRAM_ADDR[15]
+-set_location_assignment PIN_Y6 -to SRAM_ADDR[16]
+-set_location_assignment PIN_Y5 -to SRAM_ADDR[17]
+-set_location_assignment PIN_AB5 -to SRAM_CE_N
+-set_location_assignment PIN_AA6 -to SRAM_DQ[0]
+-set_location_assignment PIN_AB6 -to SRAM_DQ[1]
+-set_location_assignment PIN_AA7 -to SRAM_DQ[2]
+-set_location_assignment PIN_AB7 -to SRAM_DQ[3]
+-set_location_assignment PIN_AA8 -to SRAM_DQ[4]
+-set_location_assignment PIN_AB8 -to SRAM_DQ[5]
+-set_location_assignment PIN_AA9 -to SRAM_DQ[6]
+-set_location_assignment PIN_AB9 -to SRAM_DQ[7]
+-set_location_assignment PIN_Y9 -to SRAM_DQ[8]
+-set_location_assignment PIN_W9 -to SRAM_DQ[9]
+-set_location_assignment PIN_V9 -to SRAM_DQ[10]
+-set_location_assignment PIN_U9 -to SRAM_DQ[11]
+-set_location_assignment PIN_R9 -to SRAM_DQ[12]
+-set_location_assignment PIN_W8 -to SRAM_DQ[13]
+-set_location_assignment PIN_V8 -to SRAM_DQ[14]
+-set_location_assignment PIN_U8 -to SRAM_DQ[15]
+-set_location_assignment PIN_Y7 -to SRAM_LB_N
+-set_location_assignment PIN_T8 -to SRAM_OE_N
+-set_location_assignment PIN_W7 -to SRAM_UB_N
+-set_location_assignment PIN_AA10 -to SRAM_WE_N
+-set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED WITH WEAK PULL-UP"
+-set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
+-set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
+-set_global_assignment -name LL_ROOT_REGION ON -section_id "Root Region"
+-set_global_assignment -name LL_MEMBER_STATE LOCKED -section_id "Root Region"
+-set_global_assignment -name MISC_FILE "U:/git_repos/fpga/bbc/bbc_micro_de1.dpf"
+-set_location_assignment PIN_AB15 -to FL_CE_N
+-set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL"
+-set_global_assignment -name STRATIX_CONFIGURATION_DEVICE EPCS4
+-set_global_assignment -name RESERVE_ASDO_AFTER_CONFIGURATION "AS INPUT TRI-STATED"
+-set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO"
+-set_location_assignment PIN_U20 -to SD_nCS
+-set_location_assignment PIN_V20 -to SD_SCLK
+-set_location_assignment PIN_Y20 -to SD_MOSI
+-set_location_assignment PIN_W20 -to SD_MISO
+-set_global_assignment -name VHDL_FILE saa5050.vhd
+-set_global_assignment -name VHDL_FILE i2s_intf.vhd
+-set_global_assignment -name VHDL_FILE i2c_loader.vhd
+-set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_comp_pack-p.vhd"
+-set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_noise.vhd"
+-set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_tone.vhd"
+-set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_top.vhd"
+-set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_attenuator.vhd"
+-set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_clock_div.vhd"
+-set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_latch_ctrl.vhd"
+-set_global_assignment -name VHDL_FILE ps2_intf.vhd
+-set_global_assignment -name VHDL_FILE m6522.vhd
+-set_global_assignment -name VHDL_FILE seg7.vhd
+-set_global_assignment -name VHDL_FILE vidproc.vhd
+-set_global_assignment -name VHDL_FILE mc6845.vhd
+-set_global_assignment -name VHDL_FILE T65/T65_Pack.vhd
+-set_global_assignment -name VHDL_FILE T65/T65.vhd
+-set_global_assignment -name VHDL_FILE T65/T65_ALU.vhd
+-set_global_assignment -name VHDL_FILE T65/T65_MCode.vhd
+-set_global_assignment -name QIP_FILE pll32.qip
+-set_global_assignment -name VHDL_FILE bbc_micro_de1.vhd
+-set_global_assignment -name VHDL_FILE bbc_micro_de1_tb.vhd
+-set_global_assignment -name VHDL_FILE m6522_tb.vhd
+-set_global_assignment -name VHDL_FILE keyboard.vhd
+-set_global_assignment -name VHDL_FILE debugger.vhd
+-set_global_assignment -name QIP_FILE saa5050_rom.qip
++# -------------------------------------------------------------------------- # ++# ++# Copyright (C) 1991-2009 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. ++# ++# -------------------------------------------------------------------------- # ++# ++# Quartus II ++# Version 9.1 Build 222 10/21/2009 SJ Web Edition ++# Date created = 20:48:44 July 12, 2011 ++# ++# -------------------------------------------------------------------------- # ++# ++# Notes: ++# ++# 1) The default values for assignments are stored in the file: ++# bbc_micro_de1_assignment_defaults.qdf ++# If this file doesn't exist, see file: ++# assignment_defaults.qdf ++# ++# 2) Altera recommends that you do not modify this file. This ++# file is updated automatically by the Quartus II software ++# and any changes you make may be lost or overwritten. ++# ++# -------------------------------------------------------------------------- # ++ ++ ++set_global_assignment -name FAMILY "Cyclone II" ++set_global_assignment -name DEVICE EP2C20F484C7 ++set_global_assignment -name TOP_LEVEL_ENTITY bbc_micro_de1 ++set_global_assignment -name ORIGINAL_QUARTUS_VERSION 9.1 ++set_global_assignment -name PROJECT_CREATION_TIME_DATE "20:48:44 JULY 12, 2011" ++set_global_assignment -name LAST_QUARTUS_VERSION 9.1 ++set_global_assignment -name USE_GENERATED_PHYSICAL_CONSTRAINTS OFF -section_id eda_blast_fpga ++set_global_assignment -name DEVICE_FILTER_PACKAGE FBGA ++set_global_assignment -name DEVICE_FILTER_PIN_COUNT 484 ++set_global_assignment -name DEVICE_FILTER_SPEED_GRADE 7 ++set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 ++set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 ++set_location_assignment PIN_A13 -to GPIO_0[0] ++set_location_assignment PIN_B13 -to GPIO_0[1] ++set_location_assignment PIN_A14 -to GPIO_0[2] ++set_location_assignment PIN_B14 -to GPIO_0[3] ++set_location_assignment PIN_A15 -to GPIO_0[4] ++set_location_assignment PIN_B15 -to GPIO_0[5] ++set_location_assignment PIN_A16 -to GPIO_0[6] ++set_location_assignment PIN_B16 -to GPIO_0[7] ++set_location_assignment PIN_A17 -to GPIO_0[8] ++set_location_assignment PIN_B17 -to GPIO_0[9] ++set_location_assignment PIN_A18 -to GPIO_0[10] ++set_location_assignment PIN_B18 -to GPIO_0[11] ++set_location_assignment PIN_A19 -to GPIO_0[12] ++set_location_assignment PIN_B19 -to GPIO_0[13] ++set_location_assignment PIN_A20 -to GPIO_0[14] ++set_location_assignment PIN_B20 -to GPIO_0[15] ++set_location_assignment PIN_C21 -to GPIO_0[16] ++set_location_assignment PIN_C22 -to GPIO_0[17] ++set_location_assignment PIN_D21 -to GPIO_0[18] ++set_location_assignment PIN_D22 -to GPIO_0[19] ++set_location_assignment PIN_E21 -to GPIO_0[20] ++set_location_assignment PIN_E22 -to GPIO_0[21] ++set_location_assignment PIN_F21 -to GPIO_0[22] ++set_location_assignment PIN_F22 -to GPIO_0[23] ++set_location_assignment PIN_G21 -to GPIO_0[24] ++set_location_assignment PIN_G22 -to GPIO_0[25] ++set_location_assignment PIN_J21 -to GPIO_0[26] ++set_location_assignment PIN_J22 -to GPIO_0[27] ++set_location_assignment PIN_K21 -to GPIO_0[28] ++set_location_assignment PIN_K22 -to GPIO_0[29] ++set_location_assignment PIN_J19 -to GPIO_0[30] ++set_location_assignment PIN_J20 -to GPIO_0[31] ++set_location_assignment PIN_J18 -to GPIO_0[32] ++set_location_assignment PIN_K20 -to GPIO_0[33] ++set_location_assignment PIN_L19 -to GPIO_0[34] ++set_location_assignment PIN_L18 -to GPIO_0[35] ++set_location_assignment PIN_H12 -to GPIO_1[0] ++set_location_assignment PIN_H13 -to GPIO_1[1] ++set_location_assignment PIN_H14 -to GPIO_1[2] ++set_location_assignment PIN_G15 -to GPIO_1[3] ++set_location_assignment PIN_E14 -to GPIO_1[4] ++set_location_assignment PIN_E15 -to GPIO_1[5] ++set_location_assignment PIN_F15 -to GPIO_1[6] ++set_location_assignment PIN_G16 -to GPIO_1[7] ++set_location_assignment PIN_F12 -to GPIO_1[8] ++set_location_assignment PIN_F13 -to GPIO_1[9] ++set_location_assignment PIN_C14 -to GPIO_1[10] ++set_location_assignment PIN_D14 -to GPIO_1[11] ++set_location_assignment PIN_D15 -to GPIO_1[12] ++set_location_assignment PIN_D16 -to GPIO_1[13] ++set_location_assignment PIN_C17 -to GPIO_1[14] ++set_location_assignment PIN_C18 -to GPIO_1[15] ++set_location_assignment PIN_C19 -to GPIO_1[16] ++set_location_assignment PIN_C20 -to GPIO_1[17] ++set_location_assignment PIN_D19 -to GPIO_1[18] ++set_location_assignment PIN_D20 -to GPIO_1[19] ++set_location_assignment PIN_E20 -to GPIO_1[20] ++set_location_assignment PIN_F20 -to GPIO_1[21] ++set_location_assignment PIN_E19 -to GPIO_1[22] ++set_location_assignment PIN_E18 -to GPIO_1[23] ++set_location_assignment PIN_G20 -to GPIO_1[24] ++set_location_assignment PIN_G18 -to GPIO_1[25] ++set_location_assignment PIN_G17 -to GPIO_1[26] ++set_location_assignment PIN_H17 -to GPIO_1[27] ++set_location_assignment PIN_J15 -to GPIO_1[28] ++set_location_assignment PIN_H18 -to GPIO_1[29] ++set_location_assignment PIN_N22 -to GPIO_1[30] ++set_location_assignment PIN_N21 -to GPIO_1[31] ++set_location_assignment PIN_P15 -to GPIO_1[32] ++set_location_assignment PIN_N15 -to GPIO_1[33] ++set_location_assignment PIN_P17 -to GPIO_1[34] ++set_location_assignment PIN_P18 -to GPIO_1[35] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[2] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[3] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[4] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[5] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[6] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[7] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[8] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[9] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[10] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[11] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[12] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[13] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[14] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[15] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[16] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[17] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[18] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[19] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[20] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[21] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[22] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[23] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[24] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[25] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[26] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[27] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[28] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[29] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[30] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[31] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[32] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[33] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[34] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_0[35] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[2] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[3] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[4] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[5] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[6] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[7] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[8] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[9] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[10] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[11] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[12] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[13] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[14] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[15] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[16] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[17] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[18] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[19] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[20] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[21] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[22] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[23] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[24] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[25] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[26] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[27] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[28] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[29] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[30] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[31] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[32] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[33] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[34] ++set_instance_assignment -name IO_STANDARD LVTTL -to GPIO_1[35] ++set_location_assignment PIN_L22 -to SW[0] ++set_location_assignment PIN_L21 -to SW[1] ++set_location_assignment PIN_M22 -to SW[2] ++set_location_assignment PIN_V12 -to SW[3] ++set_location_assignment PIN_W12 -to SW[4] ++set_location_assignment PIN_U12 -to SW[5] ++set_location_assignment PIN_U11 -to SW[6] ++set_location_assignment PIN_M2 -to SW[7] ++set_location_assignment PIN_M1 -to SW[8] ++set_location_assignment PIN_L2 -to SW[9] ++set_instance_assignment -name IO_STANDARD LVTTL -to SW[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to SW[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to SW[2] ++set_instance_assignment -name IO_STANDARD LVTTL -to SW[3] ++set_instance_assignment -name IO_STANDARD LVTTL -to SW[4] ++set_instance_assignment -name IO_STANDARD LVTTL -to SW[5] ++set_instance_assignment -name IO_STANDARD LVTTL -to SW[6] ++set_instance_assignment -name IO_STANDARD LVTTL -to SW[7] ++set_instance_assignment -name IO_STANDARD LVTTL -to SW[8] ++set_instance_assignment -name IO_STANDARD LVTTL -to SW[9] ++set_location_assignment PIN_J2 -to HEX0[0] ++set_location_assignment PIN_J1 -to HEX0[1] ++set_location_assignment PIN_H2 -to HEX0[2] ++set_location_assignment PIN_H1 -to HEX0[3] ++set_location_assignment PIN_F2 -to HEX0[4] ++set_location_assignment PIN_F1 -to HEX0[5] ++set_location_assignment PIN_E2 -to HEX0[6] ++set_location_assignment PIN_E1 -to HEX1[0] ++set_location_assignment PIN_H6 -to HEX1[1] ++set_location_assignment PIN_H5 -to HEX1[2] ++set_location_assignment PIN_H4 -to HEX1[3] ++set_location_assignment PIN_G3 -to HEX1[4] ++set_location_assignment PIN_D2 -to HEX1[5] ++set_location_assignment PIN_D1 -to HEX1[6] ++set_location_assignment PIN_G5 -to HEX2[0] ++set_location_assignment PIN_G6 -to HEX2[1] ++set_location_assignment PIN_C2 -to HEX2[2] ++set_location_assignment PIN_C1 -to HEX2[3] ++set_location_assignment PIN_E3 -to HEX2[4] ++set_location_assignment PIN_E4 -to HEX2[5] ++set_location_assignment PIN_D3 -to HEX2[6] ++set_location_assignment PIN_F4 -to HEX3[0] ++set_location_assignment PIN_D5 -to HEX3[1] ++set_location_assignment PIN_D6 -to HEX3[2] ++set_location_assignment PIN_J4 -to HEX3[3] ++set_location_assignment PIN_L8 -to HEX3[4] ++set_location_assignment PIN_F3 -to HEX3[5] ++set_location_assignment PIN_D4 -to HEX3[6] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[2] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[3] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[4] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[5] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX0[6] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[2] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[3] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[4] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[5] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX1[6] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[2] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[3] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[4] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[5] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX2[6] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[2] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[3] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[4] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[5] ++set_instance_assignment -name IO_STANDARD LVTTL -to HEX3[6] ++set_location_assignment PIN_R22 -to KEY[0] ++set_location_assignment PIN_R21 -to KEY[1] ++set_location_assignment PIN_T22 -to KEY[2] ++set_location_assignment PIN_T21 -to KEY[3] ++set_location_assignment PIN_R20 -to LEDR[0] ++set_location_assignment PIN_R19 -to LEDR[1] ++set_location_assignment PIN_U19 -to LEDR[2] ++set_location_assignment PIN_Y19 -to LEDR[3] ++set_location_assignment PIN_T18 -to LEDR[4] ++set_location_assignment PIN_V19 -to LEDR[5] ++set_location_assignment PIN_Y18 -to LEDR[6] ++set_location_assignment PIN_U18 -to LEDR[7] ++set_location_assignment PIN_R18 -to LEDR[8] ++set_location_assignment PIN_R17 -to LEDR[9] ++set_location_assignment PIN_U22 -to LEDG[0] ++set_location_assignment PIN_U21 -to LEDG[1] ++set_location_assignment PIN_V22 -to LEDG[2] ++set_location_assignment PIN_V21 -to LEDG[3] ++set_location_assignment PIN_W22 -to LEDG[4] ++set_location_assignment PIN_W21 -to LEDG[5] ++set_location_assignment PIN_Y22 -to LEDG[6] ++set_location_assignment PIN_Y21 -to LEDG[7] ++set_instance_assignment -name IO_STANDARD LVTTL -to KEY[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to KEY[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to KEY[2] ++set_instance_assignment -name IO_STANDARD LVTTL -to KEY[3] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[2] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[3] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[4] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[5] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[6] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[7] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[8] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDR[9] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[2] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[3] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[4] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[5] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[6] ++set_instance_assignment -name IO_STANDARD LVTTL -to LEDG[7] ++set_location_assignment PIN_D12 -to CLOCK_27[0] ++set_location_assignment PIN_E12 -to CLOCK_27[1] ++set_location_assignment PIN_B12 -to CLOCK_24[0] ++set_location_assignment PIN_A12 -to CLOCK_24[1] ++set_location_assignment PIN_L1 -to CLOCK_50 ++set_location_assignment PIN_M21 -to EXT_CLOCK ++set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_27[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_24[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_24[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to CLOCK_50 ++set_instance_assignment -name IO_STANDARD LVTTL -to EXT_CLOCK ++set_location_assignment PIN_H15 -to PS2_CLK ++set_location_assignment PIN_J14 -to PS2_DAT ++set_location_assignment PIN_F14 -to UART_RXD ++set_location_assignment PIN_G12 -to UART_TXD ++set_instance_assignment -name IO_STANDARD LVTTL -to PS2_CLK ++set_instance_assignment -name IO_STANDARD LVTTL -to PS2_DAT ++set_instance_assignment -name IO_STANDARD LVTTL -to UART_RXD ++set_instance_assignment -name IO_STANDARD LVTTL -to UART_TXD ++set_location_assignment PIN_E8 -to TDI ++set_location_assignment PIN_D8 -to TCS ++set_location_assignment PIN_C7 -to TCK ++set_location_assignment PIN_D7 -to TDO ++set_instance_assignment -name IO_STANDARD LVTTL -to TDI ++set_instance_assignment -name IO_STANDARD LVTTL -to TCS ++set_instance_assignment -name IO_STANDARD LVTTL -to TCK ++set_instance_assignment -name IO_STANDARD LVTTL -to TDO ++set_location_assignment PIN_D9 -to VGA_R[0] ++set_location_assignment PIN_C9 -to VGA_R[1] ++set_location_assignment PIN_A7 -to VGA_R[2] ++set_location_assignment PIN_B7 -to VGA_R[3] ++set_location_assignment PIN_B8 -to VGA_G[0] ++set_location_assignment PIN_C10 -to VGA_G[1] ++set_location_assignment PIN_B9 -to VGA_G[2] ++set_location_assignment PIN_A8 -to VGA_G[3] ++set_location_assignment PIN_A9 -to VGA_B[0] ++set_location_assignment PIN_D11 -to VGA_B[1] ++set_location_assignment PIN_A10 -to VGA_B[2] ++set_location_assignment PIN_B10 -to VGA_B[3] ++set_location_assignment PIN_A11 -to VGA_HS ++set_location_assignment PIN_B11 -to VGA_VS ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[2] ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_R[3] ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[2] ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_G[3] ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[0] ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[1] ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[2] ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_B[3] ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_HS ++set_instance_assignment -name IO_STANDARD LVTTL -to VGA_VS ++set_location_assignment PIN_A3 -to I2C_SCLK ++set_location_assignment PIN_B3 -to I2C_SDAT ++set_location_assignment PIN_A6 -to AUD_ADCLRCK ++set_location_assignment PIN_B6 -to AUD_ADCDAT ++set_location_assignment PIN_A5 -to AUD_DACLRCK ++set_location_assignment PIN_B5 -to AUD_DACDAT ++set_location_assignment PIN_B4 -to AUD_XCK ++set_location_assignment PIN_A4 -to AUD_BCLK ++set_instance_assignment -name IO_STANDARD LVTTL -to I2C_SCLK ++set_instance_assignment -name IO_STANDARD LVTTL -to I2C_SDAT ++set_instance_assignment -name IO_STANDARD LVTTL -to AUD_ADCLRCK ++set_instance_assignment -name IO_STANDARD LVTTL -to AUD_ADCDAT ++set_instance_assignment -name IO_STANDARD LVTTL -to AUD_DACLRCK ++set_instance_assignment -name IO_STANDARD LVTTL -to AUD_DACDAT ++set_instance_assignment -name IO_STANDARD LVTTL -to AUD_XCK ++set_instance_assignment -name IO_STANDARD LVTTL -to AUD_BCLK ++set_location_assignment PIN_W4 -to DRAM_ADDR[0] ++set_location_assignment PIN_W5 -to DRAM_ADDR[1] ++set_location_assignment PIN_Y3 -to DRAM_ADDR[2] ++set_location_assignment PIN_Y4 -to DRAM_ADDR[3] ++set_location_assignment PIN_R6 -to DRAM_ADDR[4] ++set_location_assignment PIN_R5 -to DRAM_ADDR[5] ++set_location_assignment PIN_P6 -to DRAM_ADDR[6] ++set_location_assignment PIN_P5 -to DRAM_ADDR[7] ++set_location_assignment PIN_P3 -to DRAM_ADDR[8] ++set_location_assignment PIN_N4 -to DRAM_ADDR[9] ++set_location_assignment PIN_W3 -to DRAM_ADDR[10] ++set_location_assignment PIN_N6 -to DRAM_ADDR[11] ++set_location_assignment PIN_U3 -to DRAM_BA_0 ++set_location_assignment PIN_V4 -to DRAM_BA_1 ++set_location_assignment PIN_T3 -to DRAM_CAS_N ++set_location_assignment PIN_N3 -to DRAM_CKE ++set_location_assignment PIN_U4 -to DRAM_CLK ++set_location_assignment PIN_T6 -to DRAM_CS_N ++set_location_assignment PIN_U1 -to DRAM_DQ[0] ++set_location_assignment PIN_U2 -to DRAM_DQ[1] ++set_location_assignment PIN_V1 -to DRAM_DQ[2] ++set_location_assignment PIN_V2 -to DRAM_DQ[3] ++set_location_assignment PIN_W1 -to DRAM_DQ[4] ++set_location_assignment PIN_W2 -to DRAM_DQ[5] ++set_location_assignment PIN_Y1 -to DRAM_DQ[6] ++set_location_assignment PIN_Y2 -to DRAM_DQ[7] ++set_location_assignment PIN_N1 -to DRAM_DQ[8] ++set_location_assignment PIN_N2 -to DRAM_DQ[9] ++set_location_assignment PIN_P1 -to DRAM_DQ[10] ++set_location_assignment PIN_P2 -to DRAM_DQ[11] ++set_location_assignment PIN_R1 -to DRAM_DQ[12] ++set_location_assignment PIN_R2 -to DRAM_DQ[13] ++set_location_assignment PIN_T1 -to DRAM_DQ[14] ++set_location_assignment PIN_T2 -to DRAM_DQ[15] ++set_location_assignment PIN_R7 -to DRAM_LDQM ++set_location_assignment PIN_T5 -to DRAM_RAS_N ++set_location_assignment PIN_M5 -to DRAM_UDQM ++set_location_assignment PIN_R8 -to DRAM_WE_N ++set_location_assignment PIN_AB20 -to FL_ADDR[0] ++set_location_assignment PIN_AA14 -to FL_ADDR[1] ++set_location_assignment PIN_Y16 -to FL_ADDR[2] ++set_location_assignment PIN_R15 -to FL_ADDR[3] ++set_location_assignment PIN_T15 -to FL_ADDR[4] ++set_location_assignment PIN_U15 -to FL_ADDR[5] ++set_location_assignment PIN_V15 -to FL_ADDR[6] ++set_location_assignment PIN_W15 -to FL_ADDR[7] ++set_location_assignment PIN_R14 -to FL_ADDR[8] ++set_location_assignment PIN_Y13 -to FL_ADDR[9] ++set_location_assignment PIN_R12 -to FL_ADDR[10] ++set_location_assignment PIN_T12 -to FL_ADDR[11] ++set_location_assignment PIN_AB14 -to FL_ADDR[12] ++set_location_assignment PIN_AA13 -to FL_ADDR[13] ++set_location_assignment PIN_AB13 -to FL_ADDR[14] ++set_location_assignment PIN_AA12 -to FL_ADDR[15] ++set_location_assignment PIN_AB12 -to FL_ADDR[16] ++set_location_assignment PIN_AA20 -to FL_ADDR[17] ++set_location_assignment PIN_U14 -to FL_ADDR[18] ++set_location_assignment PIN_V14 -to FL_ADDR[19] ++set_location_assignment PIN_U13 -to FL_ADDR[20] ++set_location_assignment PIN_R13 -to FL_ADDR[21] ++set_location_assignment PIN_AB16 -to FL_DQ[0] ++set_location_assignment PIN_AA16 -to FL_DQ[1] ++set_location_assignment PIN_AB17 -to FL_DQ[2] ++set_location_assignment PIN_AA17 -to FL_DQ[3] ++set_location_assignment PIN_AB18 -to FL_DQ[4] ++set_location_assignment PIN_AA18 -to FL_DQ[5] ++set_location_assignment PIN_AB19 -to FL_DQ[6] ++set_location_assignment PIN_AA19 -to FL_DQ[7] ++set_location_assignment PIN_AA15 -to FL_OE_N ++set_location_assignment PIN_W14 -to FL_RST_N ++set_location_assignment PIN_Y14 -to FL_WE_N ++set_location_assignment PIN_AA3 -to SRAM_ADDR[0] ++set_location_assignment PIN_AB3 -to SRAM_ADDR[1] ++set_location_assignment PIN_AA4 -to SRAM_ADDR[2] ++set_location_assignment PIN_AB4 -to SRAM_ADDR[3] ++set_location_assignment PIN_AA5 -to SRAM_ADDR[4] ++set_location_assignment PIN_AB10 -to SRAM_ADDR[5] ++set_location_assignment PIN_AA11 -to SRAM_ADDR[6] ++set_location_assignment PIN_AB11 -to SRAM_ADDR[7] ++set_location_assignment PIN_V11 -to SRAM_ADDR[8] ++set_location_assignment PIN_W11 -to SRAM_ADDR[9] ++set_location_assignment PIN_R11 -to SRAM_ADDR[10] ++set_location_assignment PIN_T11 -to SRAM_ADDR[11] ++set_location_assignment PIN_Y10 -to SRAM_ADDR[12] ++set_location_assignment PIN_U10 -to SRAM_ADDR[13] ++set_location_assignment PIN_R10 -to SRAM_ADDR[14] ++set_location_assignment PIN_T7 -to SRAM_ADDR[15] ++set_location_assignment PIN_Y6 -to SRAM_ADDR[16] ++set_location_assignment PIN_Y5 -to SRAM_ADDR[17] ++set_location_assignment PIN_AB5 -to SRAM_CE_N ++set_location_assignment PIN_AA6 -to SRAM_DQ[0] ++set_location_assignment PIN_AB6 -to SRAM_DQ[1] ++set_location_assignment PIN_AA7 -to SRAM_DQ[2] ++set_location_assignment PIN_AB7 -to SRAM_DQ[3] ++set_location_assignment PIN_AA8 -to SRAM_DQ[4] ++set_location_assignment PIN_AB8 -to SRAM_DQ[5] ++set_location_assignment PIN_AA9 -to SRAM_DQ[6] ++set_location_assignment PIN_AB9 -to SRAM_DQ[7] ++set_location_assignment PIN_Y9 -to SRAM_DQ[8] ++set_location_assignment PIN_W9 -to SRAM_DQ[9] ++set_location_assignment PIN_V9 -to SRAM_DQ[10] ++set_location_assignment PIN_U9 -to SRAM_DQ[11] ++set_location_assignment PIN_R9 -to SRAM_DQ[12] ++set_location_assignment PIN_W8 -to SRAM_DQ[13] ++set_location_assignment PIN_V8 -to SRAM_DQ[14] ++set_location_assignment PIN_U8 -to SRAM_DQ[15] ++set_location_assignment PIN_Y7 -to SRAM_LB_N ++set_location_assignment PIN_T8 -to SRAM_OE_N ++set_location_assignment PIN_W7 -to SRAM_UB_N ++set_location_assignment PIN_AA10 -to SRAM_WE_N ++set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED WITH WEAK PULL-UP" ++set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top ++set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top ++set_global_assignment -name LL_ROOT_REGION ON -section_id "Root Region" ++set_global_assignment -name LL_MEMBER_STATE LOCKED -section_id "Root Region" ++set_global_assignment -name MISC_FILE "U:/git_repos/fpga/bbc/bbc_micro_de1.dpf" ++set_location_assignment PIN_AB15 -to FL_CE_N ++set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" ++set_global_assignment -name STRATIX_CONFIGURATION_DEVICE EPCS4 ++set_global_assignment -name RESERVE_ASDO_AFTER_CONFIGURATION "AS INPUT TRI-STATED" ++set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" ++set_location_assignment PIN_U20 -to SD_nCS ++set_location_assignment PIN_V20 -to SD_SCLK ++set_location_assignment PIN_Y20 -to SD_MOSI ++set_location_assignment PIN_W20 -to SD_MISO ++set_global_assignment -name VHDL_FILE saa5050.vhd ++set_global_assignment -name VHDL_FILE i2s_intf.vhd ++set_global_assignment -name VHDL_FILE i2c_loader.vhd ++set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_comp_pack-p.vhd" ++set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_noise.vhd" ++set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_tone.vhd" ++set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_top.vhd" ++set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_attenuator.vhd" ++set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_clock_div.vhd" ++set_global_assignment -name VHDL_FILE "sn76489-1.0/sn76489_latch_ctrl.vhd" ++set_global_assignment -name VHDL_FILE ps2_intf.vhd ++set_global_assignment -name VHDL_FILE m6522.vhd ++set_global_assignment -name VHDL_FILE seg7.vhd ++set_global_assignment -name VHDL_FILE vidproc.vhd ++set_global_assignment -name VHDL_FILE mc6845.vhd ++set_global_assignment -name VHDL_FILE T65/T65_Pack.vhd ++set_global_assignment -name VHDL_FILE T65/T65.vhd ++set_global_assignment -name VHDL_FILE T65/T65_ALU.vhd ++set_global_assignment -name VHDL_FILE T65/T65_MCode.vhd ++set_global_assignment -name QIP_FILE pll32.qip ++set_global_assignment -name VHDL_FILE bbc_micro_de1.vhd ++set_global_assignment -name VHDL_FILE bbc_micro_de1_tb.vhd ++set_global_assignment -name VHDL_FILE m6522_tb.vhd ++set_global_assignment -name VHDL_FILE keyboard.vhd ++set_global_assignment -name VHDL_FILE debugger.vhd ++set_global_assignment -name QIP_FILE saa5050_rom.qip + set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top +\ No newline at end of file +diff --git a/bbc_micro_de1.vhd b/bbc_micro_de1.vhd +index e109c36..0fca9de 100644 +--- a/bbc_micro_de1.vhd ++++ b/bbc_micro_de1.vhd +@@ -1,1265 +1,1265 @@ +--- BBC Micro for Altera DE1
+---
+--- Copyright (c) 2011 Mike Stirling
+---
+--- 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 agreement from the author.
+---
+--- * License is granted for non-commercial use only. A fee may not be charged
+--- for redistributions as source code or in synthesized/hardware form without
+--- specific prior written agreement from the author.
+---
+--- 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.
+---
+--- BBC B Micro
+---
+--- Terasic DE1 top-level
+---
+--- (C) 2011 Mike Stirling
+-
+-library IEEE;
+-use IEEE.STD_LOGIC_1164.ALL;
+-use IEEE.NUMERIC_STD.ALL;
+-
+--- Generic top-level entity for Altera DE1 board
+-entity bbc_micro_de1 is
+-generic (
+- -- ROM offset
+- -- The 4MB Flash is used in 16KB banks as a simple mechanism for
+- -- different machines to address different parts of the ROM, saving
+- -- on re-flashing each time a new machine is run on the board.
+- -- This generic sets the upper 8 address bits.
+- -- Note that the lower bits may be ignored by the implementation,
+- -- e.g. where ROMs are bigger than 16K or where multiple banks
+- -- are required. In this case it is important to ensure that the
+- -- ROM images are aligned correctly (such that these ignored bits are 0).
+- --
+- -- For the BBC the ROMs start in bank 8 (the first 8 banks are used by
+- -- the Spectrum project). The particular bank is selected by the sideways
+- -- ROM paging register, and bank 7 is used for the MOS. Recommended layout
+- -- is:
+- --
+- -- 0 Sideways
+- -- 1 Sideways
+- -- 2 Sideways - SuperMMC (DFS)
+- -- 3 Sideways - BASIC
+- -- 4 Not used
+- -- 5 Not used
+- -- 6 Not used
+- -- 7 MOS
+- ROM_OFFSET : std_logic_vector(7 downto 0) := "00001000"
+- );
+-port (
+- -- Clocks
+- CLOCK_24 : in std_logic_vector(1 downto 0);
+- CLOCK_27 : in std_logic_vector(1 downto 0);
+- CLOCK_50 : in std_logic;
+- EXT_CLOCK : in std_logic;
+-
+- -- Switches
+- SW : in std_logic_vector(9 downto 0);
+- -- Buttons
+- KEY : in std_logic_vector(3 downto 0);
+-
+- -- 7 segment displays
+- HEX0 : out std_logic_vector(6 downto 0);
+- HEX1 : out std_logic_vector(6 downto 0);
+- HEX2 : out std_logic_vector(6 downto 0);
+- HEX3 : out std_logic_vector(6 downto 0);
+- -- Red LEDs
+- LEDR : out std_logic_vector(9 downto 0);
+- -- Green LEDs
+- LEDG : out std_logic_vector(7 downto 0);
+-
+- -- VGA
+- VGA_R : out std_logic_vector(3 downto 0);
+- VGA_G : out std_logic_vector(3 downto 0);
+- VGA_B : out std_logic_vector(3 downto 0);
+- VGA_HS : out std_logic;
+- VGA_VS : out std_logic;
+-
+- -- Serial
+- UART_RXD : in std_logic;
+- UART_TXD : out std_logic;
+-
+- -- PS/2 Keyboard
+- PS2_CLK : inout std_logic;
+- PS2_DAT : inout std_logic;
+-
+- -- I2C
+- I2C_SCLK : inout std_logic;
+- I2C_SDAT : inout std_logic;
+-
+- -- Audio
+- AUD_XCK : out std_logic;
+- AUD_BCLK : out std_logic;
+- AUD_ADCLRCK : out std_logic;
+- AUD_ADCDAT : in std_logic;
+- AUD_DACLRCK : out std_logic;
+- AUD_DACDAT : out std_logic;
+-
+- -- SRAM
+- SRAM_ADDR : out std_logic_vector(17 downto 0);
+- SRAM_DQ : inout std_logic_vector(15 downto 0);
+- SRAM_CE_N : out std_logic;
+- SRAM_OE_N : out std_logic;
+- SRAM_WE_N : out std_logic;
+- SRAM_UB_N : out std_logic;
+- SRAM_LB_N : out std_logic;
+-
+- -- SDRAM
+- DRAM_ADDR : out std_logic_vector(11 downto 0);
+- DRAM_DQ : inout std_logic_vector(15 downto 0);
+- DRAM_BA_0 : in std_logic;
+- DRAM_BA_1 : in std_logic;
+- DRAM_CAS_N : in std_logic;
+- DRAM_CKE : in std_logic;
+- DRAM_CLK : in std_logic;
+- DRAM_CS_N : in std_logic;
+- DRAM_LDQM : in std_logic;
+- DRAM_RAS_N : in std_logic;
+- DRAM_UDQM : in std_logic;
+- DRAM_WE_N : in std_logic;
+-
+- -- Flash
+- FL_ADDR : out std_logic_vector(21 downto 0);
+- FL_DQ : inout std_logic_vector(7 downto 0);
+- FL_RST_N : out std_logic;
+- FL_OE_N : out std_logic;
+- FL_WE_N : out std_logic;
+- FL_CE_N : out std_logic;
+-
+- -- SD card (SPI mode)
+- SD_nCS : out std_logic;
+- SD_MOSI : out std_logic;
+- SD_SCLK : out std_logic;
+- SD_MISO : in std_logic;
+-
+- -- GPIO
+- GPIO_0 : inout std_logic_vector(35 downto 0);
+- GPIO_1 : inout std_logic_vector(35 downto 0)
+- );
+-end entity;
+-
+-architecture rtl of bbc_micro_de1 is
+-
+-------------------------------
+--- PLL (32 MHz master clock)
+-------------------------------
+-
+-component pll32 IS
+- PORT
+- (
+- areset : IN STD_LOGIC := '0';
+- inclk0 : IN STD_LOGIC := '0';
+- c0 : OUT STD_LOGIC ;
+- locked : OUT STD_LOGIC
+- );
+-end component;
+-
+----------
+--- CPU
+----------
+-
+-component 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)
+- );
+-end component;
+-
+------------------
+--- MC6845 CRTC
+------------------
+-
+-component mc6845 is
+-port (
+- CLOCK : in std_logic;
+- CLKEN : in std_logic;
+- nRESET : in std_logic;
+-
+- -- Bus interface
+- ENABLE : in std_logic;
+- R_nW : in std_logic;
+- RS : in std_logic;
+- DI : in std_logic_vector(7 downto 0);
+- DO : out std_logic_vector(7 downto 0);
+-
+- -- Display interface
+- VSYNC : out std_logic;
+- HSYNC : out std_logic;
+- DE : out std_logic;
+- CURSOR : out std_logic;
+- LPSTB : in std_logic;
+-
+- -- Memory interface
+- MA : out std_logic_vector(13 downto 0);
+- RA : out std_logic_vector(4 downto 0)
+- );
+-end component;
+-
+--------------------------
+--- "VIDPROC" Video ULA
+--------------------------
+-
+-component vidproc is
+-port (
+- CLOCK : in std_logic;
+- -- Clock enable qualifies display cycles (interleaved with CPU cycles)
+- CLKEN : in std_logic;
+- nRESET : in std_logic;
+-
+- -- Clock enable output to CRTC
+- CLKEN_CRTC : out std_logic;
+-
+- -- Bus interface
+- ENABLE : in std_logic;
+- A0 : in std_logic;
+- -- CPU data bus (for register writes)
+- DI_CPU : in std_logic_vector(7 downto 0);
+- -- Display RAM data bus (for display data fetch)
+- DI_RAM : in std_logic_vector(7 downto 0);
+-
+- -- Control interface
+- nINVERT : in std_logic;
+- DISEN : in std_logic;
+- CURSOR : in std_logic;
+-
+- -- Video in (teletext mode)
+- R_IN : in std_logic;
+- G_IN : in std_logic;
+- B_IN : in std_logic;
+-
+- -- Video out
+- R : out std_logic;
+- G : out std_logic;
+- B : out std_logic
+- );
+-end component;
+-
+---------------------------------
+--- SAA5050 Teletext Generator
+---------------------------------
+-
+-component saa5050 is
+-port (
+- CLOCK : in std_logic;
+- -- 6 MHz dot clock enable
+- CLKEN : in std_logic;
+- -- Async reset
+- nRESET : in std_logic;
+-
+- -- Character data input (in the bus clock domain)
+- DI_CLOCK : in std_logic;
+- DI_CLKEN : in std_logic;
+- DI : in std_logic_vector(6 downto 0);
+-
+- -- Timing inputs
+- -- General line reset (not used)
+- GLR : in std_logic; -- /HSYNC
+- -- Data entry window - high during VSYNC.
+- -- Resets ROM row counter and drives 'flash' signal
+- DEW : in std_logic; -- VSYNC
+- -- Character rounding select - high during even field
+- CRS : in std_logic; -- FIELD
+- -- Load output shift register enable - high during active video
+- LOSE : in std_logic; -- DE
+-
+- -- Video out
+- R : out std_logic;
+- G : out std_logic;
+- B : out std_logic;
+- Y : out std_logic
+- );
+-end component;
+-
+---------------
+--- 6522 VIA
+---------------
+-
+-component 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);
+-
+- -- FIXME: Revisit timing in this component. Does it really need a 4x clock?
+- I_P2_H : in std_logic; -- high for phase 2 clock ____----__
+- RESET_L : in std_logic;
+- ENA_4 : in std_logic; -- clk enable (4x system clock rate)
+- CLK : in std_logic
+- );
+-end component;
+-
+------------------------------
+--- PS/2 Keyboard Emulation
+------------------------------
+-
+-component keyboard is
+-port (
+- CLOCK : in std_logic;
+- nRESET : in std_logic;
+- CLKEN_1MHZ : in std_logic;
+-
+- -- PS/2 interface
+- PS2_CLK : in std_logic;
+- PS2_DATA : in std_logic;
+-
+- -- If 1 then column is incremented automatically at
+- -- 1 MHz rate
+- AUTOSCAN : in std_logic;
+-
+- COLUMN : in std_logic_vector(3 downto 0);
+- ROW : in std_logic_vector(2 downto 0);
+-
+- -- 1 when currently selected key is down (AUTOSCAN disabled)
+- KEYPRESS : out std_logic;
+- -- 1 when any key is down (except row 0)
+- INT : out std_logic;
+- -- BREAK key output - 1 when pressed
+- BREAK_OUT : out std_logic;
+-
+- -- DIP switch inputs
+- DIP_SWITCH : in std_logic_vector(7 downto 0)
+- );
+-end component;
+-
+------------------------------
+--- SN76489 sound generator
+------------------------------
+-
+-component sn76489_top is
+-
+- generic (
+- clock_div_16_g : integer := 1
+- );
+- port (
+- clock_i : in std_logic;
+- clock_en_i : in std_logic;
+- res_n_i : in std_logic;
+- ce_n_i : in std_logic;
+- we_n_i : in std_logic;
+- ready_o : out std_logic;
+- d_i : in std_logic_vector(0 to 7);
+- aout_o : out signed(0 to 7)
+- );
+-
+-end component;
+-
+-component i2s_intf is
+-generic(
+- mclk_rate : positive := 12000000;
+- sample_rate : positive := 8000;
+- preamble : positive := 1; -- I2S
+- word_length : positive := 16
+- );
+-
+-port (
+- -- 2x MCLK in (e.g. 24 MHz for WM8731 USB mode)
+- CLK : in std_logic;
+- nRESET : in std_logic;
+-
+- -- Parallel IO
+- PCM_INL : out std_logic_vector(word_length - 1 downto 0);
+- PCM_INR : out std_logic_vector(word_length - 1 downto 0);
+- PCM_OUTL : in std_logic_vector(word_length - 1 downto 0);
+- PCM_OUTR : in std_logic_vector(word_length - 1 downto 0);
+-
+- -- Codec interface (right justified mode)
+- -- MCLK is generated at half of the CLK input
+- I2S_MCLK : out std_logic;
+- -- LRCLK is equal to the sample rate and is synchronous to
+- -- MCLK. It must be related to MCLK by the oversampling ratio
+- -- given in the codec datasheet.
+- I2S_LRCLK : out std_logic;
+-
+- -- Data is shifted out on the falling edge of BCLK, sampled
+- -- on the rising edge. The bit rate is determined such that
+- -- it is fast enough to fit preamble + word_length bits into
+- -- each LRCLK half cycle. The last cycle of each word may be
+- -- stretched to fit to LRCLK. This is OK at least for the
+- -- WM8731 codec.
+- -- The first falling edge of each timeslot is always synchronised
+- -- with the LRCLK edge.
+- I2S_BCLK : out std_logic;
+- -- Output bitstream
+- I2S_DOUT : out std_logic;
+- -- Input bitstream
+- I2S_DIN : in std_logic
+- );
+-end component;
+-
+-component i2c_loader is
+-generic (
+- -- Address of slave to be loaded
+- device_address : integer := 16#1a#;
+- -- Number of retries to allow before stopping
+- num_retries : integer := 0;
+- -- Length of clock divider in bits. Resulting bus frequency is
+- -- CLK/2^(log2_divider + 2)
+- log2_divider : integer := 6
+-);
+-
+-port (
+- CLK : in std_logic;
+- nRESET : in std_logic;
+-
+- I2C_SCL : inout std_logic;
+- I2C_SDA : inout std_logic;
+-
+- IS_DONE : out std_logic;
+- IS_ERROR : out std_logic
+- );
+-end component;
+-
+-component debugger is
+-generic (
+- -- Set this for a reasonable half flash duration relative to the
+- -- clock frequency
+- flash_divider : natural := 24
+- );
+-port (
+- CLOCK : in std_logic;
+- nRESET : in std_logic;
+- -- CPU clock enable in
+- CLKEN_IN : in std_logic;
+- -- Gated clock enable back out to CPU
+- CLKEN_OUT : out std_logic;
+- -- CPU IRQ in
+- nIRQ_IN : in std_logic;
+- -- Gated IRQ back out to CPU (no interrupts when single stepping)
+- nIRQ_OUT : out std_logic;
+-
+- -- CPU
+- A_CPU : in std_logic_vector(15 downto 0);
+- R_nW : in std_logic;
+- SYNC : in std_logic;
+-
+- -- Aux bus input for display in hex
+- AUX_BUS : in std_logic_vector(15 downto 0);
+-
+- -- Controls
+- -- RUN or HALT CPU
+- RUN : in std_logic;
+- -- Push button to single-step in HALT mode
+- nSTEP : in std_logic;
+- -- Push button to cycle display mode
+- nMODE : in std_logic;
+- -- Push button to cycle display digit in edit mode
+- nDIGIT : in std_logic;
+- -- Push button to cycle digit value in edit mode
+- nSET : in std_logic;
+-
+- -- Output to display
+- DIGIT3 : out std_logic_vector(6 downto 0);
+- DIGIT2 : out std_logic_vector(6 downto 0);
+- DIGIT1 : out std_logic_vector(6 downto 0);
+- DIGIT0 : out std_logic_vector(6 downto 0);
+-
+- LED_BREAKPOINT : out std_logic;
+- LED_WATCHPOINT : out std_logic
+- );
+-end component;
+-
+--------------
+--- Signals
+--------------
+-
+--- Master clock - 32 MHz
+-signal pll_reset : std_logic;
+-signal pll_locked : std_logic;
+-signal clock : std_logic;
+-signal hard_reset_n : std_logic;
+-signal reset_n : std_logic;
+-
+--- Clock enable counter
+--- CPU and video cycles are interleaved. The CPU runs at 2 MHz (every 16th
+--- cycle) and the video subsystem is enabled on every odd cycle.
+-signal clken_counter : unsigned(4 downto 0);
+-signal cpu_cycle : std_logic; -- Qualifies all 2 MHz cycles
+-signal cpu_cycle_mask : std_logic; -- Set to mask CPU cycles until 1 MHz cycle is complete
+-signal cpu_clken : std_logic; -- 2 MHz cycles in which the CPU is enabled
+-signal cpu_debug_clken : std_logic; -- CPU clken return from hardware debugger
+--- IO cycles are out of phase with the CPU
+-signal vid_clken : std_logic; -- 16 MHz video cycles
+-signal mhz4_clken : std_logic; -- Used by 6522
+-signal mhz2_clken : std_logic; -- Used for latching CPU address for clock stretch
+-signal mhz1_clken : std_logic; -- 1 MHz bus and associated peripherals, 6522 phase 2
+--- SAA5050 needs a 6 MHz clock enable relative to a 24 MHz clock
+-signal ttxt_clken_counter : unsigned(1 downto 0);
+-signal ttxt_clken : std_logic;
+-
+--- Debugger connections
+-signal debug_irq_in_n : std_logic;
+-signal debug_aux : std_logic_vector(15 downto 0);
+-
+--- CPU signals
+-signal cpu_mode : std_logic_vector(1 downto 0);
+-signal cpu_ready : std_logic;
+-signal cpu_abort_n : std_logic;
+-signal cpu_irq_n : std_logic;
+-signal cpu_nmi_n : std_logic;
+-signal cpu_so_n : std_logic;
+-signal cpu_r_nw : std_logic;
+-signal cpu_sync : std_logic;
+-signal cpu_ef : std_logic;
+-signal cpu_mf : std_logic;
+-signal cpu_xf : std_logic;
+-signal cpu_ml_n : std_logic;
+-signal cpu_vp_n : std_logic;
+-signal cpu_vda : std_logic;
+-signal cpu_vpa : std_logic;
+-signal cpu_a : std_logic_vector(23 downto 0);
+-signal cpu_di : std_logic_vector(7 downto 0);
+-signal cpu_do : std_logic_vector(7 downto 0);
+-
+--- CRTC signals
+-signal crtc_clken : std_logic;
+-signal crtc_do : std_logic_vector(7 downto 0);
+-signal crtc_vsync : std_logic;
+-signal crtc_hsync : std_logic;
+-signal crtc_de : std_logic;
+-signal crtc_cursor : std_logic;
+-signal crtc_lpstb : std_logic := '0';
+-signal crtc_ma : std_logic_vector(13 downto 0);
+-signal crtc_ra : std_logic_vector(4 downto 0);
+-
+--- Decoded display address after address translation for hardware
+--- scrolling
+-signal display_a : std_logic_vector(14 downto 0);
+-
+--- "VIDPROC" signals
+-signal vidproc_invert_n : std_logic;
+-signal vidproc_disen : std_logic;
+-signal r_in : std_logic;
+-signal g_in : std_logic;
+-signal b_in : std_logic;
+-signal r_out : std_logic;
+-signal g_out : std_logic;
+-signal b_out : std_logic;
+-
+--- SAA5050 signals
+-signal ttxt_glr : std_logic;
+-signal ttxt_dew : std_logic;
+-signal ttxt_crs : std_logic;
+-signal ttxt_lose : std_logic;
+-signal ttxt_r : std_logic;
+-signal ttxt_g : std_logic;
+-signal ttxt_b : std_logic;
+-signal ttxt_y : std_logic;
+-
+--- System VIA signals
+-signal sys_via_do : std_logic_vector(7 downto 0);
+-signal sys_via_do_oe_n : std_logic;
+-signal sys_via_irq_n : std_logic;
+-signal sys_via_ca1_in : std_logic := '0';
+-signal sys_via_ca2_in : std_logic := '0';
+-signal sys_via_ca2_out : std_logic;
+-signal sys_via_ca2_oe_n : std_logic;
+-signal sys_via_pa_in : std_logic_vector(7 downto 0);
+-signal sys_via_pa_out : std_logic_vector(7 downto 0);
+-signal sys_via_pa_oe_n : std_logic_vector(7 downto 0);
+-signal sys_via_cb1_in : std_logic := '0';
+-signal sys_via_cb1_out : std_logic;
+-signal sys_via_cb1_oe_n : std_logic;
+-signal sys_via_cb2_in : std_logic := '0';
+-signal sys_via_cb2_out : std_logic;
+-signal sys_via_cb2_oe_n : std_logic;
+-signal sys_via_pb_in : std_logic_vector(7 downto 0);
+-signal sys_via_pb_out : std_logic_vector(7 downto 0);
+-signal sys_via_pb_oe_n : std_logic_vector(7 downto 0);
+-
+--- User VIA signals
+-signal user_via_do : std_logic_vector(7 downto 0);
+-signal user_via_do_oe_n : std_logic;
+-signal user_via_irq_n : std_logic;
+-signal user_via_ca1_in : std_logic := '0';
+-signal user_via_ca2_in : std_logic := '0';
+-signal user_via_ca2_out : std_logic;
+-signal user_via_ca2_oe_n : std_logic;
+-signal user_via_pa_in : std_logic_vector(7 downto 0);
+-signal user_via_pa_out : std_logic_vector(7 downto 0);
+-signal user_via_pa_oe_n : std_logic_vector(7 downto 0);
+-signal user_via_cb1_in : std_logic := '0';
+-signal user_via_cb1_out : std_logic;
+-signal user_via_cb1_oe_n : std_logic;
+-signal user_via_cb2_in : std_logic := '0';
+-signal user_via_cb2_out : std_logic;
+-signal user_via_cb2_oe_n : std_logic;
+-signal user_via_pb_in : std_logic_vector(7 downto 0);
+-signal user_via_pb_out : std_logic_vector(7 downto 0);
+-signal user_via_pb_oe_n : std_logic_vector(7 downto 0);
+-
+--- IC32 latch on System VIA
+-signal ic32 : std_logic_vector(7 downto 0);
+-signal sound_enable_n : std_logic;
+-signal speech_read_n : std_logic;
+-signal speech_write_n : std_logic;
+-signal keyb_enable_n : std_logic;
+-signal disp_addr_offs : std_logic_vector(1 downto 0);
+-signal caps_lock_led_n : std_logic;
+-signal shift_lock_led_n : std_logic;
+-
+--- Keyboard
+-signal keyb_column : std_logic_vector(3 downto 0);
+-signal keyb_row : std_logic_vector(2 downto 0);
+-signal keyb_out : std_logic;
+-signal keyb_int : std_logic;
+-signal keyb_break : std_logic;
+-
+--- Sound generator
+-signal sound_ready : std_logic;
+-signal sound_di : std_logic_vector(7 downto 0);
+-signal sound_ao : signed(7 downto 0);
+-signal pcm_inl : std_logic_vector(15 downto 0);
+-signal pcm_inr : std_logic_vector(15 downto 0);
+-
+--- Memory enables
+-signal ram_enable : std_logic; -- 0x0000
+-signal rom_enable : std_logic; -- 0x8000 (BASIC/sideways ROMs)
+-signal mos_enable : std_logic; -- 0xC000
+--- IO region enables
+-signal io_fred : std_logic; -- 0xFC00 (1 MHz bus)
+-signal io_jim : std_logic; -- 0xFD00 (1 MHz bus)
+-signal io_sheila : std_logic; -- 0xFE00 (System peripherals)
+--- SHIELA
+-signal crtc_enable : std_logic; -- 0xFE00-FE07
+-signal acia_enable : std_logic; -- 0xFE08-FE0F
+-signal serproc_enable : std_logic; -- 0xFE10-FE1F
+-signal vidproc_enable : std_logic; -- 0xFE20-FE2F
+-signal romsel_enable : std_logic; -- 0xFE30-FE3F
+-signal sys_via_enable : std_logic; -- 0xFE40-FE5F
+-signal user_via_enable : std_logic; -- 0xFE60-FE7F
+-signal fddc_enable : std_logic; -- 0xFE80-FE9F
+-signal adlc_enable : std_logic; -- 0xFEA0-FEBF (Econet)
+-signal adc_enable : std_logic; -- 0xFEC0-FEDF
+-signal tube_enable : std_logic; -- 0xFEE0-FEFF
+-
+--- ROM select latch
+-signal romsel : std_logic_vector(3 downto 0);
+-
+-signal mhz1_enable : std_logic; -- Set for access to any 1 MHz peripheral
+-
+-begin
+- -------------------------
+- -- COMPONENT INSTANCES
+- -------------------------
+-
+- -- 32 MHz master clock
+- pll: pll32 port map (
+- pll_reset,
+- CLOCK_24(0),
+- clock,
+- pll_locked );
+-
+- -- Hardware debugger block (single-step, breakpoints)
+- debug: debugger port map (
+- clock,
+- hard_reset_n,
+- cpu_clken,
+- cpu_debug_clken,
+- debug_irq_in_n,
+- cpu_irq_n,
+- cpu_a(15 downto 0), cpu_r_nw, cpu_sync,
+- debug_aux,
+- SW(8), -- RUN
+- KEY(3), -- STEP
+- KEY(2), -- MODE
+- KEY(1), -- DIGIT
+- KEY(0), -- SET
+- HEX3, HEX2, HEX1, HEX0,
+- LEDR(3), -- BREAKPOINT
+- LEDR(2) -- WATCHPOINT
+- );
+-
+- -- 6502 CPU
+- cpu : T65 port map (
+- cpu_mode,
+- reset_n,
+- cpu_debug_clken,
+- clock,
+- cpu_ready,
+- cpu_abort_n,
+- cpu_irq_n,
+- cpu_nmi_n,
+- cpu_so_n,
+- cpu_r_nw,
+- cpu_sync,
+- cpu_ef,
+- cpu_mf,
+- cpu_xf,
+- cpu_ml_n,
+- cpu_vp_n,
+- cpu_vda,
+- cpu_vpa,
+- cpu_a,
+- cpu_di,
+- cpu_do );
+-
+- crtc : mc6845 port map (
+- clock,
+- crtc_clken,
+- reset_n,
+- crtc_enable,
+- cpu_r_nw,
+- cpu_a(0),
+- cpu_do,
+- crtc_do,
+- crtc_vsync,
+- crtc_hsync,
+- crtc_de,
+- crtc_cursor,
+- crtc_lpstb,
+- crtc_ma,
+- crtc_ra );
+-
+- video_ula : vidproc port map (
+- clock,
+- vid_clken,
+- reset_n,
+- crtc_clken,
+- vidproc_enable,
+- cpu_a(0),
+- cpu_do,
+- SRAM_DQ(7 downto 0),
+- vidproc_invert_n,
+- vidproc_disen,
+- crtc_cursor,
+- r_in, g_in, b_in,
+- r_out, g_out, b_out
+- );
+-
+- teletext : saa5050 port map (
+- CLOCK_24(0), -- This runs at 6 MHz, which we can't derive from the 32 MHz clock
+- ttxt_clken,
+- reset_n,
+- clock, -- Data input is synchronised from the bus clock domain
+- vid_clken,
+- SRAM_DQ(6 downto 0),
+- ttxt_glr,
+- ttxt_dew,
+- ttxt_crs,
+- ttxt_lose,
+- ttxt_r, ttxt_g, ttxt_b, ttxt_y
+- );
+-
+- -- System VIA
+- system_via : m6522 port map (
+- cpu_a(3 downto 0),
+- cpu_do,
+- sys_via_do,
+- sys_via_do_oe_n,
+- cpu_r_nw,
+- sys_via_enable,
+- '0', -- nCS2
+- sys_via_irq_n,
+- sys_via_ca1_in,
+- sys_via_ca2_in,
+- sys_via_ca2_out,
+- sys_via_ca2_oe_n,
+- sys_via_pa_in,
+- sys_via_pa_out,
+- sys_via_pa_oe_n,
+- sys_via_cb1_in,
+- sys_via_cb1_out,
+- sys_via_cb1_oe_n,
+- sys_via_cb2_in,
+- sys_via_cb2_out,
+- sys_via_cb2_oe_n,
+- sys_via_pb_in,
+- sys_via_pb_out,
+- sys_via_pb_oe_n,
+- mhz1_clken,
+- hard_reset_n, -- System VIA is reset by power on reset only
+- mhz4_clken,
+- clock
+- );
+-
+- -- User VIA
+- user_via : m6522 port map (
+- cpu_a(3 downto 0),
+- cpu_do,
+- user_via_do,
+- user_via_do_oe_n,
+- cpu_r_nw,
+- user_via_enable,
+- '0', -- nCS2
+- user_via_irq_n,
+- user_via_ca1_in,
+- user_via_ca2_in,
+- user_via_ca2_out,
+- user_via_ca2_oe_n,
+- user_via_pa_in,
+- user_via_pa_out,
+- user_via_pa_oe_n,
+- user_via_cb1_in,
+- user_via_cb1_out,
+- user_via_cb1_oe_n,
+- user_via_cb2_in,
+- user_via_cb2_out,
+- user_via_cb2_oe_n,
+- user_via_pb_in,
+- user_via_pb_out,
+- user_via_pb_oe_n,
+- mhz1_clken,
+- reset_n,
+- mhz4_clken,
+- clock
+- );
+-
+- -- Keyboard
+- keyb : keyboard port map (
+- clock, hard_reset_n, mhz1_clken,
+- PS2_CLK, PS2_DAT,
+- keyb_enable_n,
+- keyb_column,
+- keyb_row,
+- keyb_out,
+- keyb_int,
+- keyb_break,
+- SW(7 downto 0)
+- );
+-
+- -- Sound generator (and drive logic for I2S codec)
+- sound : sn76489_top port map (
+- clock, mhz4_clken,
+- reset_n, '0', sound_enable_n,
+- sound_ready, sound_di,
+- sound_ao
+- );
+- i2s : i2s_intf port map (
+- CLOCK_24(0), reset_n,
+- pcm_inl, pcm_inr,
+- std_logic_vector(sound_ao) & "00000000",
+- std_logic_vector(sound_ao) & "00000000",
+- AUD_XCK, AUD_DACLRCK,
+- AUD_BCLK, AUD_DACDAT, AUD_ADCDAT
+- );
+- i2c : i2c_loader
+- generic map (
+- log2_divider => 7
+- )
+- port map (
+- clock, reset_n,
+- I2C_SCLK, I2C_SDAT,
+- LEDR(5), -- IS_DONE
+- LEDR(4) -- IS_ERROR
+- );
+-
+- -- Asynchronous reset
+- -- PLL is reset by external reset switch
+- pll_reset <= not SW(9);
+- -- Keyboard and System VIA are reset by external reset switch or PLL being out of lock
+- hard_reset_n <= not (pll_reset or not pll_locked);
+- -- Rest of system is reset by all of the above plus the keyboard BREAK key
+- reset_n <= hard_reset_n and not keyb_break;
+-
+- -- Clock enable generation - 32 MHz clock split into 32 cycles
+- -- CPU is on 0 and 16 (but can be masked by 1 MHz bus accesses)
+- -- Video is on all odd cycles (16 MHz)
+- -- 1 MHz cycles are on cycle 31 (1 MHz)
+- vid_clken <= clken_counter(0); -- 1,3,5...
+- mhz4_clken <= clken_counter(0) and clken_counter(1) and clken_counter(2); -- 7/15/23/31
+- mhz2_clken <= mhz4_clken and clken_counter(3); -- 15/31
+- mhz1_clken <= mhz2_clken and clken_counter(4); -- 31
+- cpu_cycle <= not (clken_counter(0) or clken_counter(1) or clken_counter(2) or clken_counter(3)); -- 0/16
+- cpu_clken <= cpu_cycle and not cpu_cycle_mask;
+-
+- clk_gen: process(clock,reset_n)
+- begin
+- if reset_n = '0' then
+- clken_counter <= (others => '0');
+- elsif rising_edge(clock) then
+- clken_counter <= clken_counter + 1;
+- end if;
+- end process;
+-
+- cycle_stretch: process(clock,reset_n)
+- begin
+- if reset_n = '0' then
+- cpu_cycle_mask <= '0';
+- elsif rising_edge(clock) and mhz2_clken = '1' then
+- if mhz1_enable = '1' and cpu_cycle_mask = '0' then
+- -- Block CPU cycles until 1 MHz cycle has completed
+- cpu_cycle_mask <= '1';
+- end if;
+- if mhz1_clken = '1' then
+- -- CPU can run again
+- -- FIXME: This may not be correct in terms of CPU cycles, but it
+- -- should work
+- cpu_cycle_mask <= '0';
+- end if;
+- end if;
+- end process;
+-
+- ttxt_clk_gen: process(CLOCK_24(0),reset_n)
+- begin
+- if reset_n = '0' then
+- ttxt_clken_counter <= (others => '0');
+- elsif rising_edge(CLOCK_24(0)) then
+- ttxt_clken_counter <= ttxt_clken_counter + 1;
+- end if;
+- end process;
+-
+- -- 6 MHz clock enable for SAA5050
+- ttxt_clken <= '1' when ttxt_clken_counter = 0 else '0';
+-
+- -- CPU configuration and fixed signals
+- cpu_mode <= "00"; -- 6502
+- cpu_ready <= '1';
+- cpu_abort_n <= '1';
+- cpu_nmi_n <= '1';
+- cpu_so_n <= '1';
+-
+- -- Address decoding
+- -- 0x0000 = 32 KB SRAM
+- -- 0x8000 = 16 KB BASIC/Sideways ROMs
+- -- 0xC000 = 16 KB MOS ROM
+- --
+- -- IO regions are mapped into a hole in the MOS. There are three regions:
+- -- 0xFC00 = FRED
+- -- 0xFD00 = JIM
+- -- 0xFE00 = SHEILA
+- ram_enable <= not cpu_a(15);
+- rom_enable <= cpu_a(15) and not cpu_a(14);
+- mos_enable <= cpu_a(15) and cpu_a(14) and not (io_fred or io_jim or io_sheila);
+- io_fred <= '1' when cpu_a(15 downto 8) = "11111100" else '0';
+- io_jim <= '1' when cpu_a(15 downto 8) = "11111101" else '0';
+- io_sheila <= '1' when cpu_a(15 downto 8) = "11111110" else '0';
+- -- The following IO regions are accessed at 1 MHz and hence will stall the
+- -- CPU accordingly
+- mhz1_enable <= io_fred or io_jim or
+- adc_enable or sys_via_enable or user_via_enable or
+- serproc_enable or acia_enable or crtc_enable;
+-
+- -- SHEILA address demux
+- -- All the system peripherals are mapped into this page as follows:
+- -- 0xFE00 - 0xFE07 = MC6845 CRTC
+- -- 0xFE08 - 0xFE0F = MC6850 ACIA (Serial/Tape)
+- -- 0xFE10 - 0xFE1F = Serial ULA
+- -- 0xFE20 - 0xFE2F = Video ULA
+- -- 0xFE30 - 0xFE3F = Paged ROM select latch
+- -- 0xFE40 - 0xFE5F = System VIA (6522)
+- -- 0xFE60 - 0xFE7F = User VIA (6522)
+- -- 0xFE80 - 0xFE9F = 8271 Floppy disc controller
+- -- 0xFEA0 - 0xFEBF = 68B54 ADLC for Econet
+- -- 0xFEC0 - 0xFEDF = uPD7002 ADC
+- -- 0xFEE0 - 0xFEFF = Tube ULA
+- process(cpu_a,io_sheila)
+- begin
+- -- All regions normally de-selected
+- crtc_enable <= '0';
+- acia_enable <= '0';
+- serproc_enable <= '0';
+- vidproc_enable <= '0';
+- romsel_enable <= '0';
+- sys_via_enable <= '0';
+- user_via_enable <= '0';
+- fddc_enable <= '0';
+- adlc_enable <= '0';
+- adc_enable <= '0';
+- tube_enable <= '0';
+-
+- if io_sheila = '1' then
+- case cpu_a(7 downto 5) is
+- when "000" =>
+- -- 0xFE00
+- if cpu_a(4) = '0' then
+- if cpu_a(3) = '0' then
+- -- 0xFE00
+- crtc_enable <= '1';
+- else
+- -- 0xFE08
+- acia_enable <= '1';
+- end if;
+- else
+- -- 0xFE10
+- serproc_enable <= '1';
+- end if;
+- when "001" =>
+- -- 0xFE20
+- if cpu_a(4) = '0' then
+- -- 0xFE20
+- vidproc_enable <= '1';
+- else
+- -- 0xFE30
+- romsel_enable <= '1';
+- end if;
+- when "010" => sys_via_enable <= '1'; -- 0xFE40
+- when "011" => user_via_enable <= '1'; -- 0xFE60
+- when "100" => fddc_enable <= '1'; -- 0xFE80
+- when "101" => adlc_enable <= '1'; -- 0xFEA0
+- when "110" => adc_enable <= '1'; -- 0xFEC0
+- when "111" => tube_enable <= '1'; -- 0xFEE0
+- when others =>
+- null;
+- end case;
+- end if;
+- end process;
+-
+- -- CPU data bus mux and interrupts
+- cpu_di <=
+- SRAM_DQ(7 downto 0) when ram_enable = '1' else
+- FL_DQ when rom_enable = '1' else
+- FL_DQ when mos_enable = '1' else
+- crtc_do when crtc_enable = '1' else
+- "00000010" when acia_enable = '1' else
+- sys_via_do when sys_via_enable = '1' else
+- user_via_do when user_via_enable = '1' else
+- (others => '0'); -- un-decoded locations are pulled down by RP1
+- debug_irq_in_n <= sys_via_irq_n and user_via_irq_n; -- route IRQ through debugger
+- --cpu_irq_n <= sys_via_irq_n and user_via_irq_n;
+-
+- -- ROMs are in external flash and split into 16K slots (since this also suits other
+- -- computers that might be run on the same board).
+- -- The first 8 slots are allocated for use here, and the first 4 are decoded as
+- -- the sideways ROMs. Slot 7 is used for the MOS.
+- FL_RST_N <= reset_n;
+- FL_CE_N <= '0';
+- FL_OE_N <= '0';
+- FL_WE_N <= '1';
+- FL_ADDR(21 downto 17) <= ROM_OFFSET(7 downto 3);
+- FL_ADDR(16 downto 14) <=
+- "111" when mos_enable = '1' else
+- "0" & romsel(1 downto 0);
+- FL_ADDR(13 downto 0) <= cpu_a(13 downto 0);
+-
+- -- SRAM bus
+- SRAM_UB_N <= '1';
+- SRAM_LB_N <= '0';
+- SRAM_CE_N <= '0';
+- SRAM_OE_N <= '0';
+- SRAM_DQ(15 downto 8) <= (others => '0');
+-
+- -- Synchronous outputs to SRAM
+- process(clock,reset_n)
+- variable ram_write : std_logic;
+- begin
+- ram_write := ram_enable and not cpu_r_nw;
+-
+- if reset_n = '0' then
+- SRAM_WE_N <= '1';
+- SRAM_DQ(7 downto 0) <= (others => 'Z');
+- elsif rising_edge(clock) then
+- -- Default to inputs
+- SRAM_DQ(7 downto 0) <= (others => 'Z');
+-
+- -- Register SRAM signals to outputs (clock must be at least 2x CPU clock)
+- if vid_clken = '1' then
+- -- Fetch data from previous CPU cycle
+- SRAM_WE_N <= not ram_write;
+- SRAM_ADDR <= "00" & cpu_a(15 downto 0);
+- if ram_write = '1' then
+- SRAM_DQ(7 downto 0) <= cpu_do;
+- end if;
+- else
+- -- Fetch data from previous display cycle
+- SRAM_WE_N <= '1';
+- SRAM_ADDR <= "000" & display_a;
+- end if;
+- end if;
+- end process;
+-
+- -- Address translation logic for calculation of display address
+- process(crtc_ma,crtc_ra,disp_addr_offs)
+- variable aa : unsigned(3 downto 0);
+- begin
+- if crtc_ma(12) = '0' then
+- -- No adjustment
+- aa := unsigned(crtc_ma(11 downto 8));
+- else
+- -- Address adjusted according to screen mode to compensate for
+- -- wrap at 0x8000.
+- case disp_addr_offs is
+- when "00" =>
+- -- Mode 3 - restart at 0x4000
+- aa := unsigned(crtc_ma(11 downto 8)) + 8;
+- when "01" =>
+- -- Mode 6 - restart at 0x6000
+- aa := unsigned(crtc_ma(11 downto 8)) + 12;
+- when "10" =>
+- -- Mode 0,1,2 - restart at 0x3000
+- aa := unsigned(crtc_ma(11 downto 8)) + 6;
+- when "11" =>
+- -- Mode 4,5 - restart at 0x5800
+- aa := unsigned(crtc_ma(11 downto 8)) + 11;
+- when others =>
+- null;
+- end case;
+- end if;
+-
+- if crtc_ma(13) = '0' then
+- -- HI RES
+- display_a <= std_logic_vector(aa(3 downto 0)) & crtc_ma(7 downto 0) & crtc_ra(2 downto 0);
+- else
+- -- TTX VDU
+- display_a <= std_logic(aa(3)) & "1111" & crtc_ma(9 downto 0);
+- end if;
+- end process;
+-
+- -- VIDPROC
+- vidproc_invert_n <= '1';
+- vidproc_disen <= crtc_de and not crtc_ra(3); -- DISEN is masked off by RA(3) for MODEs 3 and 6
+- r_in <= ttxt_r;
+- g_in <= ttxt_g;
+- b_in <= ttxt_b;
+-
+- -- SAA5050
+- ttxt_glr <= not crtc_hsync;
+- ttxt_dew <= crtc_vsync;
+- ttxt_crs <= not crtc_ra(0);
+- ttxt_lose <= crtc_de;
+-
+- -- CRTC drives video out (CSYNC on HSYNC output, VSYNC high)
+- VGA_HS <= not (crtc_hsync xor crtc_vsync);
+- VGA_VS <= '1';
+- VGA_R <= r_out & r_out & r_out & r_out;
+- VGA_G <= g_out & g_out & g_out & g_out;
+- VGA_B <= b_out & b_out & b_out & b_out;
+-
+- -- Connections to System VIA
+- -- ADC
+- sys_via_cb1_in <= '1'; -- /EOC
+- -- CRTC
+- sys_via_ca1_in <= crtc_vsync;
+- sys_via_cb2_in <= crtc_lpstb;
+- -- Keyboard
+- sys_via_ca2_in <= keyb_int;
+- sys_via_pa_in(7) <= keyb_out;
+- sys_via_pa_in(6 downto 0) <= sys_via_pa_out(6 downto 0); -- Must loop back output pins or keyboard won't work
+- keyb_column <= sys_via_pa_out(3 downto 0);
+- keyb_row <= sys_via_pa_out(6 downto 4);
+- -- Sound
+- sound_di <= sys_via_pa_out;
+- -- Others (idle until missing bits implemented)
+- sys_via_pb_in(7 downto 4) <= (others => '1');
+-
+- -- Connections to User VIA (user port is output on green LEDs)
+- user_via_ca1_in <= '1'; -- Pulled up
+- --LEDG <= user_via_pb_out;
+-
+- -- MMBEEB
+- user_via_cb1_in <= user_via_pb_out(1);
+- SD_SCLK <= user_via_pb_out(1); -- SCLK
+- SD_MOSI <= user_via_pb_out(0); -- SDO
+- SD_nCS <= '0'; -- CS
+- user_via_cb2_in <= SD_MISO; -- SDI
+- user_via_pb_in <= user_via_pb_out;
+-
+- -- ROM select latch
+- process(clock,reset_n)
+- begin
+- if reset_n = '0' then
+- romsel <= (others => '0');
+- elsif rising_edge(clock) then
+- if romsel_enable = '1' and cpu_r_nw = '0' then
+- romsel <= cpu_do(3 downto 0);
+- end if;
+- end if;
+- end process;
+-
+- -- IC32 latch
+- sound_enable_n <= ic32(0);
+- speech_write_n <= ic32(1);
+- speech_read_n <= ic32(2);
+- keyb_enable_n <= ic32(3);
+- disp_addr_offs <= ic32(5 downto 4);
+- caps_lock_led_n <= ic32(6);
+- shift_lock_led_n <= ic32(7);
+-
+- process(clock,reset_n)
+- variable bit_num : integer;
+- begin
+- bit_num := to_integer(unsigned(sys_via_pb_out(2 downto 0)));
+-
+- if reset_n = '0' then
+- ic32 <= (others => '0');
+- elsif rising_edge(clock) then
+- ic32(bit_num) <= sys_via_pb_out(3);
+- end if;
+- end process;
+-
+- -- Keyboard LEDs
+- LEDR(0) <= not caps_lock_led_n;
+- LEDR(1) <= not shift_lock_led_n;
+-
+- -----------------
+- -- DEBUG STUFF
+- -----------------
+-
+- GPIO_0(0) <= not (crtc_hsync xor crtc_vsync);
+- GPIO_0(1) <= crtc_de;
+-
+-end architecture;
++-- BBC Micro for Altera DE1 ++-- ++-- Copyright (c) 2011 Mike Stirling ++-- ++-- 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 agreement from the author. ++-- ++-- * License is granted for non-commercial use only. A fee may not be charged ++-- for redistributions as source code or in synthesized/hardware form without ++-- specific prior written agreement from the author. ++-- ++-- 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. ++-- ++-- BBC B Micro ++-- ++-- Terasic DE1 top-level ++-- ++-- (C) 2011 Mike Stirling ++ ++library IEEE; ++use IEEE.STD_LOGIC_1164.ALL; ++use IEEE.NUMERIC_STD.ALL; ++ ++-- Generic top-level entity for Altera DE1 board ++entity bbc_micro_de1 is ++generic ( ++ -- ROM offset ++ -- The 4MB Flash is used in 16KB banks as a simple mechanism for ++ -- different machines to address different parts of the ROM, saving ++ -- on re-flashing each time a new machine is run on the board. ++ -- This generic sets the upper 8 address bits. ++ -- Note that the lower bits may be ignored by the implementation, ++ -- e.g. where ROMs are bigger than 16K or where multiple banks ++ -- are required. In this case it is important to ensure that the ++ -- ROM images are aligned correctly (such that these ignored bits are 0). ++ -- ++ -- For the BBC the ROMs start in bank 8 (the first 8 banks are used by ++ -- the Spectrum project). The particular bank is selected by the sideways ++ -- ROM paging register, and bank 7 is used for the MOS. Recommended layout ++ -- is: ++ -- ++ -- 0 Sideways ++ -- 1 Sideways ++ -- 2 Sideways - SuperMMC (DFS) ++ -- 3 Sideways - BASIC ++ -- 4 Not used ++ -- 5 Not used ++ -- 6 Not used ++ -- 7 MOS ++ ROM_OFFSET : std_logic_vector(7 downto 0) := "00001000" ++ ); ++port ( ++ -- Clocks ++ CLOCK_24 : in std_logic_vector(1 downto 0); ++ CLOCK_27 : in std_logic_vector(1 downto 0); ++ CLOCK_50 : in std_logic; ++ EXT_CLOCK : in std_logic; ++ ++ -- Switches ++ SW : in std_logic_vector(9 downto 0); ++ -- Buttons ++ KEY : in std_logic_vector(3 downto 0); ++ ++ -- 7 segment displays ++ HEX0 : out std_logic_vector(6 downto 0); ++ HEX1 : out std_logic_vector(6 downto 0); ++ HEX2 : out std_logic_vector(6 downto 0); ++ HEX3 : out std_logic_vector(6 downto 0); ++ -- Red LEDs ++ LEDR : out std_logic_vector(9 downto 0); ++ -- Green LEDs ++ LEDG : out std_logic_vector(7 downto 0); ++ ++ -- VGA ++ VGA_R : out std_logic_vector(3 downto 0); ++ VGA_G : out std_logic_vector(3 downto 0); ++ VGA_B : out std_logic_vector(3 downto 0); ++ VGA_HS : out std_logic; ++ VGA_VS : out std_logic; ++ ++ -- Serial ++ UART_RXD : in std_logic; ++ UART_TXD : out std_logic; ++ ++ -- PS/2 Keyboard ++ PS2_CLK : inout std_logic; ++ PS2_DAT : inout std_logic; ++ ++ -- I2C ++ I2C_SCLK : inout std_logic; ++ I2C_SDAT : inout std_logic; ++ ++ -- Audio ++ AUD_XCK : out std_logic; ++ AUD_BCLK : out std_logic; ++ AUD_ADCLRCK : out std_logic; ++ AUD_ADCDAT : in std_logic; ++ AUD_DACLRCK : out std_logic; ++ AUD_DACDAT : out std_logic; ++ ++ -- SRAM ++ SRAM_ADDR : out std_logic_vector(17 downto 0); ++ SRAM_DQ : inout std_logic_vector(15 downto 0); ++ SRAM_CE_N : out std_logic; ++ SRAM_OE_N : out std_logic; ++ SRAM_WE_N : out std_logic; ++ SRAM_UB_N : out std_logic; ++ SRAM_LB_N : out std_logic; ++ ++ -- SDRAM ++ DRAM_ADDR : out std_logic_vector(11 downto 0); ++ DRAM_DQ : inout std_logic_vector(15 downto 0); ++ DRAM_BA_0 : in std_logic; ++ DRAM_BA_1 : in std_logic; ++ DRAM_CAS_N : in std_logic; ++ DRAM_CKE : in std_logic; ++ DRAM_CLK : in std_logic; ++ DRAM_CS_N : in std_logic; ++ DRAM_LDQM : in std_logic; ++ DRAM_RAS_N : in std_logic; ++ DRAM_UDQM : in std_logic; ++ DRAM_WE_N : in std_logic; ++ ++ -- Flash ++ FL_ADDR : out std_logic_vector(21 downto 0); ++ FL_DQ : inout std_logic_vector(7 downto 0); ++ FL_RST_N : out std_logic; ++ FL_OE_N : out std_logic; ++ FL_WE_N : out std_logic; ++ FL_CE_N : out std_logic; ++ ++ -- SD card (SPI mode) ++ SD_nCS : out std_logic; ++ SD_MOSI : out std_logic; ++ SD_SCLK : out std_logic; ++ SD_MISO : in std_logic; ++ ++ -- GPIO ++ GPIO_0 : inout std_logic_vector(35 downto 0); ++ GPIO_1 : inout std_logic_vector(35 downto 0) ++ ); ++end entity; ++ ++architecture rtl of bbc_micro_de1 is ++ ++------------------------------ ++-- PLL (32 MHz master clock) ++------------------------------ ++ ++component pll32 IS ++ PORT ++ ( ++ areset : IN STD_LOGIC := '0'; ++ inclk0 : IN STD_LOGIC := '0'; ++ c0 : OUT STD_LOGIC ; ++ locked : OUT STD_LOGIC ++ ); ++end component; ++ ++--------- ++-- CPU ++--------- ++ ++component 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) ++ ); ++end component; ++ ++----------------- ++-- MC6845 CRTC ++----------------- ++ ++component mc6845 is ++port ( ++ CLOCK : in std_logic; ++ CLKEN : in std_logic; ++ nRESET : in std_logic; ++ ++ -- Bus interface ++ ENABLE : in std_logic; ++ R_nW : in std_logic; ++ RS : in std_logic; ++ DI : in std_logic_vector(7 downto 0); ++ DO : out std_logic_vector(7 downto 0); ++ ++ -- Display interface ++ VSYNC : out std_logic; ++ HSYNC : out std_logic; ++ DE : out std_logic; ++ CURSOR : out std_logic; ++ LPSTB : in std_logic; ++ ++ -- Memory interface ++ MA : out std_logic_vector(13 downto 0); ++ RA : out std_logic_vector(4 downto 0) ++ ); ++end component; ++ ++------------------------- ++-- "VIDPROC" Video ULA ++------------------------- ++ ++component vidproc is ++port ( ++ CLOCK : in std_logic; ++ -- Clock enable qualifies display cycles (interleaved with CPU cycles) ++ CLKEN : in std_logic; ++ nRESET : in std_logic; ++ ++ -- Clock enable output to CRTC ++ CLKEN_CRTC : out std_logic; ++ ++ -- Bus interface ++ ENABLE : in std_logic; ++ A0 : in std_logic; ++ -- CPU data bus (for register writes) ++ DI_CPU : in std_logic_vector(7 downto 0); ++ -- Display RAM data bus (for display data fetch) ++ DI_RAM : in std_logic_vector(7 downto 0); ++ ++ -- Control interface ++ nINVERT : in std_logic; ++ DISEN : in std_logic; ++ CURSOR : in std_logic; ++ ++ -- Video in (teletext mode) ++ R_IN : in std_logic; ++ G_IN : in std_logic; ++ B_IN : in std_logic; ++ ++ -- Video out ++ R : out std_logic; ++ G : out std_logic; ++ B : out std_logic ++ ); ++end component; ++ ++-------------------------------- ++-- SAA5050 Teletext Generator ++-------------------------------- ++ ++component saa5050 is ++port ( ++ CLOCK : in std_logic; ++ -- 6 MHz dot clock enable ++ CLKEN : in std_logic; ++ -- Async reset ++ nRESET : in std_logic; ++ ++ -- Character data input (in the bus clock domain) ++ DI_CLOCK : in std_logic; ++ DI_CLKEN : in std_logic; ++ DI : in std_logic_vector(6 downto 0); ++ ++ -- Timing inputs ++ -- General line reset (not used) ++ GLR : in std_logic; -- /HSYNC ++ -- Data entry window - high during VSYNC. ++ -- Resets ROM row counter and drives 'flash' signal ++ DEW : in std_logic; -- VSYNC ++ -- Character rounding select - high during even field ++ CRS : in std_logic; -- FIELD ++ -- Load output shift register enable - high during active video ++ LOSE : in std_logic; -- DE ++ ++ -- Video out ++ R : out std_logic; ++ G : out std_logic; ++ B : out std_logic; ++ Y : out std_logic ++ ); ++end component; ++ ++-------------- ++-- 6522 VIA ++-------------- ++ ++component 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); ++ ++ -- FIXME: Revisit timing in this component. Does it really need a 4x clock? ++ I_P2_H : in std_logic; -- high for phase 2 clock ____----__ ++ RESET_L : in std_logic; ++ ENA_4 : in std_logic; -- clk enable (4x system clock rate) ++ CLK : in std_logic ++ ); ++end component; ++ ++----------------------------- ++-- PS/2 Keyboard Emulation ++----------------------------- ++ ++component keyboard is ++port ( ++ CLOCK : in std_logic; ++ nRESET : in std_logic; ++ CLKEN_1MHZ : in std_logic; ++ ++ -- PS/2 interface ++ PS2_CLK : in std_logic; ++ PS2_DATA : in std_logic; ++ ++ -- If 1 then column is incremented automatically at ++ -- 1 MHz rate ++ AUTOSCAN : in std_logic; ++ ++ COLUMN : in std_logic_vector(3 downto 0); ++ ROW : in std_logic_vector(2 downto 0); ++ ++ -- 1 when currently selected key is down (AUTOSCAN disabled) ++ KEYPRESS : out std_logic; ++ -- 1 when any key is down (except row 0) ++ INT : out std_logic; ++ -- BREAK key output - 1 when pressed ++ BREAK_OUT : out std_logic; ++ ++ -- DIP switch inputs ++ DIP_SWITCH : in std_logic_vector(7 downto 0) ++ ); ++end component; ++ ++----------------------------- ++-- SN76489 sound generator ++----------------------------- ++ ++component sn76489_top is ++ ++ generic ( ++ clock_div_16_g : integer := 1 ++ ); ++ port ( ++ clock_i : in std_logic; ++ clock_en_i : in std_logic; ++ res_n_i : in std_logic; ++ ce_n_i : in std_logic; ++ we_n_i : in std_logic; ++ ready_o : out std_logic; ++ d_i : in std_logic_vector(0 to 7); ++ aout_o : out signed(0 to 7) ++ ); ++ ++end component; ++ ++component i2s_intf is ++generic( ++ mclk_rate : positive := 12000000; ++ sample_rate : positive := 8000; ++ preamble : positive := 1; -- I2S ++ word_length : positive := 16 ++ ); ++ ++port ( ++ -- 2x MCLK in (e.g. 24 MHz for WM8731 USB mode) ++ CLK : in std_logic; ++ nRESET : in std_logic; ++ ++ -- Parallel IO ++ PCM_INL : out std_logic_vector(word_length - 1 downto 0); ++ PCM_INR : out std_logic_vector(word_length - 1 downto 0); ++ PCM_OUTL : in std_logic_vector(word_length - 1 downto 0); ++ PCM_OUTR : in std_logic_vector(word_length - 1 downto 0); ++ ++ -- Codec interface (right justified mode) ++ -- MCLK is generated at half of the CLK input ++ I2S_MCLK : out std_logic; ++ -- LRCLK is equal to the sample rate and is synchronous to ++ -- MCLK. It must be related to MCLK by the oversampling ratio ++ -- given in the codec datasheet. ++ I2S_LRCLK : out std_logic; ++ ++ -- Data is shifted out on the falling edge of BCLK, sampled ++ -- on the rising edge. The bit rate is determined such that ++ -- it is fast enough to fit preamble + word_length bits into ++ -- each LRCLK half cycle. The last cycle of each word may be ++ -- stretched to fit to LRCLK. This is OK at least for the ++ -- WM8731 codec. ++ -- The first falling edge of each timeslot is always synchronised ++ -- with the LRCLK edge. ++ I2S_BCLK : out std_logic; ++ -- Output bitstream ++ I2S_DOUT : out std_logic; ++ -- Input bitstream ++ I2S_DIN : in std_logic ++ ); ++end component; ++ ++component i2c_loader is ++generic ( ++ -- Address of slave to be loaded ++ device_address : integer := 16#1a#; ++ -- Number of retries to allow before stopping ++ num_retries : integer := 0; ++ -- Length of clock divider in bits. Resulting bus frequency is ++ -- CLK/2^(log2_divider + 2) ++ log2_divider : integer := 6 ++); ++ ++port ( ++ CLK : in std_logic; ++ nRESET : in std_logic; ++ ++ I2C_SCL : inout std_logic; ++ I2C_SDA : inout std_logic; ++ ++ IS_DONE : out std_logic; ++ IS_ERROR : out std_logic ++ ); ++end component; ++ ++component debugger is ++generic ( ++ -- Set this for a reasonable half flash duration relative to the ++ -- clock frequency ++ flash_divider : natural := 24 ++ ); ++port ( ++ CLOCK : in std_logic; ++ nRESET : in std_logic; ++ -- CPU clock enable in ++ CLKEN_IN : in std_logic; ++ -- Gated clock enable back out to CPU ++ CLKEN_OUT : out std_logic; ++ -- CPU IRQ in ++ nIRQ_IN : in std_logic; ++ -- Gated IRQ back out to CPU (no interrupts when single stepping) ++ nIRQ_OUT : out std_logic; ++ ++ -- CPU ++ A_CPU : in std_logic_vector(15 downto 0); ++ R_nW : in std_logic; ++ SYNC : in std_logic; ++ ++ -- Aux bus input for display in hex ++ AUX_BUS : in std_logic_vector(15 downto 0); ++ ++ -- Controls ++ -- RUN or HALT CPU ++ RUN : in std_logic; ++ -- Push button to single-step in HALT mode ++ nSTEP : in std_logic; ++ -- Push button to cycle display mode ++ nMODE : in std_logic; ++ -- Push button to cycle display digit in edit mode ++ nDIGIT : in std_logic; ++ -- Push button to cycle digit value in edit mode ++ nSET : in std_logic; ++ ++ -- Output to display ++ DIGIT3 : out std_logic_vector(6 downto 0); ++ DIGIT2 : out std_logic_vector(6 downto 0); ++ DIGIT1 : out std_logic_vector(6 downto 0); ++ DIGIT0 : out std_logic_vector(6 downto 0); ++ ++ LED_BREAKPOINT : out std_logic; ++ LED_WATCHPOINT : out std_logic ++ ); ++end component; ++ ++------------- ++-- Signals ++------------- ++ ++-- Master clock - 32 MHz ++signal pll_reset : std_logic; ++signal pll_locked : std_logic; ++signal clock : std_logic; ++signal hard_reset_n : std_logic; ++signal reset_n : std_logic; ++ ++-- Clock enable counter ++-- CPU and video cycles are interleaved. The CPU runs at 2 MHz (every 16th ++-- cycle) and the video subsystem is enabled on every odd cycle. ++signal clken_counter : unsigned(4 downto 0); ++signal cpu_cycle : std_logic; -- Qualifies all 2 MHz cycles ++signal cpu_cycle_mask : std_logic; -- Set to mask CPU cycles until 1 MHz cycle is complete ++signal cpu_clken : std_logic; -- 2 MHz cycles in which the CPU is enabled ++signal cpu_debug_clken : std_logic; -- CPU clken return from hardware debugger ++-- IO cycles are out of phase with the CPU ++signal vid_clken : std_logic; -- 16 MHz video cycles ++signal mhz4_clken : std_logic; -- Used by 6522 ++signal mhz2_clken : std_logic; -- Used for latching CPU address for clock stretch ++signal mhz1_clken : std_logic; -- 1 MHz bus and associated peripherals, 6522 phase 2 ++-- SAA5050 needs a 6 MHz clock enable relative to a 24 MHz clock ++signal ttxt_clken_counter : unsigned(1 downto 0); ++signal ttxt_clken : std_logic; ++ ++-- Debugger connections ++signal debug_irq_in_n : std_logic; ++signal debug_aux : std_logic_vector(15 downto 0); ++ ++-- CPU signals ++signal cpu_mode : std_logic_vector(1 downto 0); ++signal cpu_ready : std_logic; ++signal cpu_abort_n : std_logic; ++signal cpu_irq_n : std_logic; ++signal cpu_nmi_n : std_logic; ++signal cpu_so_n : std_logic; ++signal cpu_r_nw : std_logic; ++signal cpu_sync : std_logic; ++signal cpu_ef : std_logic; ++signal cpu_mf : std_logic; ++signal cpu_xf : std_logic; ++signal cpu_ml_n : std_logic; ++signal cpu_vp_n : std_logic; ++signal cpu_vda : std_logic; ++signal cpu_vpa : std_logic; ++signal cpu_a : std_logic_vector(23 downto 0); ++signal cpu_di : std_logic_vector(7 downto 0); ++signal cpu_do : std_logic_vector(7 downto 0); ++ ++-- CRTC signals ++signal crtc_clken : std_logic; ++signal crtc_do : std_logic_vector(7 downto 0); ++signal crtc_vsync : std_logic; ++signal crtc_hsync : std_logic; ++signal crtc_de : std_logic; ++signal crtc_cursor : std_logic; ++signal crtc_lpstb : std_logic := '0'; ++signal crtc_ma : std_logic_vector(13 downto 0); ++signal crtc_ra : std_logic_vector(4 downto 0); ++ ++-- Decoded display address after address translation for hardware ++-- scrolling ++signal display_a : std_logic_vector(14 downto 0); ++ ++-- "VIDPROC" signals ++signal vidproc_invert_n : std_logic; ++signal vidproc_disen : std_logic; ++signal r_in : std_logic; ++signal g_in : std_logic; ++signal b_in : std_logic; ++signal r_out : std_logic; ++signal g_out : std_logic; ++signal b_out : std_logic; ++ ++-- SAA5050 signals ++signal ttxt_glr : std_logic; ++signal ttxt_dew : std_logic; ++signal ttxt_crs : std_logic; ++signal ttxt_lose : std_logic; ++signal ttxt_r : std_logic; ++signal ttxt_g : std_logic; ++signal ttxt_b : std_logic; ++signal ttxt_y : std_logic; ++ ++-- System VIA signals ++signal sys_via_do : std_logic_vector(7 downto 0); ++signal sys_via_do_oe_n : std_logic; ++signal sys_via_irq_n : std_logic; ++signal sys_via_ca1_in : std_logic := '0'; ++signal sys_via_ca2_in : std_logic := '0'; ++signal sys_via_ca2_out : std_logic; ++signal sys_via_ca2_oe_n : std_logic; ++signal sys_via_pa_in : std_logic_vector(7 downto 0); ++signal sys_via_pa_out : std_logic_vector(7 downto 0); ++signal sys_via_pa_oe_n : std_logic_vector(7 downto 0); ++signal sys_via_cb1_in : std_logic := '0'; ++signal sys_via_cb1_out : std_logic; ++signal sys_via_cb1_oe_n : std_logic; ++signal sys_via_cb2_in : std_logic := '0'; ++signal sys_via_cb2_out : std_logic; ++signal sys_via_cb2_oe_n : std_logic; ++signal sys_via_pb_in : std_logic_vector(7 downto 0); ++signal sys_via_pb_out : std_logic_vector(7 downto 0); ++signal sys_via_pb_oe_n : std_logic_vector(7 downto 0); ++ ++-- User VIA signals ++signal user_via_do : std_logic_vector(7 downto 0); ++signal user_via_do_oe_n : std_logic; ++signal user_via_irq_n : std_logic; ++signal user_via_ca1_in : std_logic := '0'; ++signal user_via_ca2_in : std_logic := '0'; ++signal user_via_ca2_out : std_logic; ++signal user_via_ca2_oe_n : std_logic; ++signal user_via_pa_in : std_logic_vector(7 downto 0); ++signal user_via_pa_out : std_logic_vector(7 downto 0); ++signal user_via_pa_oe_n : std_logic_vector(7 downto 0); ++signal user_via_cb1_in : std_logic := '0'; ++signal user_via_cb1_out : std_logic; ++signal user_via_cb1_oe_n : std_logic; ++signal user_via_cb2_in : std_logic := '0'; ++signal user_via_cb2_out : std_logic; ++signal user_via_cb2_oe_n : std_logic; ++signal user_via_pb_in : std_logic_vector(7 downto 0); ++signal user_via_pb_out : std_logic_vector(7 downto 0); ++signal user_via_pb_oe_n : std_logic_vector(7 downto 0); ++ ++-- IC32 latch on System VIA ++signal ic32 : std_logic_vector(7 downto 0); ++signal sound_enable_n : std_logic; ++signal speech_read_n : std_logic; ++signal speech_write_n : std_logic; ++signal keyb_enable_n : std_logic; ++signal disp_addr_offs : std_logic_vector(1 downto 0); ++signal caps_lock_led_n : std_logic; ++signal shift_lock_led_n : std_logic; ++ ++-- Keyboard ++signal keyb_column : std_logic_vector(3 downto 0); ++signal keyb_row : std_logic_vector(2 downto 0); ++signal keyb_out : std_logic; ++signal keyb_int : std_logic; ++signal keyb_break : std_logic; ++ ++-- Sound generator ++signal sound_ready : std_logic; ++signal sound_di : std_logic_vector(7 downto 0); ++signal sound_ao : signed(7 downto 0); ++signal pcm_inl : std_logic_vector(15 downto 0); ++signal pcm_inr : std_logic_vector(15 downto 0); ++ ++-- Memory enables ++signal ram_enable : std_logic; -- 0x0000 ++signal rom_enable : std_logic; -- 0x8000 (BASIC/sideways ROMs) ++signal mos_enable : std_logic; -- 0xC000 ++-- IO region enables ++signal io_fred : std_logic; -- 0xFC00 (1 MHz bus) ++signal io_jim : std_logic; -- 0xFD00 (1 MHz bus) ++signal io_sheila : std_logic; -- 0xFE00 (System peripherals) ++-- SHIELA ++signal crtc_enable : std_logic; -- 0xFE00-FE07 ++signal acia_enable : std_logic; -- 0xFE08-FE0F ++signal serproc_enable : std_logic; -- 0xFE10-FE1F ++signal vidproc_enable : std_logic; -- 0xFE20-FE2F ++signal romsel_enable : std_logic; -- 0xFE30-FE3F ++signal sys_via_enable : std_logic; -- 0xFE40-FE5F ++signal user_via_enable : std_logic; -- 0xFE60-FE7F ++signal fddc_enable : std_logic; -- 0xFE80-FE9F ++signal adlc_enable : std_logic; -- 0xFEA0-FEBF (Econet) ++signal adc_enable : std_logic; -- 0xFEC0-FEDF ++signal tube_enable : std_logic; -- 0xFEE0-FEFF ++ ++-- ROM select latch ++signal romsel : std_logic_vector(3 downto 0); ++ ++signal mhz1_enable : std_logic; -- Set for access to any 1 MHz peripheral ++ ++begin ++ ------------------------- ++ -- COMPONENT INSTANCES ++ ------------------------- ++ ++ -- 32 MHz master clock ++ pll: pll32 port map ( ++ pll_reset, ++ CLOCK_24(0), ++ clock, ++ pll_locked ); ++ ++ -- Hardware debugger block (single-step, breakpoints) ++ debug: debugger port map ( ++ clock, ++ hard_reset_n, ++ cpu_clken, ++ cpu_debug_clken, ++ debug_irq_in_n, ++ cpu_irq_n, ++ cpu_a(15 downto 0), cpu_r_nw, cpu_sync, ++ debug_aux, ++ SW(8), -- RUN ++ KEY(3), -- STEP ++ KEY(2), -- MODE ++ KEY(1), -- DIGIT ++ KEY(0), -- SET ++ HEX3, HEX2, HEX1, HEX0, ++ LEDR(3), -- BREAKPOINT ++ LEDR(2) -- WATCHPOINT ++ ); ++ ++ -- 6502 CPU ++ cpu : T65 port map ( ++ cpu_mode, ++ reset_n, ++ cpu_debug_clken, ++ clock, ++ cpu_ready, ++ cpu_abort_n, ++ cpu_irq_n, ++ cpu_nmi_n, ++ cpu_so_n, ++ cpu_r_nw, ++ cpu_sync, ++ cpu_ef, ++ cpu_mf, ++ cpu_xf, ++ cpu_ml_n, ++ cpu_vp_n, ++ cpu_vda, ++ cpu_vpa, ++ cpu_a, ++ cpu_di, ++ cpu_do ); ++ ++ crtc : mc6845 port map ( ++ clock, ++ crtc_clken, ++ reset_n, ++ crtc_enable, ++ cpu_r_nw, ++ cpu_a(0), ++ cpu_do, ++ crtc_do, ++ crtc_vsync, ++ crtc_hsync, ++ crtc_de, ++ crtc_cursor, ++ crtc_lpstb, ++ crtc_ma, ++ crtc_ra ); ++ ++ video_ula : vidproc port map ( ++ clock, ++ vid_clken, ++ reset_n, ++ crtc_clken, ++ vidproc_enable, ++ cpu_a(0), ++ cpu_do, ++ SRAM_DQ(7 downto 0), ++ vidproc_invert_n, ++ vidproc_disen, ++ crtc_cursor, ++ r_in, g_in, b_in, ++ r_out, g_out, b_out ++ ); ++ ++ teletext : saa5050 port map ( ++ CLOCK_24(0), -- This runs at 6 MHz, which we can't derive from the 32 MHz clock ++ ttxt_clken, ++ reset_n, ++ clock, -- Data input is synchronised from the bus clock domain ++ vid_clken, ++ SRAM_DQ(6 downto 0), ++ ttxt_glr, ++ ttxt_dew, ++ ttxt_crs, ++ ttxt_lose, ++ ttxt_r, ttxt_g, ttxt_b, ttxt_y ++ ); ++ ++ -- System VIA ++ system_via : m6522 port map ( ++ cpu_a(3 downto 0), ++ cpu_do, ++ sys_via_do, ++ sys_via_do_oe_n, ++ cpu_r_nw, ++ sys_via_enable, ++ '0', -- nCS2 ++ sys_via_irq_n, ++ sys_via_ca1_in, ++ sys_via_ca2_in, ++ sys_via_ca2_out, ++ sys_via_ca2_oe_n, ++ sys_via_pa_in, ++ sys_via_pa_out, ++ sys_via_pa_oe_n, ++ sys_via_cb1_in, ++ sys_via_cb1_out, ++ sys_via_cb1_oe_n, ++ sys_via_cb2_in, ++ sys_via_cb2_out, ++ sys_via_cb2_oe_n, ++ sys_via_pb_in, ++ sys_via_pb_out, ++ sys_via_pb_oe_n, ++ mhz1_clken, ++ hard_reset_n, -- System VIA is reset by power on reset only ++ mhz4_clken, ++ clock ++ ); ++ ++ -- User VIA ++ user_via : m6522 port map ( ++ cpu_a(3 downto 0), ++ cpu_do, ++ user_via_do, ++ user_via_do_oe_n, ++ cpu_r_nw, ++ user_via_enable, ++ '0', -- nCS2 ++ user_via_irq_n, ++ user_via_ca1_in, ++ user_via_ca2_in, ++ user_via_ca2_out, ++ user_via_ca2_oe_n, ++ user_via_pa_in, ++ user_via_pa_out, ++ user_via_pa_oe_n, ++ user_via_cb1_in, ++ user_via_cb1_out, ++ user_via_cb1_oe_n, ++ user_via_cb2_in, ++ user_via_cb2_out, ++ user_via_cb2_oe_n, ++ user_via_pb_in, ++ user_via_pb_out, ++ user_via_pb_oe_n, ++ mhz1_clken, ++ reset_n, ++ mhz4_clken, ++ clock ++ ); ++ ++ -- Keyboard ++ keyb : keyboard port map ( ++ clock, hard_reset_n, mhz1_clken, ++ PS2_CLK, PS2_DAT, ++ keyb_enable_n, ++ keyb_column, ++ keyb_row, ++ keyb_out, ++ keyb_int, ++ keyb_break, ++ SW(7 downto 0) ++ ); ++ ++ -- Sound generator (and drive logic for I2S codec) ++ sound : sn76489_top port map ( ++ clock, mhz4_clken, ++ reset_n, '0', sound_enable_n, ++ sound_ready, sound_di, ++ sound_ao ++ ); ++ i2s : i2s_intf port map ( ++ CLOCK_24(0), reset_n, ++ pcm_inl, pcm_inr, ++ std_logic_vector(sound_ao) & "00000000", ++ std_logic_vector(sound_ao) & "00000000", ++ AUD_XCK, AUD_DACLRCK, ++ AUD_BCLK, AUD_DACDAT, AUD_ADCDAT ++ ); ++ i2c : i2c_loader ++ generic map ( ++ log2_divider => 7 ++ ) ++ port map ( ++ clock, reset_n, ++ I2C_SCLK, I2C_SDAT, ++ LEDR(5), -- IS_DONE ++ LEDR(4) -- IS_ERROR ++ ); ++ ++ -- Asynchronous reset ++ -- PLL is reset by external reset switch ++ pll_reset <= not SW(9); ++ -- Keyboard and System VIA are reset by external reset switch or PLL being out of lock ++ hard_reset_n <= not (pll_reset or not pll_locked); ++ -- Rest of system is reset by all of the above plus the keyboard BREAK key ++ reset_n <= hard_reset_n and not keyb_break; ++ ++ -- Clock enable generation - 32 MHz clock split into 32 cycles ++ -- CPU is on 0 and 16 (but can be masked by 1 MHz bus accesses) ++ -- Video is on all odd cycles (16 MHz) ++ -- 1 MHz cycles are on cycle 31 (1 MHz) ++ vid_clken <= clken_counter(0); -- 1,3,5... ++ mhz4_clken <= clken_counter(0) and clken_counter(1) and clken_counter(2); -- 7/15/23/31 ++ mhz2_clken <= mhz4_clken and clken_counter(3); -- 15/31 ++ mhz1_clken <= mhz2_clken and clken_counter(4); -- 31 ++ cpu_cycle <= not (clken_counter(0) or clken_counter(1) or clken_counter(2) or clken_counter(3)); -- 0/16 ++ cpu_clken <= cpu_cycle and not cpu_cycle_mask; ++ ++ clk_gen: process(clock,reset_n) ++ begin ++ if reset_n = '0' then ++ clken_counter <= (others => '0'); ++ elsif rising_edge(clock) then ++ clken_counter <= clken_counter + 1; ++ end if; ++ end process; ++ ++ cycle_stretch: process(clock,reset_n) ++ begin ++ if reset_n = '0' then ++ cpu_cycle_mask <= '0'; ++ elsif rising_edge(clock) and mhz2_clken = '1' then ++ if mhz1_enable = '1' and cpu_cycle_mask = '0' then ++ -- Block CPU cycles until 1 MHz cycle has completed ++ cpu_cycle_mask <= '1'; ++ end if; ++ if mhz1_clken = '1' then ++ -- CPU can run again ++ -- FIXME: This may not be correct in terms of CPU cycles, but it ++ -- should work ++ cpu_cycle_mask <= '0'; ++ end if; ++ end if; ++ end process; ++ ++ ttxt_clk_gen: process(CLOCK_24(0),reset_n) ++ begin ++ if reset_n = '0' then ++ ttxt_clken_counter <= (others => '0'); ++ elsif rising_edge(CLOCK_24(0)) then ++ ttxt_clken_counter <= ttxt_clken_counter + 1; ++ end if; ++ end process; ++ ++ -- 6 MHz clock enable for SAA5050 ++ ttxt_clken <= '1' when ttxt_clken_counter = 0 else '0'; ++ ++ -- CPU configuration and fixed signals ++ cpu_mode <= "00"; -- 6502 ++ cpu_ready <= '1'; ++ cpu_abort_n <= '1'; ++ cpu_nmi_n <= '1'; ++ cpu_so_n <= '1'; ++ ++ -- Address decoding ++ -- 0x0000 = 32 KB SRAM ++ -- 0x8000 = 16 KB BASIC/Sideways ROMs ++ -- 0xC000 = 16 KB MOS ROM ++ -- ++ -- IO regions are mapped into a hole in the MOS. There are three regions: ++ -- 0xFC00 = FRED ++ -- 0xFD00 = JIM ++ -- 0xFE00 = SHEILA ++ ram_enable <= not cpu_a(15); ++ rom_enable <= cpu_a(15) and not cpu_a(14); ++ mos_enable <= cpu_a(15) and cpu_a(14) and not (io_fred or io_jim or io_sheila); ++ io_fred <= '1' when cpu_a(15 downto 8) = "11111100" else '0'; ++ io_jim <= '1' when cpu_a(15 downto 8) = "11111101" else '0'; ++ io_sheila <= '1' when cpu_a(15 downto 8) = "11111110" else '0'; ++ -- The following IO regions are accessed at 1 MHz and hence will stall the ++ -- CPU accordingly ++ mhz1_enable <= io_fred or io_jim or ++ adc_enable or sys_via_enable or user_via_enable or ++ serproc_enable or acia_enable or crtc_enable; ++ ++ -- SHEILA address demux ++ -- All the system peripherals are mapped into this page as follows: ++ -- 0xFE00 - 0xFE07 = MC6845 CRTC ++ -- 0xFE08 - 0xFE0F = MC6850 ACIA (Serial/Tape) ++ -- 0xFE10 - 0xFE1F = Serial ULA ++ -- 0xFE20 - 0xFE2F = Video ULA ++ -- 0xFE30 - 0xFE3F = Paged ROM select latch ++ -- 0xFE40 - 0xFE5F = System VIA (6522) ++ -- 0xFE60 - 0xFE7F = User VIA (6522) ++ -- 0xFE80 - 0xFE9F = 8271 Floppy disc controller ++ -- 0xFEA0 - 0xFEBF = 68B54 ADLC for Econet ++ -- 0xFEC0 - 0xFEDF = uPD7002 ADC ++ -- 0xFEE0 - 0xFEFF = Tube ULA ++ process(cpu_a,io_sheila) ++ begin ++ -- All regions normally de-selected ++ crtc_enable <= '0'; ++ acia_enable <= '0'; ++ serproc_enable <= '0'; ++ vidproc_enable <= '0'; ++ romsel_enable <= '0'; ++ sys_via_enable <= '0'; ++ user_via_enable <= '0'; ++ fddc_enable <= '0'; ++ adlc_enable <= '0'; ++ adc_enable <= '0'; ++ tube_enable <= '0'; ++ ++ if io_sheila = '1' then ++ case cpu_a(7 downto 5) is ++ when "000" => ++ -- 0xFE00 ++ if cpu_a(4) = '0' then ++ if cpu_a(3) = '0' then ++ -- 0xFE00 ++ crtc_enable <= '1'; ++ else ++ -- 0xFE08 ++ acia_enable <= '1'; ++ end if; ++ else ++ -- 0xFE10 ++ serproc_enable <= '1'; ++ end if; ++ when "001" => ++ -- 0xFE20 ++ if cpu_a(4) = '0' then ++ -- 0xFE20 ++ vidproc_enable <= '1'; ++ else ++ -- 0xFE30 ++ romsel_enable <= '1'; ++ end if; ++ when "010" => sys_via_enable <= '1'; -- 0xFE40 ++ when "011" => user_via_enable <= '1'; -- 0xFE60 ++ when "100" => fddc_enable <= '1'; -- 0xFE80 ++ when "101" => adlc_enable <= '1'; -- 0xFEA0 ++ when "110" => adc_enable <= '1'; -- 0xFEC0 ++ when "111" => tube_enable <= '1'; -- 0xFEE0 ++ when others => ++ null; ++ end case; ++ end if; ++ end process; ++ ++ -- CPU data bus mux and interrupts ++ cpu_di <= ++ SRAM_DQ(7 downto 0) when ram_enable = '1' else ++ FL_DQ when rom_enable = '1' else ++ FL_DQ when mos_enable = '1' else ++ crtc_do when crtc_enable = '1' else ++ "00000010" when acia_enable = '1' else ++ sys_via_do when sys_via_enable = '1' else ++ user_via_do when user_via_enable = '1' else ++ (others => '0'); -- un-decoded locations are pulled down by RP1 ++ debug_irq_in_n <= sys_via_irq_n and user_via_irq_n; -- route IRQ through debugger ++ --cpu_irq_n <= sys_via_irq_n and user_via_irq_n; ++ ++ -- ROMs are in external flash and split into 16K slots (since this also suits other ++ -- computers that might be run on the same board). ++ -- The first 8 slots are allocated for use here, and the first 4 are decoded as ++ -- the sideways ROMs. Slot 7 is used for the MOS. ++ FL_RST_N <= reset_n; ++ FL_CE_N <= '0'; ++ FL_OE_N <= '0'; ++ FL_WE_N <= '1'; ++ FL_ADDR(21 downto 17) <= ROM_OFFSET(7 downto 3); ++ FL_ADDR(16 downto 14) <= ++ "111" when mos_enable = '1' else ++ "0" & romsel(1 downto 0); ++ FL_ADDR(13 downto 0) <= cpu_a(13 downto 0); ++ ++ -- SRAM bus ++ SRAM_UB_N <= '1'; ++ SRAM_LB_N <= '0'; ++ SRAM_CE_N <= '0'; ++ SRAM_OE_N <= '0'; ++ SRAM_DQ(15 downto 8) <= (others => '0'); ++ ++ -- Synchronous outputs to SRAM ++ process(clock,reset_n) ++ variable ram_write : std_logic; ++ begin ++ ram_write := ram_enable and not cpu_r_nw; ++ ++ if reset_n = '0' then ++ SRAM_WE_N <= '1'; ++ SRAM_DQ(7 downto 0) <= (others => 'Z'); ++ elsif rising_edge(clock) then ++ -- Default to inputs ++ SRAM_DQ(7 downto 0) <= (others => 'Z'); ++ ++ -- Register SRAM signals to outputs (clock must be at least 2x CPU clock) ++ if vid_clken = '1' then ++ -- Fetch data from previous CPU cycle ++ SRAM_WE_N <= not ram_write; ++ SRAM_ADDR <= "00" & cpu_a(15 downto 0); ++ if ram_write = '1' then ++ SRAM_DQ(7 downto 0) <= cpu_do; ++ end if; ++ else ++ -- Fetch data from previous display cycle ++ SRAM_WE_N <= '1'; ++ SRAM_ADDR <= "000" & display_a; ++ end if; ++ end if; ++ end process; ++ ++ -- Address translation logic for calculation of display address ++ process(crtc_ma,crtc_ra,disp_addr_offs) ++ variable aa : unsigned(3 downto 0); ++ begin ++ if crtc_ma(12) = '0' then ++ -- No adjustment ++ aa := unsigned(crtc_ma(11 downto 8)); ++ else ++ -- Address adjusted according to screen mode to compensate for ++ -- wrap at 0x8000. ++ case disp_addr_offs is ++ when "00" => ++ -- Mode 3 - restart at 0x4000 ++ aa := unsigned(crtc_ma(11 downto 8)) + 8; ++ when "01" => ++ -- Mode 6 - restart at 0x6000 ++ aa := unsigned(crtc_ma(11 downto 8)) + 12; ++ when "10" => ++ -- Mode 0,1,2 - restart at 0x3000 ++ aa := unsigned(crtc_ma(11 downto 8)) + 6; ++ when "11" => ++ -- Mode 4,5 - restart at 0x5800 ++ aa := unsigned(crtc_ma(11 downto 8)) + 11; ++ when others => ++ null; ++ end case; ++ end if; ++ ++ if crtc_ma(13) = '0' then ++ -- HI RES ++ display_a <= std_logic_vector(aa(3 downto 0)) & crtc_ma(7 downto 0) & crtc_ra(2 downto 0); ++ else ++ -- TTX VDU ++ display_a <= std_logic(aa(3)) & "1111" & crtc_ma(9 downto 0); ++ end if; ++ end process; ++ ++ -- VIDPROC ++ vidproc_invert_n <= '1'; ++ vidproc_disen <= crtc_de and not crtc_ra(3); -- DISEN is masked off by RA(3) for MODEs 3 and 6 ++ r_in <= ttxt_r; ++ g_in <= ttxt_g; ++ b_in <= ttxt_b; ++ ++ -- SAA5050 ++ ttxt_glr <= not crtc_hsync; ++ ttxt_dew <= crtc_vsync; ++ ttxt_crs <= not crtc_ra(0); ++ ttxt_lose <= crtc_de; ++ ++ -- CRTC drives video out (CSYNC on HSYNC output, VSYNC high) ++ VGA_HS <= not (crtc_hsync xor crtc_vsync); ++ VGA_VS <= '1'; ++ VGA_R <= r_out & r_out & r_out & r_out; ++ VGA_G <= g_out & g_out & g_out & g_out; ++ VGA_B <= b_out & b_out & b_out & b_out; ++ ++ -- Connections to System VIA ++ -- ADC ++ sys_via_cb1_in <= '1'; -- /EOC ++ -- CRTC ++ sys_via_ca1_in <= crtc_vsync; ++ sys_via_cb2_in <= crtc_lpstb; ++ -- Keyboard ++ sys_via_ca2_in <= keyb_int; ++ sys_via_pa_in(7) <= keyb_out; ++ sys_via_pa_in(6 downto 0) <= sys_via_pa_out(6 downto 0); -- Must loop back output pins or keyboard won't work ++ keyb_column <= sys_via_pa_out(3 downto 0); ++ keyb_row <= sys_via_pa_out(6 downto 4); ++ -- Sound ++ sound_di <= sys_via_pa_out; ++ -- Others (idle until missing bits implemented) ++ sys_via_pb_in(7 downto 4) <= (others => '1'); ++ ++ -- Connections to User VIA (user port is output on green LEDs) ++ user_via_ca1_in <= '1'; -- Pulled up ++ --LEDG <= user_via_pb_out; ++ ++ -- MMBEEB ++ user_via_cb1_in <= user_via_pb_out(1); ++ SD_SCLK <= user_via_pb_out(1); -- SCLK ++ SD_MOSI <= user_via_pb_out(0); -- SDO ++ SD_nCS <= '0'; -- CS ++ user_via_cb2_in <= SD_MISO; -- SDI ++ user_via_pb_in <= user_via_pb_out; ++ ++ -- ROM select latch ++ process(clock,reset_n) ++ begin ++ if reset_n = '0' then ++ romsel <= (others => '0'); ++ elsif rising_edge(clock) then ++ if romsel_enable = '1' and cpu_r_nw = '0' then ++ romsel <= cpu_do(3 downto 0); ++ end if; ++ end if; ++ end process; ++ ++ -- IC32 latch ++ sound_enable_n <= ic32(0); ++ speech_write_n <= ic32(1); ++ speech_read_n <= ic32(2); ++ keyb_enable_n <= ic32(3); ++ disp_addr_offs <= ic32(5 downto 4); ++ caps_lock_led_n <= ic32(6); ++ shift_lock_led_n <= ic32(7); ++ ++ process(clock,reset_n) ++ variable bit_num : integer; ++ begin ++ bit_num := to_integer(unsigned(sys_via_pb_out(2 downto 0))); ++ ++ if reset_n = '0' then ++ ic32 <= (others => '0'); ++ elsif rising_edge(clock) then ++ ic32(bit_num) <= sys_via_pb_out(3); ++ end if; ++ end process; ++ ++ -- Keyboard LEDs ++ LEDR(0) <= not caps_lock_led_n; ++ LEDR(1) <= not shift_lock_led_n; ++ ++ ----------------- ++ -- DEBUG STUFF ++ ----------------- ++ ++ GPIO_0(0) <= not (crtc_hsync xor crtc_vsync); ++ GPIO_0(1) <= crtc_de; ++ ++end architecture; +diff --git a/bbc_micro_de1_tb.vhd b/bbc_micro_de1_tb.vhd +index 82012ec..9197958 100644 +--- a/bbc_micro_de1_tb.vhd ++++ b/bbc_micro_de1_tb.vhd +@@ -1,299 +1,299 @@ +--- BBC Micro for Altera DE1
+---
+--- Copyright (c) 2011 Mike Stirling
+---
+--- 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 agreement from the author.
+---
+--- * License is granted for non-commercial use only. A fee may not be charged
+--- for redistributions as source code or in synthesized/hardware form without
+--- specific prior written agreement from the author.
+---
+--- 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.
+---
+-
+-library IEEE;
+-use IEEE.STD_LOGIC_1164.ALL;
+-use IEEE.NUMERIC_STD.ALL;
+-
+-entity bbc_micro_tb is
+-end entity;
+-
+-architecture tb of bbc_micro_tb is
+-component bbc_micro_de1 is
+-port (
+- -- Clocks
+- CLOCK_24 : in std_logic_vector(1 downto 0);
+- CLOCK_27 : in std_logic_vector(1 downto 0);
+- CLOCK_50 : in std_logic;
+- EXT_CLOCK : in std_logic;
+-
+- -- Switches
+- SW : in std_logic_vector(9 downto 0);
+- -- Buttons
+- KEY : in std_logic_vector(3 downto 0);
+-
+- -- 7 segment displays
+- HEX0 : out std_logic_vector(6 downto 0);
+- HEX1 : out std_logic_vector(6 downto 0);
+- HEX2 : out std_logic_vector(6 downto 0);
+- HEX3 : out std_logic_vector(6 downto 0);
+- -- Red LEDs
+- LEDR : out std_logic_vector(9 downto 0);
+- -- Green LEDs
+- LEDG : out std_logic_vector(7 downto 0);
+-
+- -- VGA
+- VGA_R : out std_logic_vector(3 downto 0);
+- VGA_G : out std_logic_vector(3 downto 0);
+- VGA_B : out std_logic_vector(3 downto 0);
+- VGA_HS : out std_logic;
+- VGA_VS : out std_logic;
+-
+- -- Serial
+- UART_RXD : in std_logic;
+- UART_TXD : out std_logic;
+-
+- -- PS/2 Keyboard
+- PS2_CLK : inout std_logic;
+- PS2_DAT : inout std_logic;
+-
+- -- I2C
+- I2C_SCLK : inout std_logic;
+- I2C_SDAT : inout std_logic;
+-
+- -- Audio
+- AUD_XCK : out std_logic;
+- AUD_BCLK : out std_logic;
+- AUD_ADCLRCK : out std_logic;
+- AUD_ADCDAT : in std_logic;
+- AUD_DACLRCK : out std_logic;
+- AUD_DACDAT : out std_logic;
+-
+- -- SRAM
+- SRAM_ADDR : out std_logic_vector(17 downto 0);
+- SRAM_DQ : inout std_logic_vector(15 downto 0);
+- SRAM_CE_N : out std_logic;
+- SRAM_OE_N : out std_logic;
+- SRAM_WE_N : out std_logic;
+- SRAM_UB_N : out std_logic;
+- SRAM_LB_N : out std_logic;
+-
+- -- SDRAM
+- DRAM_ADDR : out std_logic_vector(11 downto 0);
+- DRAM_DQ : inout std_logic_vector(15 downto 0);
+- DRAM_BA_0 : in std_logic;
+- DRAM_BA_1 : in std_logic;
+- DRAM_CAS_N : in std_logic;
+- DRAM_CKE : in std_logic;
+- DRAM_CLK : in std_logic;
+- DRAM_CS_N : in std_logic;
+- DRAM_LDQM : in std_logic;
+- DRAM_RAS_N : in std_logic;
+- DRAM_UDQM : in std_logic;
+- DRAM_WE_N : in std_logic;
+-
+- -- Flash
+- FL_ADDR : out std_logic_vector(21 downto 0);
+- FL_DQ : inout std_logic_vector(7 downto 0);
+- FL_RST_N : in std_logic;
+- FL_OE_N : in std_logic;
+- FL_WE_N : in std_logic;
+-
+- -- GPIO
+- GPIO_0 : inout std_logic_vector(35 downto 0);
+- GPIO_1 : inout std_logic_vector(35 downto 0)
+- );
+-end component;
+-
+-
+-signal clock_24 : std_logic_vector(1 downto 0) := "00";
+-signal clock_27 : std_logic_vector(1 downto 0) := "00";
+-signal clock_50 : std_logic := '0';
+-signal ext_clock : std_logic := '0';
+-signal sw : std_logic_vector(9 downto 0);
+-signal key : std_logic_vector(3 downto 0);
+-signal hex0 : std_logic_vector(6 downto 0);
+-signal hex1 : std_logic_vector(6 downto 0);
+-signal hex2 : std_logic_vector(6 downto 0);
+-signal hex3 : std_logic_vector(6 downto 0);
+-signal ledr : std_logic_vector(9 downto 0);
+-signal ledg : std_logic_vector(7 downto 0);
+-signal vga_r : std_logic_vector(3 downto 0);
+-signal vga_g : std_logic_vector(3 downto 0);
+-signal vga_b : std_logic_vector(3 downto 0);
+-signal vga_hs : std_logic;
+-signal vga_vs : std_logic;
+-signal uart_rxd : std_logic;
+-signal uart_txd : std_logic;
+-signal ps2_clk : std_logic;
+-signal ps2_dat : std_logic;
+-signal i2c_sclk : std_logic;
+-signal i2c_sdat : std_logic;
+-signal aud_xck : std_logic;
+-signal aud_bclk : std_logic;
+-signal aud_adclrck : std_logic;
+-signal aud_adcdat : std_logic;
+-signal aud_daclrck : std_logic;
+-signal aud_dacdat : std_logic;
+-signal sram_addr : std_logic_vector(17 downto 0);
+-signal sram_dq : std_logic_vector(15 downto 0);
+-signal sram_ce_n : std_logic;
+-signal sram_oe_n : std_logic;
+-signal sram_we_n : std_logic;
+-signal sram_ub_n : std_logic;
+-signal sram_lb_n : std_logic;
+-signal dram_addr : std_logic_vector(11 downto 0);
+-signal dram_dq : std_logic_vector(15 downto 0);
+-signal dram_ba_0 : std_logic;
+-signal dram_ba_1 : std_logic;
+-signal dram_cas_n : std_logic;
+-signal dram_cke : std_logic;
+-signal dram_clk : std_logic;
+-signal dram_cs_n : std_logic;
+-signal dram_ldqm : std_logic;
+-signal dram_ras_n : std_logic;
+-signal dram_udqm : std_logic;
+-signal dram_we_n : std_logic;
+-signal fl_addr : std_logic_vector(21 downto 0);
+-signal fl_dq : std_logic_vector(7 downto 0);
+-signal fl_rst_n : std_logic;
+-signal fl_oe_n : std_logic;
+-signal fl_we_n : std_logic;
+-signal gpio_0 : std_logic_vector(35 downto 0);
+-signal gpio_1 : std_logic_vector(35 downto 0);
+-
+-signal n_reset : std_logic := '0';
+-signal n_slow : std_logic := '1';
+-
+-type ram_t is array(0 to 65535) of std_logic_vector(15 downto 0);
+-signal ram : ram_t;
+-signal ram_a : std_logic_vector(15 downto 0);
+-begin
+-
+- uut: bbc_micro_de1 port map (
+- clock_24,
+- clock_27,
+- clock_50,
+- ext_clock,
+- sw,
+- key,
+- hex0,
+- hex1,
+- hex2,
+- hex3,
+- ledr,
+- ledg,
+- vga_r,
+- vga_g,
+- vga_b,
+- vga_hs,
+- vga_vs,
+- uart_rxd,
+- uart_txd,
+- ps2_clk,
+- ps2_dat,
+- i2c_sclk,
+- i2c_sdat,
+- aud_xck,
+- aud_bclk,
+- aud_adclrck,
+- aud_adcdat,
+- aud_daclrck,
+- aud_dacdat,
+- sram_addr,
+- sram_dq,
+- sram_ce_n,
+- sram_oe_n,
+- sram_we_n,
+- sram_ub_n,
+- sram_lb_n,
+- dram_addr,
+- dram_dq,
+- dram_ba_0,
+- dram_ba_1,
+- dram_cas_n,
+- dram_cke,
+- dram_clk,
+- dram_cs_n,
+- dram_ldqm,
+- dram_ras_n,
+- dram_udqm,
+- dram_we_n,
+- fl_addr,
+- fl_dq,
+- fl_rst_n,
+- fl_oe_n,
+- fl_we_n,
+- gpio_0,
+- gpio_1
+- );
+-
+- sw <= n_reset & n_slow & "00000101";
+- clock_50 <= not clock_50 after 10 ns;
+- clock_27(0) <= not clock_27(0) after 18.5 ns;
+- clock_27(1) <= not clock_27(1) after 18.5 ns;
+- clock_24(0) <= not clock_24(0) after 20.8 ns;
+- clock_24(1) <= not clock_24(1) after 20.8 ns;
+-
+- reset: process
+- begin
+- wait for 100 ns;
+- n_reset <= '1';
+- end process;
+-
+- sram: process(sram_addr,sram_dq,sram_ce_n,sram_oe_n,sram_we_n,sram_ub_n,sram_lb_n)
+- begin
+- if sram_ce_n = '0' then
+- if sram_oe_n = '0' and sram_we_n = '1' then
+- if sram_ub_n = '0' then
+- sram_dq(15 downto 8) <= ram(to_integer(unsigned(sram_addr(15 downto 0))))(15 downto 8);
+- else
+- sram_dq(15 downto 8) <= (others => 'Z');
+- end if;
+- if sram_lb_n = '0' then
+- sram_dq(7 downto 0) <= ram(to_integer(unsigned(sram_addr(15 downto 0))))(7 downto 0);
+- else
+- sram_dq(7 downto 0) <= (others => 'Z');
+- end if;
+- else
+- sram_dq(15 downto 0) <= (others => 'Z');
+- if sram_we_n = '0' then
+- if sram_ub_n = '0' then
+- ram(to_integer(unsigned(sram_addr(15 downto 0))))(15 downto 8) <= sram_dq(15 downto 8);
+- end if;
+- if sram_lb_n = '0' then
+- ram(to_integer(unsigned(sram_addr(15 downto 0))))(7 downto 0) <= sram_dq(7 downto 0);
+- end if;
+- end if;
+- end if;
+- else
+- sram_dq <= (others => 'Z');
+- end if;
+- end process;
+-
+-
+-end architecture;
++-- BBC Micro for Altera DE1 ++-- ++-- Copyright (c) 2011 Mike Stirling ++-- ++-- 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 agreement from the author. ++-- ++-- * License is granted for non-commercial use only. A fee may not be charged ++-- for redistributions as source code or in synthesized/hardware form without ++-- specific prior written agreement from the author. ++-- ++-- 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. ++-- ++ ++library IEEE; ++use IEEE.STD_LOGIC_1164.ALL; ++use IEEE.NUMERIC_STD.ALL; ++ ++entity bbc_micro_tb is ++end entity; ++ ++architecture tb of bbc_micro_tb is ++component bbc_micro_de1 is ++port ( ++ -- Clocks ++ CLOCK_24 : in std_logic_vector(1 downto 0); ++ CLOCK_27 : in std_logic_vector(1 downto 0); ++ CLOCK_50 : in std_logic; ++ EXT_CLOCK : in std_logic; ++ ++ -- Switches ++ SW : in std_logic_vector(9 downto 0); ++ -- Buttons ++ KEY : in std_logic_vector(3 downto 0); ++ ++ -- 7 segment displays ++ HEX0 : out std_logic_vector(6 downto 0); ++ HEX1 : out std_logic_vector(6 downto 0); ++ HEX2 : out std_logic_vector(6 downto 0); ++ HEX3 : out std_logic_vector(6 downto 0); ++ -- Red LEDs ++ LEDR : out std_logic_vector(9 downto 0); ++ -- Green LEDs ++ LEDG : out std_logic_vector(7 downto 0); ++ ++ -- VGA ++ VGA_R : out std_logic_vector(3 downto 0); ++ VGA_G : out std_logic_vector(3 downto 0); ++ VGA_B : out std_logic_vector(3 downto 0); ++ VGA_HS : out std_logic; ++ VGA_VS : out std_logic; ++ ++ -- Serial ++ UART_RXD : in std_logic; ++ UART_TXD : out std_logic; ++ ++ -- PS/2 Keyboard ++ PS2_CLK : inout std_logic; ++ PS2_DAT : inout std_logic; ++ ++ -- I2C ++ I2C_SCLK : inout std_logic; ++ I2C_SDAT : inout std_logic; ++ ++ -- Audio ++ AUD_XCK : out std_logic; ++ AUD_BCLK : out std_logic; ++ AUD_ADCLRCK : out std_logic; ++ AUD_ADCDAT : in std_logic; ++ AUD_DACLRCK : out std_logic; ++ AUD_DACDAT : out std_logic; ++ ++ -- SRAM ++ SRAM_ADDR : out std_logic_vector(17 downto 0); ++ SRAM_DQ : inout std_logic_vector(15 downto 0); ++ SRAM_CE_N : out std_logic; ++ SRAM_OE_N : out std_logic; ++ SRAM_WE_N : out std_logic; ++ SRAM_UB_N : out std_logic; ++ SRAM_LB_N : out std_logic; ++ ++ -- SDRAM ++ DRAM_ADDR : out std_logic_vector(11 downto 0); ++ DRAM_DQ : inout std_logic_vector(15 downto 0); ++ DRAM_BA_0 : in std_logic; ++ DRAM_BA_1 : in std_logic; ++ DRAM_CAS_N : in std_logic; ++ DRAM_CKE : in std_logic; ++ DRAM_CLK : in std_logic; ++ DRAM_CS_N : in std_logic; ++ DRAM_LDQM : in std_logic; ++ DRAM_RAS_N : in std_logic; ++ DRAM_UDQM : in std_logic; ++ DRAM_WE_N : in std_logic; ++ ++ -- Flash ++ FL_ADDR : out std_logic_vector(21 downto 0); ++ FL_DQ : inout std_logic_vector(7 downto 0); ++ FL_RST_N : in std_logic; ++ FL_OE_N : in std_logic; ++ FL_WE_N : in std_logic; ++ ++ -- GPIO ++ GPIO_0 : inout std_logic_vector(35 downto 0); ++ GPIO_1 : inout std_logic_vector(35 downto 0) ++ ); ++end component; ++ ++ ++signal clock_24 : std_logic_vector(1 downto 0) := "00"; ++signal clock_27 : std_logic_vector(1 downto 0) := "00"; ++signal clock_50 : std_logic := '0'; ++signal ext_clock : std_logic := '0'; ++signal sw : std_logic_vector(9 downto 0); ++signal key : std_logic_vector(3 downto 0); ++signal hex0 : std_logic_vector(6 downto 0); ++signal hex1 : std_logic_vector(6 downto 0); ++signal hex2 : std_logic_vector(6 downto 0); ++signal hex3 : std_logic_vector(6 downto 0); ++signal ledr : std_logic_vector(9 downto 0); ++signal ledg : std_logic_vector(7 downto 0); ++signal vga_r : std_logic_vector(3 downto 0); ++signal vga_g : std_logic_vector(3 downto 0); ++signal vga_b : std_logic_vector(3 downto 0); ++signal vga_hs : std_logic; ++signal vga_vs : std_logic; ++signal uart_rxd : std_logic; ++signal uart_txd : std_logic; ++signal ps2_clk : std_logic; ++signal ps2_dat : std_logic; ++signal i2c_sclk : std_logic; ++signal i2c_sdat : std_logic; ++signal aud_xck : std_logic; ++signal aud_bclk : std_logic; ++signal aud_adclrck : std_logic; ++signal aud_adcdat : std_logic; ++signal aud_daclrck : std_logic; ++signal aud_dacdat : std_logic; ++signal sram_addr : std_logic_vector(17 downto 0); ++signal sram_dq : std_logic_vector(15 downto 0); ++signal sram_ce_n : std_logic; ++signal sram_oe_n : std_logic; ++signal sram_we_n : std_logic; ++signal sram_ub_n : std_logic; ++signal sram_lb_n : std_logic; ++signal dram_addr : std_logic_vector(11 downto 0); ++signal dram_dq : std_logic_vector(15 downto 0); ++signal dram_ba_0 : std_logic; ++signal dram_ba_1 : std_logic; ++signal dram_cas_n : std_logic; ++signal dram_cke : std_logic; ++signal dram_clk : std_logic; ++signal dram_cs_n : std_logic; ++signal dram_ldqm : std_logic; ++signal dram_ras_n : std_logic; ++signal dram_udqm : std_logic; ++signal dram_we_n : std_logic; ++signal fl_addr : std_logic_vector(21 downto 0); ++signal fl_dq : std_logic_vector(7 downto 0); ++signal fl_rst_n : std_logic; ++signal fl_oe_n : std_logic; ++signal fl_we_n : std_logic; ++signal gpio_0 : std_logic_vector(35 downto 0); ++signal gpio_1 : std_logic_vector(35 downto 0); ++ ++signal n_reset : std_logic := '0'; ++signal n_slow : std_logic := '1'; ++ ++type ram_t is array(0 to 65535) of std_logic_vector(15 downto 0); ++signal ram : ram_t; ++signal ram_a : std_logic_vector(15 downto 0); ++begin ++ ++ uut: bbc_micro_de1 port map ( ++ clock_24, ++ clock_27, ++ clock_50, ++ ext_clock, ++ sw, ++ key, ++ hex0, ++ hex1, ++ hex2, ++ hex3, ++ ledr, ++ ledg, ++ vga_r, ++ vga_g, ++ vga_b, ++ vga_hs, ++ vga_vs, ++ uart_rxd, ++ uart_txd, ++ ps2_clk, ++ ps2_dat, ++ i2c_sclk, ++ i2c_sdat, ++ aud_xck, ++ aud_bclk, ++ aud_adclrck, ++ aud_adcdat, ++ aud_daclrck, ++ aud_dacdat, ++ sram_addr, ++ sram_dq, ++ sram_ce_n, ++ sram_oe_n, ++ sram_we_n, ++ sram_ub_n, ++ sram_lb_n, ++ dram_addr, ++ dram_dq, ++ dram_ba_0, ++ dram_ba_1, ++ dram_cas_n, ++ dram_cke, ++ dram_clk, ++ dram_cs_n, ++ dram_ldqm, ++ dram_ras_n, ++ dram_udqm, ++ dram_we_n, ++ fl_addr, ++ fl_dq, ++ fl_rst_n, ++ fl_oe_n, ++ fl_we_n, ++ gpio_0, ++ gpio_1 ++ ); ++ ++ sw <= n_reset & n_slow & "00000101"; ++ clock_50 <= not clock_50 after 10 ns; ++ clock_27(0) <= not clock_27(0) after 18.5 ns; ++ clock_27(1) <= not clock_27(1) after 18.5 ns; ++ clock_24(0) <= not clock_24(0) after 20.8 ns; ++ clock_24(1) <= not clock_24(1) after 20.8 ns; ++ ++ reset: process ++ begin ++ wait for 100 ns; ++ n_reset <= '1'; ++ end process; ++ ++ sram: process(sram_addr,sram_dq,sram_ce_n,sram_oe_n,sram_we_n,sram_ub_n,sram_lb_n) ++ begin ++ if sram_ce_n = '0' then ++ if sram_oe_n = '0' and sram_we_n = '1' then ++ if sram_ub_n = '0' then ++ sram_dq(15 downto 8) <= ram(to_integer(unsigned(sram_addr(15 downto 0))))(15 downto 8); ++ else ++ sram_dq(15 downto 8) <= (others => 'Z'); ++ end if; ++ if sram_lb_n = '0' then ++ sram_dq(7 downto 0) <= ram(to_integer(unsigned(sram_addr(15 downto 0))))(7 downto 0); ++ else ++ sram_dq(7 downto 0) <= (others => 'Z'); ++ end if; ++ else ++ sram_dq(15 downto 0) <= (others => 'Z'); ++ if sram_we_n = '0' then ++ if sram_ub_n = '0' then ++ ram(to_integer(unsigned(sram_addr(15 downto 0))))(15 downto 8) <= sram_dq(15 downto 8); ++ end if; ++ if sram_lb_n = '0' then ++ ram(to_integer(unsigned(sram_addr(15 downto 0))))(7 downto 0) <= sram_dq(7 downto 0); ++ end if; ++ end if; ++ end if; ++ else ++ sram_dq <= (others => 'Z'); ++ end if; ++ end process; ++ ++ ++end architecture; +diff --git a/debugger.vhd b/debugger.vhd +index 1d78bd5..a7a9d7d 100644 +--- a/debugger.vhd ++++ b/debugger.vhd +@@ -1,300 +1,300 @@ +--- BBC Micro for Altera DE1
+---
+--- Copyright (c) 2011 Mike Stirling
+---
+--- 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 agreement from the author.
+---
+--- * License is granted for non-commercial use only. A fee may not be charged
+--- for redistributions as source code or in synthesized/hardware form without
+--- specific prior written agreement from the author.
+---
+--- 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.
+---
+---
+--- General purpose hardware debugger
+---
+--- (C) 2011 Mike Stirling
+---
+-
+-library IEEE;
+-use IEEE.STD_LOGIC_1164.ALL;
+-use IEEE.NUMERIC_STD.ALL;
+-
+-entity debugger is
+-generic (
+- -- Set this for a reasonable half flash duration relative to the
+- -- clock frequency
+- flash_divider : natural := 24
+- );
+-port (
+- CLOCK : in std_logic;
+- nRESET : in std_logic;
+- -- CPU clock enable in
+- CLKEN_IN : in std_logic;
+- -- Gated clock enable back out to CPU
+- CLKEN_OUT : out std_logic;
+- -- CPU IRQ in
+- nIRQ_IN : in std_logic;
+- -- Gated IRQ back out to CPU (no interrupts when single stepping)
+- nIRQ_OUT : out std_logic;
+-
+- -- CPU
+- A_CPU : in std_logic_vector(15 downto 0);
+- R_nW : in std_logic;
+- SYNC : in std_logic;
+-
+- -- Aux bus input for display in hex
+- AUX_BUS : in std_logic_vector(15 downto 0);
+-
+- -- Controls
+- -- RUN or HALT CPU
+- RUN : in std_logic;
+- -- Push button to single-step in HALT mode
+- nSTEP : in std_logic;
+- -- Push button to cycle display mode
+- nMODE : in std_logic;
+- -- Push button to cycle display digit in edit mode
+- nDIGIT : in std_logic;
+- -- Push button to cycle digit value in edit mode
+- nSET : in std_logic;
+-
+- -- Output to display
+- DIGIT3 : out std_logic_vector(6 downto 0);
+- DIGIT2 : out std_logic_vector(6 downto 0);
+- DIGIT1 : out std_logic_vector(6 downto 0);
+- DIGIT0 : out std_logic_vector(6 downto 0);
+-
+- LED_BREAKPOINT : out std_logic;
+- LED_WATCHPOINT : out std_logic
+- );
+-end entity;
+-
+-architecture rtl of debugger is
+-
+-component seg7 is
+-port (
+- D : in std_logic_vector(3 downto 0);
+- Q : out std_logic_vector(6 downto 0)
+-);
+-end component;
+-
+--- Current display mode
+-type mode_t is (modeAddress,modeBreak,modeWatch,modeAux);
+-signal mode : mode_t;
+--- Current edit digit
+-signal digit : unsigned(1 downto 0);
+--- For flashing selected digit
+-signal counter : unsigned(flash_divider-1 downto 0);
+-signal flash : std_logic;
+--- Selected breakpoint address (stop on instruction fetch)
+-signal breakpoint : std_logic_vector(15 downto 0);
+--- Selected watchpoint address (stop on write)
+-signal watchpoint : std_logic_vector(15 downto 0);
+--- Address of last instruction fetch
+-signal instr_addr : std_logic_vector(15 downto 0);
+--- Break flags
+-signal halt : std_logic;
+--- Set when a request to resume has been received but before
+--- the CPU has run
+-signal resuming : std_logic;
+-
+--- Display interface
+-signal a_display : std_logic_vector(15 downto 0);
+-signal d3_display : std_logic_vector(6 downto 0);
+-signal d2_display : std_logic_vector(6 downto 0);
+-signal d1_display : std_logic_vector(6 downto 0);
+-signal d0_display : std_logic_vector(6 downto 0);
+-
+--- Registered button inputs
+-signal r_step_n : std_logic;
+-signal r_mode_n : std_logic;
+-signal r_digit_n : std_logic;
+-signal r_set_n : std_logic;
+-
+-begin
+- -- Mask CPU clock enable
+- CLKEN_OUT <= CLKEN_IN and not halt;
+- -- Mask interrupt
+- nIRQ_OUT <= nIRQ_IN or not RUN;
+-
+- -- Route selected address to display
+- a_display <= instr_addr when mode = modeAddress else
+- breakpoint when mode = modeBreak else
+- watchpoint when mode = modeWatch else
+- AUX_BUS when mode = modeAux else
+- (others => '0');
+-
+- -- Generate display digits from binary
+- d3 : seg7 port map (a_display(15 downto 12),d3_display);
+- d2 : seg7 port map (a_display(11 downto 8),d2_display);
+- d1 : seg7 port map (a_display(7 downto 4),d1_display);
+- d0 : seg7 port map (a_display(3 downto 0),d0_display);
+-
+- -- Flash selected digit in edit modes
+- DIGIT3 <= d3_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "11") else "1111111";
+- DIGIT2 <= d2_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "10") else "1111111";
+- DIGIT1 <= d1_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "01") else "1111111";
+- DIGIT0 <= d0_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "00") else "1111111";
+-
+- -- Show mode on LEDs
+- LED_BREAKPOINT <= '1' when mode = modeBreak or mode = modeAux else '0';
+- LED_WATCHPOINT <= '1' when mode = modeWatch or mode = modeAux else '0';
+-
+- -- Flash counter
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- counter <= (others => '0');
+- flash <= '0';
+- elsif rising_edge(CLOCK) then
+- counter <= counter + 1;
+- if counter = 0 then
+- flash <= not flash;
+- end if;
+- end if;
+- end process;
+-
+- -- Register buttons, select input mode and digit
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- r_mode_n <= '1';
+- r_digit_n <= '1';
+- r_set_n <= '1';
+- mode <= modeAddress;
+- digit <= (others => '0');
+- elsif rising_edge(CLOCK) then
+- -- Register buttons
+- r_mode_n <= nMODE;
+- r_digit_n <= nDIGIT;
+- r_set_n <= nSET;
+-
+- if r_mode_n = '1' and nMODE = '0' then
+- -- Increment mode
+- if mode = modeAddress then
+- mode <= modeBreak;
+- elsif mode = modeBreak then
+- mode <= modeWatch;
+- elsif mode = modeWatch then
+- mode <= modeAux;
+- else
+- mode <= modeAddress;
+- end if;
+- end if;
+- if r_digit_n = '1' and nDIGIT = '0' then
+- -- Increment digit
+- digit <= digit + 1;
+- end if;
+- end if;
+- end process;
+-
+- -- Set watchpoint address
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- watchpoint <= (others => '1');
+- elsif rising_edge(CLOCK) and mode = modeWatch then
+- if r_set_n = '1' and nSET = '0' then
+- -- Increment selected digit on each button press
+- case digit is
+- when "00" => watchpoint(3 downto 0) <= std_logic_vector(unsigned(watchpoint(3 downto 0)) + 1);
+- when "01" => watchpoint(7 downto 4) <= std_logic_vector(unsigned(watchpoint(7 downto 4)) + 1);
+- when "10" => watchpoint(11 downto 8) <= std_logic_vector(unsigned(watchpoint(11 downto 8)) + 1);
+- when "11" => watchpoint(15 downto 12) <= std_logic_vector(unsigned(watchpoint(15 downto 12)) + 1);
+- when others => null;
+- end case;
+- end if;
+- end if;
+- end process;
+-
+- -- Set breakpoint address
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- breakpoint <= (others => '1');
+- elsif rising_edge(CLOCK) and mode = modeBreak then
+- if r_set_n = '1' and nSET = '0' then
+- -- Increment selected digit on each button press
+- case digit is
+- when "00" => breakpoint(3 downto 0) <= std_logic_vector(unsigned(breakpoint(3 downto 0)) + 1);
+- when "01" => breakpoint(7 downto 4) <= std_logic_vector(unsigned(breakpoint(7 downto 4)) + 1);
+- when "10" => breakpoint(11 downto 8) <= std_logic_vector(unsigned(breakpoint(11 downto 8)) + 1);
+- when "11" => breakpoint(15 downto 12) <= std_logic_vector(unsigned(breakpoint(15 downto 12)) + 1);
+-
+- when others => null;
+- end case;
+- end if;
+- end if;
+- end process;
+-
+- -- CPU control logic
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- r_step_n <= '1';
+- halt <= '0';
+- resuming <= '0';
+- instr_addr <= (others => '0');
+- elsif rising_edge(CLOCK) then
+- -- Register single-step button
+- r_step_n <= nSTEP;
+-
+- -- Once the CPU has run we can trigger a new halt
+- if CLKEN_IN = '1' then
+- resuming <= '0';
+- end if;
+-
+- if SYNC = '1' then
+- -- Latch address of instruction fetch
+- instr_addr <= A_CPU;
+- end if;
+-
+- -- Check for halt conditions if we are not resuming from a previous halt
+- if resuming = '0' then
+- if RUN = '0' and SYNC = '1' then
+- -- If not in RUN mode then halt on any instruction fetch
+- -- (single-step)
+- halt <= '1';
+- end if;
+- if A_CPU = breakpoint and SYNC = '1' then
+- -- Halt CPU when instruction fetched from breakpoint address
+- halt <= '1';
+- end if;
+- if A_CPU = watchpoint and SYNC = '0' and R_nW = '0' then
+- -- Halt CPU when data write to watchpoint address
+- halt <= '1';
+- end if;
+- end if;
+-
+- -- Resume or single step when user presses "STEP" button
+- if r_step_n = '1' and nSTEP = '0' then
+- resuming <= '1';
+- halt <= '0';
+- end if;
+- end if;
+- end process;
+-end architecture;
++-- BBC Micro for Altera DE1 ++-- ++-- Copyright (c) 2011 Mike Stirling ++-- ++-- 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 agreement from the author. ++-- ++-- * License is granted for non-commercial use only. A fee may not be charged ++-- for redistributions as source code or in synthesized/hardware form without ++-- specific prior written agreement from the author. ++-- ++-- 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. ++-- ++-- ++-- General purpose hardware debugger ++-- ++-- (C) 2011 Mike Stirling ++-- ++ ++library IEEE; ++use IEEE.STD_LOGIC_1164.ALL; ++use IEEE.NUMERIC_STD.ALL; ++ ++entity debugger is ++generic ( ++ -- Set this for a reasonable half flash duration relative to the ++ -- clock frequency ++ flash_divider : natural := 24 ++ ); ++port ( ++ CLOCK : in std_logic; ++ nRESET : in std_logic; ++ -- CPU clock enable in ++ CLKEN_IN : in std_logic; ++ -- Gated clock enable back out to CPU ++ CLKEN_OUT : out std_logic; ++ -- CPU IRQ in ++ nIRQ_IN : in std_logic; ++ -- Gated IRQ back out to CPU (no interrupts when single stepping) ++ nIRQ_OUT : out std_logic; ++ ++ -- CPU ++ A_CPU : in std_logic_vector(15 downto 0); ++ R_nW : in std_logic; ++ SYNC : in std_logic; ++ ++ -- Aux bus input for display in hex ++ AUX_BUS : in std_logic_vector(15 downto 0); ++ ++ -- Controls ++ -- RUN or HALT CPU ++ RUN : in std_logic; ++ -- Push button to single-step in HALT mode ++ nSTEP : in std_logic; ++ -- Push button to cycle display mode ++ nMODE : in std_logic; ++ -- Push button to cycle display digit in edit mode ++ nDIGIT : in std_logic; ++ -- Push button to cycle digit value in edit mode ++ nSET : in std_logic; ++ ++ -- Output to display ++ DIGIT3 : out std_logic_vector(6 downto 0); ++ DIGIT2 : out std_logic_vector(6 downto 0); ++ DIGIT1 : out std_logic_vector(6 downto 0); ++ DIGIT0 : out std_logic_vector(6 downto 0); ++ ++ LED_BREAKPOINT : out std_logic; ++ LED_WATCHPOINT : out std_logic ++ ); ++end entity; ++ ++architecture rtl of debugger is ++ ++component seg7 is ++port ( ++ D : in std_logic_vector(3 downto 0); ++ Q : out std_logic_vector(6 downto 0) ++); ++end component; ++ ++-- Current display mode ++type mode_t is (modeAddress,modeBreak,modeWatch,modeAux); ++signal mode : mode_t; ++-- Current edit digit ++signal digit : unsigned(1 downto 0); ++-- For flashing selected digit ++signal counter : unsigned(flash_divider-1 downto 0); ++signal flash : std_logic; ++-- Selected breakpoint address (stop on instruction fetch) ++signal breakpoint : std_logic_vector(15 downto 0); ++-- Selected watchpoint address (stop on write) ++signal watchpoint : std_logic_vector(15 downto 0); ++-- Address of last instruction fetch ++signal instr_addr : std_logic_vector(15 downto 0); ++-- Break flags ++signal halt : std_logic; ++-- Set when a request to resume has been received but before ++-- the CPU has run ++signal resuming : std_logic; ++ ++-- Display interface ++signal a_display : std_logic_vector(15 downto 0); ++signal d3_display : std_logic_vector(6 downto 0); ++signal d2_display : std_logic_vector(6 downto 0); ++signal d1_display : std_logic_vector(6 downto 0); ++signal d0_display : std_logic_vector(6 downto 0); ++ ++-- Registered button inputs ++signal r_step_n : std_logic; ++signal r_mode_n : std_logic; ++signal r_digit_n : std_logic; ++signal r_set_n : std_logic; ++ ++begin ++ -- Mask CPU clock enable ++ CLKEN_OUT <= CLKEN_IN and not halt; ++ -- Mask interrupt ++ nIRQ_OUT <= nIRQ_IN or not RUN; ++ ++ -- Route selected address to display ++ a_display <= instr_addr when mode = modeAddress else ++ breakpoint when mode = modeBreak else ++ watchpoint when mode = modeWatch else ++ AUX_BUS when mode = modeAux else ++ (others => '0'); ++ ++ -- Generate display digits from binary ++ d3 : seg7 port map (a_display(15 downto 12),d3_display); ++ d2 : seg7 port map (a_display(11 downto 8),d2_display); ++ d1 : seg7 port map (a_display(7 downto 4),d1_display); ++ d0 : seg7 port map (a_display(3 downto 0),d0_display); ++ ++ -- Flash selected digit in edit modes ++ DIGIT3 <= d3_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "11") else "1111111"; ++ DIGIT2 <= d2_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "10") else "1111111"; ++ DIGIT1 <= d1_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "01") else "1111111"; ++ DIGIT0 <= d0_display when (mode = modeAddress or mode = modeAux or flash = '1' or digit /= "00") else "1111111"; ++ ++ -- Show mode on LEDs ++ LED_BREAKPOINT <= '1' when mode = modeBreak or mode = modeAux else '0'; ++ LED_WATCHPOINT <= '1' when mode = modeWatch or mode = modeAux else '0'; ++ ++ -- Flash counter ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ counter <= (others => '0'); ++ flash <= '0'; ++ elsif rising_edge(CLOCK) then ++ counter <= counter + 1; ++ if counter = 0 then ++ flash <= not flash; ++ end if; ++ end if; ++ end process; ++ ++ -- Register buttons, select input mode and digit ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ r_mode_n <= '1'; ++ r_digit_n <= '1'; ++ r_set_n <= '1'; ++ mode <= modeAddress; ++ digit <= (others => '0'); ++ elsif rising_edge(CLOCK) then ++ -- Register buttons ++ r_mode_n <= nMODE; ++ r_digit_n <= nDIGIT; ++ r_set_n <= nSET; ++ ++ if r_mode_n = '1' and nMODE = '0' then ++ -- Increment mode ++ if mode = modeAddress then ++ mode <= modeBreak; ++ elsif mode = modeBreak then ++ mode <= modeWatch; ++ elsif mode = modeWatch then ++ mode <= modeAux; ++ else ++ mode <= modeAddress; ++ end if; ++ end if; ++ if r_digit_n = '1' and nDIGIT = '0' then ++ -- Increment digit ++ digit <= digit + 1; ++ end if; ++ end if; ++ end process; ++ ++ -- Set watchpoint address ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ watchpoint <= (others => '1'); ++ elsif rising_edge(CLOCK) and mode = modeWatch then ++ if r_set_n = '1' and nSET = '0' then ++ -- Increment selected digit on each button press ++ case digit is ++ when "00" => watchpoint(3 downto 0) <= std_logic_vector(unsigned(watchpoint(3 downto 0)) + 1); ++ when "01" => watchpoint(7 downto 4) <= std_logic_vector(unsigned(watchpoint(7 downto 4)) + 1); ++ when "10" => watchpoint(11 downto 8) <= std_logic_vector(unsigned(watchpoint(11 downto 8)) + 1); ++ when "11" => watchpoint(15 downto 12) <= std_logic_vector(unsigned(watchpoint(15 downto 12)) + 1); ++ when others => null; ++ end case; ++ end if; ++ end if; ++ end process; ++ ++ -- Set breakpoint address ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ breakpoint <= (others => '1'); ++ elsif rising_edge(CLOCK) and mode = modeBreak then ++ if r_set_n = '1' and nSET = '0' then ++ -- Increment selected digit on each button press ++ case digit is ++ when "00" => breakpoint(3 downto 0) <= std_logic_vector(unsigned(breakpoint(3 downto 0)) + 1); ++ when "01" => breakpoint(7 downto 4) <= std_logic_vector(unsigned(breakpoint(7 downto 4)) + 1); ++ when "10" => breakpoint(11 downto 8) <= std_logic_vector(unsigned(breakpoint(11 downto 8)) + 1); ++ when "11" => breakpoint(15 downto 12) <= std_logic_vector(unsigned(breakpoint(15 downto 12)) + 1); ++ ++ when others => null; ++ end case; ++ end if; ++ end if; ++ end process; ++ ++ -- CPU control logic ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ r_step_n <= '1'; ++ halt <= '0'; ++ resuming <= '0'; ++ instr_addr <= (others => '0'); ++ elsif rising_edge(CLOCK) then ++ -- Register single-step button ++ r_step_n <= nSTEP; ++ ++ -- Once the CPU has run we can trigger a new halt ++ if CLKEN_IN = '1' then ++ resuming <= '0'; ++ end if; ++ ++ if SYNC = '1' then ++ -- Latch address of instruction fetch ++ instr_addr <= A_CPU; ++ end if; ++ ++ -- Check for halt conditions if we are not resuming from a previous halt ++ if resuming = '0' then ++ if RUN = '0' and SYNC = '1' then ++ -- If not in RUN mode then halt on any instruction fetch ++ -- (single-step) ++ halt <= '1'; ++ end if; ++ if A_CPU = breakpoint and SYNC = '1' then ++ -- Halt CPU when instruction fetched from breakpoint address ++ halt <= '1'; ++ end if; ++ if A_CPU = watchpoint and SYNC = '0' and R_nW = '0' then ++ -- Halt CPU when data write to watchpoint address ++ halt <= '1'; ++ end if; ++ end if; ++ ++ -- Resume or single step when user presses "STEP" button ++ if r_step_n = '1' and nSTEP = '0' then ++ resuming <= '1'; ++ halt <= '0'; ++ end if; ++ end if; ++ end process; ++end architecture; +diff --git a/i2c_loader.vhd b/i2c_loader.vhd +index 35da643..61bdd22 100644 +--- a/i2c_loader.vhd ++++ b/i2c_loader.vhd +@@ -1,304 +1,304 @@ +--- ZX Spectrum for Altera DE1
+---
+--- Copyright (c) 2009-2011 Mike Stirling
+---
+--- 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 agreement from the author.
+---
+--- * License is granted for non-commercial use only. A fee may not be charged
+--- for redistributions as source code or in synthesized/hardware form without
+--- specific prior written agreement from the author.
+---
+--- 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.
+---
+-
+-library IEEE;
+-use IEEE.STD_LOGIC_1164.ALL;
+-use IEEE.STD_LOGIC_ARITH.ALL;
+-use IEEE.STD_LOGIC_UNSIGNED.ALL;
+-use IEEE.STD_LOGIC_MISC.ALL; -- for AND_REDUCE
+-use IEEE.NUMERIC_STD.ALL;
+-
+-entity i2c_loader is
+-generic (
+- -- Address of slave to be loaded
+- device_address : integer := 16#1a#;
+- -- Number of retries to allow before stopping
+- num_retries : integer := 0;
+- -- Length of clock divider in bits. Resulting bus frequency is
+- -- CLK/2^(log2_divider + 2)
+- log2_divider : integer := 6
+-);
+-
+-port (
+- CLK : in std_logic;
+- nRESET : in std_logic;
+-
+- I2C_SCL : inout std_logic;
+- I2C_SDA : inout std_logic;
+-
+- IS_DONE : out std_logic;
+- IS_ERROR : out std_logic
+- );
+-end i2c_loader;
+-
+-architecture i2c_loader_arch of i2c_loader is
+-type regs is array(0 to 19) of std_logic_vector(7 downto 0);
+-constant init_regs : regs := (
+- -- Left line in, 0dB, unmute
+- X"00", X"17",
+- -- Right line in, 0dB, unmute
+- X"02", X"17",
+- -- Left headphone out, 0dB
+- X"04", X"79",
+- -- Right headphone out, 0dB
+- X"06", X"79",
+- -- Audio path, DAC enabled, Line in, Bypass off, mic unmuted
+- X"08", X"10",
+- -- Digital path, Unmute, HP filter enabled
+- X"0A", X"00",
+- -- Power down mic, clkout and xtal osc
+- X"0C", X"62",
+- -- Format 16-bit I2S, no bit inversion or phase changes
+- X"0E", X"02",
+- -- Sampling control, 8 kHz USB mode (MCLK = 250fs * 6)
+- X"10", X"0D",
+- -- Activate
+- X"12", X"01"
+- );
+--- Number of bursts (i.e. total number of registers)
+-constant burst_length : positive := 2;
+--- Number of bytes to transfer per burst
+-constant num_bursts : positive := (init_regs'length / burst_length);
+-
+-type state_t is (Idle, Start, Data, Ack, Stop, Pause, Done);
+-signal state : state_t;
+-signal phase : std_logic_vector(1 downto 0);
+-subtype nbit_t is integer range 0 to 7;
+-signal nbit : nbit_t;
+-subtype nbyte_t is integer range 0 to burst_length; -- +1 for address byte
+-signal nbyte : nbyte_t;
+-subtype thisbyte_t is integer range 0 to init_regs'length; -- +1 for "done"
+-signal thisbyte : thisbyte_t;
+-subtype retries_t is integer range 0 to num_retries;
+-signal retries : retries_t;
+-
+-signal clken : std_logic;
+-signal divider : std_logic_vector(log2_divider-1 downto 0);
+-signal shiftreg : std_logic_vector(7 downto 0);
+-signal scl_out : std_logic;
+-signal sda_out : std_logic;
+-signal nak : std_logic;
+-begin
+- -- Create open-drain outputs for I2C bus
+- I2C_SCL <= '0' when scl_out = '0' else 'Z';
+- I2C_SDA <= '0' when sda_out = '0' else 'Z';
+- -- Status outputs are driven both ways
+- IS_DONE <= '1' when state = Done else '0';
+- IS_ERROR <= nak;
+-
+- -- Generate clock enable for desired bus speed
+- clken <= AND_REDUCE(divider);
+- process(nRESET,CLK)
+- begin
+- if nRESET = '0' then
+- divider <= (others => '0');
+- elsif falling_edge(CLK) then
+- divider <= divider + '1';
+- end if;
+- end process;
+-
+- -- The I2C loader process
+- process(nRESET,CLK)
+- begin
+- if nRESET = '0' then
+- scl_out <= '1';
+- sda_out <= '1';
+- state <= Idle;
+- phase <= "00";
+- nbit <= 0;
+- nbyte <= 0;
+- thisbyte <= 0;
+- shiftreg <= (others => '0');
+- nak <= '0'; -- No error
+- retries <= num_retries;
+- elsif rising_edge(CLK) and clken = '1' then
+- -- Next phase by default
+- phase <= phase + 1;
+-
+- -- STATE: IDLE
+- if state = Idle then
+- -- Start loading the device registers straight away
+- -- A 'GO' bit could be polled here if required
+- state <= Start;
+- phase <= "00";
+- scl_out <= '1';
+- sda_out <= '1';
+-
+- -- STATE: START
+- elsif state = Start then
+- -- Generate START condition
+- case phase is
+- when "00" =>
+- -- Drop SDA first
+- sda_out <= '0';
+- when "10" =>
+- -- Then drop SCL
+- scl_out <= '0';
+- when "11" =>
+- -- Advance to next state
+- -- Shift register loaded with device slave address
+- state <= Data;
+- nbit <= 7;
+- shiftreg <= std_logic_vector(to_unsigned(device_address,7)) & '0'; -- writing
+- nbyte <= burst_length;
+- when others =>
+- null;
+- end case;
+-
+- -- STATE: DATA
+- elsif state = Data then
+- -- Generate data
+- case phase is
+- when "00" =>
+- -- Drop SCL
+- scl_out <= '0';
+- when "01" =>
+- -- Output data and shift (MSb first)
+- sda_out <= shiftreg(7);
+- shiftreg <= shiftreg(6 downto 0) & '0';
+- when "10" =>
+- -- Raise SCL
+- scl_out <= '1';
+- when "11" =>
+- -- Next bit or advance to next state when done
+- if nbit = 0 then
+- state <= Ack;
+- else
+- nbit <= nbit - 1;
+- end if;
+- when others =>
+- null;
+- end case;
+-
+- -- STATE: ACK
+- elsif state = Ack then
+- -- Generate ACK clock and check for error condition
+- case phase is
+- when "00" =>
+- -- Drop SCL
+- scl_out <= '0';
+- when "01" =>
+- -- Float data
+- sda_out <= '1';
+- when "10" =>
+- -- Sample ack bit
+- nak <= I2C_SDA;
+- if I2C_SDA = '1' then
+- -- Error
+- nbyte <= 0; -- Close this burst and skip remaining registers
+- thisbyte <= init_regs'length;
+- else
+- -- Hold ACK to avoid spurious stops - this seems to fix a
+- -- problem with the Wolfson codec which releases the ACK
+- -- right on the falling edge of the clock pulse. It looks like
+- -- the device interprets this is a STOP condition and then fails
+- -- to acknowledge the next byte. We can avoid this by holding the
+- -- ACK condition for a little longer.
+- sda_out <= '0';
+- end if;
+- -- Raise SCL
+- scl_out <= '1';
+- when "11" =>
+- -- Advance to next state
+- if nbyte = 0 then
+- -- No more bytes in this burst - generate a STOP
+- state <= Stop;
+- else
+- -- Generate next byte
+- state <= Data;
+- nbit <= 7;
+- shiftreg <= init_regs(thisbyte);
+- nbyte <= nbyte - 1;
+- thisbyte <= thisbyte + 1;
+- end if;
+- when others =>
+- null;
+- end case;
+-
+- -- STATE: STOP
+- elsif state = Stop then
+- -- Generate STOP condition
+- case phase is
+- when "00" =>
+- -- Drop SCL first
+- scl_out <= '0';
+- when "01" =>
+- -- Drop SDA
+- sda_out <= '0';
+- when "10" =>
+- -- Raise SCL
+- scl_out <= '1';
+- when "11" =>
+- if thisbyte = init_regs'length then
+- -- All registers done, advance to finished state. This will
+- -- bring SDA high while SCL is still high, completing the STOP
+- -- condition
+- state <= Done;
+- else
+- -- Load the next register after a short delay
+- state <= Pause;
+- end if;
+- when others =>
+- null;
+- end case;
+-
+- -- STATE: PAUSE
+- elsif state = Pause then
+- -- Delay for one cycle of 'phase' then start the next burst
+- scl_out <= '1';
+- sda_out <= '1';
+- if phase = "11" then
+- state <= Start;
+- end if;
+-
+- -- STATE: DONE
+- else
+- -- Finished
+- scl_out <= '1';
+- sda_out <= '1';
+-
+- if nak = '1' and retries > 0 then
+- -- We can retry in the event of a NAK in case the
+- -- slave got out of sync for some reason
+- retries <= retries - 1;
+- state <= Idle;
+- end if;
+- end if;
+- end if;
+- end process;
+-end i2c_loader_arch;
+-
++-- ZX Spectrum for Altera DE1 ++-- ++-- Copyright (c) 2009-2011 Mike Stirling ++-- ++-- 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 agreement from the author. ++-- ++-- * License is granted for non-commercial use only. A fee may not be charged ++-- for redistributions as source code or in synthesized/hardware form without ++-- specific prior written agreement from the author. ++-- ++-- 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. ++-- ++ ++library IEEE; ++use IEEE.STD_LOGIC_1164.ALL; ++use IEEE.STD_LOGIC_ARITH.ALL; ++use IEEE.STD_LOGIC_UNSIGNED.ALL; ++use IEEE.STD_LOGIC_MISC.ALL; -- for AND_REDUCE ++use IEEE.NUMERIC_STD.ALL; ++ ++entity i2c_loader is ++generic ( ++ -- Address of slave to be loaded ++ device_address : integer := 16#1a#; ++ -- Number of retries to allow before stopping ++ num_retries : integer := 0; ++ -- Length of clock divider in bits. Resulting bus frequency is ++ -- CLK/2^(log2_divider + 2) ++ log2_divider : integer := 6 ++); ++ ++port ( ++ CLK : in std_logic; ++ nRESET : in std_logic; ++ ++ I2C_SCL : inout std_logic; ++ I2C_SDA : inout std_logic; ++ ++ IS_DONE : out std_logic; ++ IS_ERROR : out std_logic ++ ); ++end i2c_loader; ++ ++architecture i2c_loader_arch of i2c_loader is ++type regs is array(0 to 19) of std_logic_vector(7 downto 0); ++constant init_regs : regs := ( ++ -- Left line in, 0dB, unmute ++ X"00", X"17", ++ -- Right line in, 0dB, unmute ++ X"02", X"17", ++ -- Left headphone out, 0dB ++ X"04", X"79", ++ -- Right headphone out, 0dB ++ X"06", X"79", ++ -- Audio path, DAC enabled, Line in, Bypass off, mic unmuted ++ X"08", X"10", ++ -- Digital path, Unmute, HP filter enabled ++ X"0A", X"00", ++ -- Power down mic, clkout and xtal osc ++ X"0C", X"62", ++ -- Format 16-bit I2S, no bit inversion or phase changes ++ X"0E", X"02", ++ -- Sampling control, 8 kHz USB mode (MCLK = 250fs * 6) ++ X"10", X"0D", ++ -- Activate ++ X"12", X"01" ++ ); ++-- Number of bursts (i.e. total number of registers) ++constant burst_length : positive := 2; ++-- Number of bytes to transfer per burst ++constant num_bursts : positive := (init_regs'length / burst_length); ++ ++type state_t is (Idle, Start, Data, Ack, Stop, Pause, Done); ++signal state : state_t; ++signal phase : std_logic_vector(1 downto 0); ++subtype nbit_t is integer range 0 to 7; ++signal nbit : nbit_t; ++subtype nbyte_t is integer range 0 to burst_length; -- +1 for address byte ++signal nbyte : nbyte_t; ++subtype thisbyte_t is integer range 0 to init_regs'length; -- +1 for "done" ++signal thisbyte : thisbyte_t; ++subtype retries_t is integer range 0 to num_retries; ++signal retries : retries_t; ++ ++signal clken : std_logic; ++signal divider : std_logic_vector(log2_divider-1 downto 0); ++signal shiftreg : std_logic_vector(7 downto 0); ++signal scl_out : std_logic; ++signal sda_out : std_logic; ++signal nak : std_logic; ++begin ++ -- Create open-drain outputs for I2C bus ++ I2C_SCL <= '0' when scl_out = '0' else 'Z'; ++ I2C_SDA <= '0' when sda_out = '0' else 'Z'; ++ -- Status outputs are driven both ways ++ IS_DONE <= '1' when state = Done else '0'; ++ IS_ERROR <= nak; ++ ++ -- Generate clock enable for desired bus speed ++ clken <= AND_REDUCE(divider); ++ process(nRESET,CLK) ++ begin ++ if nRESET = '0' then ++ divider <= (others => '0'); ++ elsif falling_edge(CLK) then ++ divider <= divider + '1'; ++ end if; ++ end process; ++ ++ -- The I2C loader process ++ process(nRESET,CLK) ++ begin ++ if nRESET = '0' then ++ scl_out <= '1'; ++ sda_out <= '1'; ++ state <= Idle; ++ phase <= "00"; ++ nbit <= 0; ++ nbyte <= 0; ++ thisbyte <= 0; ++ shiftreg <= (others => '0'); ++ nak <= '0'; -- No error ++ retries <= num_retries; ++ elsif rising_edge(CLK) and clken = '1' then ++ -- Next phase by default ++ phase <= phase + 1; ++ ++ -- STATE: IDLE ++ if state = Idle then ++ -- Start loading the device registers straight away ++ -- A 'GO' bit could be polled here if required ++ state <= Start; ++ phase <= "00"; ++ scl_out <= '1'; ++ sda_out <= '1'; ++ ++ -- STATE: START ++ elsif state = Start then ++ -- Generate START condition ++ case phase is ++ when "00" => ++ -- Drop SDA first ++ sda_out <= '0'; ++ when "10" => ++ -- Then drop SCL ++ scl_out <= '0'; ++ when "11" => ++ -- Advance to next state ++ -- Shift register loaded with device slave address ++ state <= Data; ++ nbit <= 7; ++ shiftreg <= std_logic_vector(to_unsigned(device_address,7)) & '0'; -- writing ++ nbyte <= burst_length; ++ when others => ++ null; ++ end case; ++ ++ -- STATE: DATA ++ elsif state = Data then ++ -- Generate data ++ case phase is ++ when "00" => ++ -- Drop SCL ++ scl_out <= '0'; ++ when "01" => ++ -- Output data and shift (MSb first) ++ sda_out <= shiftreg(7); ++ shiftreg <= shiftreg(6 downto 0) & '0'; ++ when "10" => ++ -- Raise SCL ++ scl_out <= '1'; ++ when "11" => ++ -- Next bit or advance to next state when done ++ if nbit = 0 then ++ state <= Ack; ++ else ++ nbit <= nbit - 1; ++ end if; ++ when others => ++ null; ++ end case; ++ ++ -- STATE: ACK ++ elsif state = Ack then ++ -- Generate ACK clock and check for error condition ++ case phase is ++ when "00" => ++ -- Drop SCL ++ scl_out <= '0'; ++ when "01" => ++ -- Float data ++ sda_out <= '1'; ++ when "10" => ++ -- Sample ack bit ++ nak <= I2C_SDA; ++ if I2C_SDA = '1' then ++ -- Error ++ nbyte <= 0; -- Close this burst and skip remaining registers ++ thisbyte <= init_regs'length; ++ else ++ -- Hold ACK to avoid spurious stops - this seems to fix a ++ -- problem with the Wolfson codec which releases the ACK ++ -- right on the falling edge of the clock pulse. It looks like ++ -- the device interprets this is a STOP condition and then fails ++ -- to acknowledge the next byte. We can avoid this by holding the ++ -- ACK condition for a little longer. ++ sda_out <= '0'; ++ end if; ++ -- Raise SCL ++ scl_out <= '1'; ++ when "11" => ++ -- Advance to next state ++ if nbyte = 0 then ++ -- No more bytes in this burst - generate a STOP ++ state <= Stop; ++ else ++ -- Generate next byte ++ state <= Data; ++ nbit <= 7; ++ shiftreg <= init_regs(thisbyte); ++ nbyte <= nbyte - 1; ++ thisbyte <= thisbyte + 1; ++ end if; ++ when others => ++ null; ++ end case; ++ ++ -- STATE: STOP ++ elsif state = Stop then ++ -- Generate STOP condition ++ case phase is ++ when "00" => ++ -- Drop SCL first ++ scl_out <= '0'; ++ when "01" => ++ -- Drop SDA ++ sda_out <= '0'; ++ when "10" => ++ -- Raise SCL ++ scl_out <= '1'; ++ when "11" => ++ if thisbyte = init_regs'length then ++ -- All registers done, advance to finished state. This will ++ -- bring SDA high while SCL is still high, completing the STOP ++ -- condition ++ state <= Done; ++ else ++ -- Load the next register after a short delay ++ state <= Pause; ++ end if; ++ when others => ++ null; ++ end case; ++ ++ -- STATE: PAUSE ++ elsif state = Pause then ++ -- Delay for one cycle of 'phase' then start the next burst ++ scl_out <= '1'; ++ sda_out <= '1'; ++ if phase = "11" then ++ state <= Start; ++ end if; ++ ++ -- STATE: DONE ++ else ++ -- Finished ++ scl_out <= '1'; ++ sda_out <= '1'; ++ ++ if nak = '1' and retries > 0 then ++ -- We can retry in the event of a NAK in case the ++ -- slave got out of sync for some reason ++ retries <= retries - 1; ++ state <= Idle; ++ end if; ++ end if; ++ end if; ++ end process; ++end i2c_loader_arch; ++ +diff --git a/i2s_intf.vhd b/i2s_intf.vhd +index e15ce2c..49b6efb 100644 +--- a/i2s_intf.vhd ++++ b/i2s_intf.vhd +@@ -1,37 +1,37 @@ + -- ZX Spectrum for Altera DE1 + -- +--- Copyright (c) 2009-2011 Mike Stirling
+---
+--- 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 agreement from the author.
+---
+--- * License is granted for non-commercial use only. A fee may not be charged
+--- for redistributions as source code or in synthesized/hardware form without
+--- specific prior written agreement from the author.
+---
+--- 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
++-- Copyright (c) 2009-2011 Mike Stirling ++-- ++-- 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 agreement from the author. ++-- ++-- * License is granted for non-commercial use only. A fee may not be charged ++-- for redistributions as source code or in synthesized/hardware form without ++-- specific prior written agreement from the author. ++-- ++-- 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. + -- + +diff --git a/keyboard.vhd b/keyboard.vhd +index c0b8603..cba4054 100644 +--- a/keyboard.vhd ++++ b/keyboard.vhd +@@ -1,294 +1,294 @@ +--- BBC Micro for Altera DE1
+---
+--- Copyright (c) 2011 Mike Stirling
+---
+--- 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 agreement from the author.
+---
+--- * License is granted for non-commercial use only. A fee may not be charged
+--- for redistributions as source code or in synthesized/hardware form without
+--- specific prior written agreement from the author.
+---
+--- 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.
+---
+--- BBC keyboard implementation with interface to PS/2
+---
+--- (C) 2011 Mike Stirling
+---
+-
+-library IEEE;
+-use IEEE.STD_LOGIC_1164.ALL;
+-use IEEE.NUMERIC_STD.ALL;
+-
+-entity keyboard is
+-port (
+- CLOCK : in std_logic;
+- nRESET : in std_logic;
+- CLKEN_1MHZ : in std_logic;
+-
+- -- PS/2 interface
+- PS2_CLK : in std_logic;
+- PS2_DATA : in std_logic;
+-
+- -- If 1 then column is incremented automatically at
+- -- 1 MHz rate
+- AUTOSCAN : in std_logic;
+-
+- COLUMN : in std_logic_vector(3 downto 0);
+- ROW : in std_logic_vector(2 downto 0);
+-
+- -- 1 when currently selected key is down (AUTOSCAN disabled)
+- KEYPRESS : out std_logic;
+- -- 1 when any key is down (except row 0)
+- INT : out std_logic;
+- -- BREAK key output - 1 when pressed
+- BREAK_OUT : out std_logic;
+-
+- -- DIP switch inputs
+- DIP_SWITCH : in std_logic_vector(7 downto 0)
+- );
+-end entity;
+-
+-architecture rtl of keyboard is
+-
+--- PS/2 interface
+-component ps2_intf is
+-generic (filter_length : positive := 8);
+-port(
+- CLK : in std_logic;
+- nRESET : in std_logic;
+-
+- -- PS/2 interface (could be bi-dir)
+- PS2_CLK : in std_logic;
+- PS2_DATA : in std_logic;
+-
+- -- Byte-wide data interface - only valid for one clock
+- -- so must be latched externally if required
+- DATA : out std_logic_vector(7 downto 0);
+- VALID : out std_logic;
+- ERROR : out std_logic
+- );
+-end component;
+-
+--- Interface to PS/2 block
+-signal keyb_data : std_logic_vector(7 downto 0);
+-signal keyb_valid : std_logic;
+-signal keyb_error : std_logic;
+-
+--- Internal signals
+-type key_matrix is array(0 to 15) of std_logic_vector(7 downto 0);
+-signal keys : key_matrix;
+-signal col : unsigned(3 downto 0);
+-signal release : std_logic;
+-signal extended : std_logic;
+-begin
+-
+- ps2 : ps2_intf port map (
+- CLOCK, nRESET,
+- PS2_CLK, PS2_DATA,
+- keyb_data, keyb_valid, keyb_error
+- );
+-
+- -- Column counts automatically when AUTOSCAN is enabled, otherwise
+- -- value is loaded from external input
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- col <= (others => '0');
+- elsif rising_edge(CLOCK) then
+- if AUTOSCAN = '0' then
+- -- If autoscan disabled then transfer current COLUMN to counter
+- -- immediately (don't wait for next 1 MHz cycle)
+- col <= unsigned(COLUMN);
+- elsif CLKEN_1MHZ = '1' then
+- -- Otherwise increment the counter once per 1 MHz tick
+- col <= col + 1;
+- end if;
+- end if;
+- end process;
+-
+- -- Generate interrupt if any key in currently scanned column is pressed
+- -- (apart from in row 0). Output selected key status if autoscan disabled.
+- process(keys,col,ROW,AUTOSCAN)
+- variable k : std_logic_vector(7 downto 0);
+- begin
+- -- Shortcut to current key column
+- k := keys(to_integer(col));
+-
+- -- Interrupt if any key pressed in rows 1 to 7.
+- INT <= k(7) or k(6) or k(5) or k(4) or k(3) or k(2) or k(1);
+-
+- -- Determine which key is pressed
+- -- Inhibit output during auto-scan
+- if AUTOSCAN = '0' then
+- KEYPRESS <= k(to_integer(unsigned(ROW)));
+- else
+- KEYPRESS <= '0';
+- end if;
+- end process;
+-
+- -- Decode PS/2 data
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- release <= '0';
+- extended <= '0';
+-
+- BREAK_OUT <= '0';
+-
+- keys(0) <= (others => '0');
+- keys(1) <= (others => '0');
+- keys(2) <= (others => '0');
+- keys(3) <= (others => '0');
+- keys(4) <= (others => '0');
+- keys(5) <= (others => '0');
+- keys(6) <= (others => '0');
+- keys(7) <= (others => '0');
+- keys(8) <= (others => '0');
+- keys(9) <= (others => '0');
+- -- These non-existent rows are used in the BBC master
+- keys(10) <= (others => '0');
+- keys(11) <= (others => '0');
+- keys(12) <= (others => '0');
+- keys(13) <= (others => '0');
+- keys(14) <= (others => '0');
+- keys(15) <= (others => '0');
+- elsif rising_edge(CLOCK) then
+- -- Copy DIP switches through to row 0
+- keys(2)(0) <= DIP_SWITCH(7);
+- keys(3)(0) <= DIP_SWITCH(6);
+- keys(4)(0) <= DIP_SWITCH(5);
+- keys(5)(0) <= DIP_SWITCH(4);
+- keys(6)(0) <= DIP_SWITCH(3);
+- keys(7)(0) <= DIP_SWITCH(2);
+- keys(8)(0) <= DIP_SWITCH(1);
+- keys(9)(0) <= DIP_SWITCH(0);
+-
+- if keyb_valid = '1' then
+- -- Decode keyboard input
+- if keyb_data = X"e0" then
+- -- Extended key code follows
+- extended <= '1';
+- elsif keyb_data = X"f0" then
+- -- Release code follows
+- release <= '1';
+- else
+- -- Cancel extended/release flags for next time
+- release <= '0';
+- extended <= '0';
+-
+- -- Decode scan codes
+- case keyb_data is
+- when X"12" => keys(0)(0) <= not release; -- Left SHIFT
+- when X"59" => keys(0)(0) <= not release; -- Right SHIFT
+- when X"15" => keys(0)(1) <= not release; -- Q
+- when X"09" => keys(0)(2) <= not release; -- F10 (F0)
+- when X"16" => keys(0)(3) <= not release; -- 1
+- when X"58" => keys(0)(4) <= not release; -- CAPS LOCK
+- when X"11" => keys(0)(5) <= not release; -- LEFT ALT (SHIFT LOCK)
+- when X"0D" => keys(0)(6) <= not release; -- TAB
+- when X"76" => keys(0)(7) <= not release; -- ESCAPE
+- when X"14" => keys(1)(0) <= not release; -- LEFT/RIGHT CTRL (CTRL)
+- when X"26" => keys(1)(1) <= not release; -- 3
+- when X"1D" => keys(1)(2) <= not release; -- W
+- when X"1E" => keys(1)(3) <= not release; -- 2
+- when X"1C" => keys(1)(4) <= not release; -- A
+- when X"1B" => keys(1)(5) <= not release; -- S
+- when X"1A" => keys(1)(6) <= not release; -- Z
+- when X"05" => keys(1)(7) <= not release; -- F1
+- when X"25" => keys(2)(1) <= not release; -- 4
+- when X"24" => keys(2)(2) <= not release; -- E
+- when X"23" => keys(2)(3) <= not release; -- D
+- when X"22" => keys(2)(4) <= not release; -- X
+- when X"21" => keys(2)(5) <= not release; -- C
+- when X"29" => keys(2)(6) <= not release; -- SPACE
+- when X"06" => keys(2)(7) <= not release; -- F2
+- when X"2E" => keys(3)(1) <= not release; -- 5
+- when X"2C" => keys(3)(2) <= not release; -- T
+- when X"2D" => keys(3)(3) <= not release; -- R
+- when X"2B" => keys(3)(4) <= not release; -- F
+- when X"34" => keys(3)(5) <= not release; -- G
+- when X"2A" => keys(3)(6) <= not release; -- V
+- when X"04" => keys(3)(7) <= not release; -- F3
+- when X"0C" => keys(4)(1) <= not release; -- F4
+- when X"3D" => keys(4)(2) <= not release; -- 7
+- when X"36" => keys(4)(3) <= not release; -- 6
+- when X"35" => keys(4)(4) <= not release; -- Y
+- when X"33" => keys(4)(5) <= not release; -- H
+- when X"32" => keys(4)(6) <= not release; -- B
+- when X"03" => keys(4)(7) <= not release; -- F5
+- when X"3E" => keys(5)(1) <= not release; -- 8
+- when X"43" => keys(5)(2) <= not release; -- I
+- when X"3C" => keys(5)(3) <= not release; -- U
+- when X"3B" => keys(5)(4) <= not release; -- J
+- when X"31" => keys(5)(5) <= not release; -- N
+- when X"3A" => keys(5)(6) <= not release; -- M
+- when X"0B" => keys(5)(7) <= not release; -- F6
+- when X"83" => keys(6)(1) <= not release; -- F7
+- when X"46" => keys(6)(2) <= not release; -- 9
+- when X"44" => keys(6)(3) <= not release; -- O
+- when X"42" => keys(6)(4) <= not release; -- K
+- when X"4B" => keys(6)(5) <= not release; -- L
+- when X"41" => keys(6)(6) <= not release; -- ,
+- when X"0A" => keys(6)(7) <= not release; -- F8
+- when X"4E" => keys(7)(1) <= not release; -- -
+- when X"45" => keys(7)(2) <= not release; -- 0
+- when X"4D" => keys(7)(3) <= not release; -- P
+- when X"0E" => keys(7)(4) <= not release; -- ` (@)
+- when X"4C" => keys(7)(5) <= not release; -- ;
+- when X"49" => keys(7)(6) <= not release; -- .
+- when X"01" => keys(7)(7) <= not release; -- F9
+- when X"55" => keys(8)(1) <= not release; -- = (^)
+- when X"5D" => keys(8)(2) <= not release; -- # (_)
+- when X"54" => keys(8)(3) <= not release; -- [
+- when X"52" => keys(8)(4) <= not release; -- '
+- when X"5B" => keys(8)(5) <= not release; -- ]
+- when X"4A" => keys(8)(6) <= not release; -- /
+- when X"61" => keys(8)(7) <= not release; -- \
+- when X"6B" => keys(9)(1) <= not release; -- LEFT
+- when X"72" => keys(9)(2) <= not release; -- DOWN
+- when X"75" => keys(9)(3) <= not release; -- UP
+- when X"5A" => keys(9)(4) <= not release; -- RETURN
+- when X"66" => keys(9)(5) <= not release; -- BACKSPACE (DELETE)
+- when X"69" => keys(9)(6) <= not release; -- END (COPY)
+- when X"74" => keys(9)(7) <= not release; -- RIGHT
+-
+- -- F12 is used for the BREAK key, which in the real BBC asserts
+- -- reset. Here we pass this out to the top level which may
+- -- optionally OR it in to the system reset
+- when X"07" => BREAK_OUT <= not release; -- F12 (BREAK)
+-
+- when others => null;
+- end case;
+-
+- end if;
+- end if;
+- end if;
+- end process;
+-
+-end architecture;
+-
+-
++-- BBC Micro for Altera DE1 ++-- ++-- Copyright (c) 2011 Mike Stirling ++-- ++-- 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 agreement from the author. ++-- ++-- * License is granted for non-commercial use only. A fee may not be charged ++-- for redistributions as source code or in synthesized/hardware form without ++-- specific prior written agreement from the author. ++-- ++-- 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. ++-- ++-- BBC keyboard implementation with interface to PS/2 ++-- ++-- (C) 2011 Mike Stirling ++-- ++ ++library IEEE; ++use IEEE.STD_LOGIC_1164.ALL; ++use IEEE.NUMERIC_STD.ALL; ++ ++entity keyboard is ++port ( ++ CLOCK : in std_logic; ++ nRESET : in std_logic; ++ CLKEN_1MHZ : in std_logic; ++ ++ -- PS/2 interface ++ PS2_CLK : in std_logic; ++ PS2_DATA : in std_logic; ++ ++ -- If 1 then column is incremented automatically at ++ -- 1 MHz rate ++ AUTOSCAN : in std_logic; ++ ++ COLUMN : in std_logic_vector(3 downto 0); ++ ROW : in std_logic_vector(2 downto 0); ++ ++ -- 1 when currently selected key is down (AUTOSCAN disabled) ++ KEYPRESS : out std_logic; ++ -- 1 when any key is down (except row 0) ++ INT : out std_logic; ++ -- BREAK key output - 1 when pressed ++ BREAK_OUT : out std_logic; ++ ++ -- DIP switch inputs ++ DIP_SWITCH : in std_logic_vector(7 downto 0) ++ ); ++end entity; ++ ++architecture rtl of keyboard is ++ ++-- PS/2 interface ++component ps2_intf is ++generic (filter_length : positive := 8); ++port( ++ CLK : in std_logic; ++ nRESET : in std_logic; ++ ++ -- PS/2 interface (could be bi-dir) ++ PS2_CLK : in std_logic; ++ PS2_DATA : in std_logic; ++ ++ -- Byte-wide data interface - only valid for one clock ++ -- so must be latched externally if required ++ DATA : out std_logic_vector(7 downto 0); ++ VALID : out std_logic; ++ ERROR : out std_logic ++ ); ++end component; ++ ++-- Interface to PS/2 block ++signal keyb_data : std_logic_vector(7 downto 0); ++signal keyb_valid : std_logic; ++signal keyb_error : std_logic; ++ ++-- Internal signals ++type key_matrix is array(0 to 15) of std_logic_vector(7 downto 0); ++signal keys : key_matrix; ++signal col : unsigned(3 downto 0); ++signal release : std_logic; ++signal extended : std_logic; ++begin ++ ++ ps2 : ps2_intf port map ( ++ CLOCK, nRESET, ++ PS2_CLK, PS2_DATA, ++ keyb_data, keyb_valid, keyb_error ++ ); ++ ++ -- Column counts automatically when AUTOSCAN is enabled, otherwise ++ -- value is loaded from external input ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ col <= (others => '0'); ++ elsif rising_edge(CLOCK) then ++ if AUTOSCAN = '0' then ++ -- If autoscan disabled then transfer current COLUMN to counter ++ -- immediately (don't wait for next 1 MHz cycle) ++ col <= unsigned(COLUMN); ++ elsif CLKEN_1MHZ = '1' then ++ -- Otherwise increment the counter once per 1 MHz tick ++ col <= col + 1; ++ end if; ++ end if; ++ end process; ++ ++ -- Generate interrupt if any key in currently scanned column is pressed ++ -- (apart from in row 0). Output selected key status if autoscan disabled. ++ process(keys,col,ROW,AUTOSCAN) ++ variable k : std_logic_vector(7 downto 0); ++ begin ++ -- Shortcut to current key column ++ k := keys(to_integer(col)); ++ ++ -- Interrupt if any key pressed in rows 1 to 7. ++ INT <= k(7) or k(6) or k(5) or k(4) or k(3) or k(2) or k(1); ++ ++ -- Determine which key is pressed ++ -- Inhibit output during auto-scan ++ if AUTOSCAN = '0' then ++ KEYPRESS <= k(to_integer(unsigned(ROW))); ++ else ++ KEYPRESS <= '0'; ++ end if; ++ end process; ++ ++ -- Decode PS/2 data ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ release <= '0'; ++ extended <= '0'; ++ ++ BREAK_OUT <= '0'; ++ ++ keys(0) <= (others => '0'); ++ keys(1) <= (others => '0'); ++ keys(2) <= (others => '0'); ++ keys(3) <= (others => '0'); ++ keys(4) <= (others => '0'); ++ keys(5) <= (others => '0'); ++ keys(6) <= (others => '0'); ++ keys(7) <= (others => '0'); ++ keys(8) <= (others => '0'); ++ keys(9) <= (others => '0'); ++ -- These non-existent rows are used in the BBC master ++ keys(10) <= (others => '0'); ++ keys(11) <= (others => '0'); ++ keys(12) <= (others => '0'); ++ keys(13) <= (others => '0'); ++ keys(14) <= (others => '0'); ++ keys(15) <= (others => '0'); ++ elsif rising_edge(CLOCK) then ++ -- Copy DIP switches through to row 0 ++ keys(2)(0) <= DIP_SWITCH(7); ++ keys(3)(0) <= DIP_SWITCH(6); ++ keys(4)(0) <= DIP_SWITCH(5); ++ keys(5)(0) <= DIP_SWITCH(4); ++ keys(6)(0) <= DIP_SWITCH(3); ++ keys(7)(0) <= DIP_SWITCH(2); ++ keys(8)(0) <= DIP_SWITCH(1); ++ keys(9)(0) <= DIP_SWITCH(0); ++ ++ if keyb_valid = '1' then ++ -- Decode keyboard input ++ if keyb_data = X"e0" then ++ -- Extended key code follows ++ extended <= '1'; ++ elsif keyb_data = X"f0" then ++ -- Release code follows ++ release <= '1'; ++ else ++ -- Cancel extended/release flags for next time ++ release <= '0'; ++ extended <= '0'; ++ ++ -- Decode scan codes ++ case keyb_data is ++ when X"12" => keys(0)(0) <= not release; -- Left SHIFT ++ when X"59" => keys(0)(0) <= not release; -- Right SHIFT ++ when X"15" => keys(0)(1) <= not release; -- Q ++ when X"09" => keys(0)(2) <= not release; -- F10 (F0) ++ when X"16" => keys(0)(3) <= not release; -- 1 ++ when X"58" => keys(0)(4) <= not release; -- CAPS LOCK ++ when X"11" => keys(0)(5) <= not release; -- LEFT ALT (SHIFT LOCK) ++ when X"0D" => keys(0)(6) <= not release; -- TAB ++ when X"76" => keys(0)(7) <= not release; -- ESCAPE ++ when X"14" => keys(1)(0) <= not release; -- LEFT/RIGHT CTRL (CTRL) ++ when X"26" => keys(1)(1) <= not release; -- 3 ++ when X"1D" => keys(1)(2) <= not release; -- W ++ when X"1E" => keys(1)(3) <= not release; -- 2 ++ when X"1C" => keys(1)(4) <= not release; -- A ++ when X"1B" => keys(1)(5) <= not release; -- S ++ when X"1A" => keys(1)(6) <= not release; -- Z ++ when X"05" => keys(1)(7) <= not release; -- F1 ++ when X"25" => keys(2)(1) <= not release; -- 4 ++ when X"24" => keys(2)(2) <= not release; -- E ++ when X"23" => keys(2)(3) <= not release; -- D ++ when X"22" => keys(2)(4) <= not release; -- X ++ when X"21" => keys(2)(5) <= not release; -- C ++ when X"29" => keys(2)(6) <= not release; -- SPACE ++ when X"06" => keys(2)(7) <= not release; -- F2 ++ when X"2E" => keys(3)(1) <= not release; -- 5 ++ when X"2C" => keys(3)(2) <= not release; -- T ++ when X"2D" => keys(3)(3) <= not release; -- R ++ when X"2B" => keys(3)(4) <= not release; -- F ++ when X"34" => keys(3)(5) <= not release; -- G ++ when X"2A" => keys(3)(6) <= not release; -- V ++ when X"04" => keys(3)(7) <= not release; -- F3 ++ when X"0C" => keys(4)(1) <= not release; -- F4 ++ when X"3D" => keys(4)(2) <= not release; -- 7 ++ when X"36" => keys(4)(3) <= not release; -- 6 ++ when X"35" => keys(4)(4) <= not release; -- Y ++ when X"33" => keys(4)(5) <= not release; -- H ++ when X"32" => keys(4)(6) <= not release; -- B ++ when X"03" => keys(4)(7) <= not release; -- F5 ++ when X"3E" => keys(5)(1) <= not release; -- 8 ++ when X"43" => keys(5)(2) <= not release; -- I ++ when X"3C" => keys(5)(3) <= not release; -- U ++ when X"3B" => keys(5)(4) <= not release; -- J ++ when X"31" => keys(5)(5) <= not release; -- N ++ when X"3A" => keys(5)(6) <= not release; -- M ++ when X"0B" => keys(5)(7) <= not release; -- F6 ++ when X"83" => keys(6)(1) <= not release; -- F7 ++ when X"46" => keys(6)(2) <= not release; -- 9 ++ when X"44" => keys(6)(3) <= not release; -- O ++ when X"42" => keys(6)(4) <= not release; -- K ++ when X"4B" => keys(6)(5) <= not release; -- L ++ when X"41" => keys(6)(6) <= not release; -- , ++ when X"0A" => keys(6)(7) <= not release; -- F8 ++ when X"4E" => keys(7)(1) <= not release; -- - ++ when X"45" => keys(7)(2) <= not release; -- 0 ++ when X"4D" => keys(7)(3) <= not release; -- P ++ when X"0E" => keys(7)(4) <= not release; -- ` (@) ++ when X"4C" => keys(7)(5) <= not release; -- ; ++ when X"49" => keys(7)(6) <= not release; -- . ++ when X"01" => keys(7)(7) <= not release; -- F9 ++ when X"55" => keys(8)(1) <= not release; -- = (^) ++ when X"5D" => keys(8)(2) <= not release; -- # (_) ++ when X"54" => keys(8)(3) <= not release; -- [ ++ when X"52" => keys(8)(4) <= not release; -- ' ++ when X"5B" => keys(8)(5) <= not release; -- ] ++ when X"4A" => keys(8)(6) <= not release; -- / ++ when X"61" => keys(8)(7) <= not release; -- \ ++ when X"6B" => keys(9)(1) <= not release; -- LEFT ++ when X"72" => keys(9)(2) <= not release; -- DOWN ++ when X"75" => keys(9)(3) <= not release; -- UP ++ when X"5A" => keys(9)(4) <= not release; -- RETURN ++ when X"66" => keys(9)(5) <= not release; -- BACKSPACE (DELETE) ++ when X"69" => keys(9)(6) <= not release; -- END (COPY) ++ when X"74" => keys(9)(7) <= not release; -- RIGHT ++ ++ -- F12 is used for the BREAK key, which in the real BBC asserts ++ -- reset. Here we pass this out to the top level which may ++ -- optionally OR it in to the system reset ++ when X"07" => BREAK_OUT <= not release; -- F12 (BREAK) ++ ++ when others => null; ++ end case; ++ ++ end if; ++ end if; ++ end if; ++ end process; ++ ++end architecture; ++ ++ +diff --git a/m6522.vhd b/m6522.vhd +index e01ed10..5c0d341 100644 +--- a/m6522.vhd ++++ b/m6522.vhd +@@ -1,886 +1,886 @@ +---
+--- 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 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.std_logic_unsigned.all;
+- use ieee.numeric_std.all;
+-
+---library UNISIM;
+--- use UNISIM.Vcomponents.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);
+- 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);
+- 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_toggle : std_logic;
+- signal t1_irq : std_logic := '0';
+-
+- -- timer 2
+- signal t2c : std_logic_vector(15 downto 0);
+- signal t2c_active : boolean;
+- signal t2c_done : boolean;
+- signal t2_pb6 : std_logic;
+- signal t2_pb6_t1 : std_logic;
+- signal t2_w_reset_int : boolean;
+- signal t2_r_reset_int : boolean;
+- signal t2_load_counter : boolean;
+- signal t2_reload_counter : boolean;
+- 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_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_off_delay : std_logic;
+-
+- -- 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 : std_logic;
+- signal cb1_ip_reg : std_logic;
+- signal ca1_int : boolean;
+- signal cb1_int : boolean;
+- signal ca1_irq : std_logic;
+- signal cb1_irq : std_logic;
+-
+- signal ca2_ip_reg : std_logic;
+- signal cb2_ip_reg : 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 <= 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;
+-
+- if (r_acr(7) = '1') and (t1_toggle = '1') then
+- r_orb(7) <= not r_orb(7); -- toggle
+- end if;
+- end if;
+- end if;
+- end process;
+-
+- p_write_reg : process
+- begin
+- wait until rising_edge(CLK);
+- 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 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
+- begin
+- wait until rising_edge(CLK);
+-
+- if ENA_4 = '1' then
+- t1_r_reset_int <= false;
+- t2_r_reset_int <= false;
+- sr_read_ena <= false;
+- r_irb_hs <= '0';
+- r_ira_hs <= '0';
+-
+- if (cs = '1') and (I_RW_L = '1') then
+- case I_RS is
+- --when x"0" => O_DATA <= r_irb; r_irb_hs <= '1';
+- -- fix from Mark McDougall, untested
+- when x"0" => O_DATA <= (r_irb and not r_ddrb) or (r_orb and r_ddrb); r_irb_hs <= '1';
+- when x"1" => O_DATA <= r_ira; 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;
+- when x"E" => O_DATA <= ('0' & r_ier);
+- when x"F" => O_DATA <= r_ira;
+- when others => null;
+- end case;
+- end if;
+- 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 listen to the CB1_OUT for the interrupt
+- if (sr_cb1_oe_l = '1') then
+- cb1_in_mux <= I_CB1;
+- else
+- cb1_in_mux <= sr_cb1_out;
+- end if;
+- end process;
+-
+- p_ca1_cb1_int : process(r_pcr, ca1_ip_reg, I_CA1, cb1_ip_reg, cb1_in_mux)
+- begin
+- if (r_pcr(0) = '0') then -- ca1 control
+- -- negative edge
+- ca1_int <= (ca1_ip_reg = '1') and (I_CA1 = '0');
+- else
+- -- positive edge
+- ca1_int <= (ca1_ip_reg = '0') and (I_CA1 = '1');
+- end if;
+-
+- if (r_pcr(4) = '0') then -- cb1 control
+- -- negative edge
+- cb1_int <= (cb1_ip_reg = '1') and (cb1_in_mux = '0');
+- else
+- -- positive edge
+- cb1_int <= (cb1_ip_reg = '0') and (cb1_in_mux = '1');
+- end if;
+- end process;
+-
+- p_ca2_cb2_int : process(r_pcr, ca2_ip_reg, I_CA2, cb2_ip_reg, I_CB2)
+- 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 = '1') and (I_CA2 = '0');
+- else
+- -- positive edge
+- ca2_int <= (ca2_ip_reg = '0') and (I_CA2 = '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 = '1') and (I_CB2 = '0');
+- else
+- -- positive edge
+- cb2_int <= (cb2_ip_reg = '0') and (I_CB2 = '1');
+- end if;
+- end if;
+- end process;
+-
+- p_ca2_cb2 : process(RESET_L, CLK)
+- begin
+- if (RESET_L = '0') then
+- O_CA2 <= '0';
+- O_CA2_OE_L <= '1';
+- O_CB2 <= '0';
+- 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 <= '0'; -- input
+- when "001" => O_CA2 <= '0'; -- input
+- when "010" => O_CA2 <= '0'; -- input
+- when "011" => O_CA2 <= '0'; -- 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 <= '0'; -- input
+- when "001" => O_CB2 <= '0'; -- input
+- when "010" => O_CB2 <= '0'; -- input
+- when "011" => O_CB2 <= '0'; -- 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 <= '0';
+- cb1_ip_reg <= '0';
+-
+- ca2_ip_reg <= '0';
+- cb2_ip_reg <= '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 <= I_CA1;
+- cb1_ip_reg <= cb1_in_mux;
+-
+- ca2_ip_reg <= I_CA2;
+- cb2_ip_reg <= I_CB2;
+-
+- 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)
+- begin
+- -- data direction reg (ddr) 0 = input, 1 = output
+- O_PA <= r_ora;
+- O_PA_OE_L <= not r_ddra;
+-
+- if (r_acr(7) = '1') then -- not clear if r_ddrb(7) must be 1 as well
+- O_PB_OE_L(7) <= '0'; -- an output if under t1 control
+- else
+- O_PB_OE_L(7) <= not (r_ddrb(7));
+- end if;
+-
+- O_PB_OE_L(6 downto 0) <= not r_ddrb(6 downto 0);
+- O_PB(7 downto 0) <= r_orb(7 downto 0);
+-
+- end process;
+- --
+- -- Timer 1
+- --
+- p_timer1_done : process(t1c,phase,r_acr)
+- variable done : boolean;
+- begin
+- done := (t1c = x"0000");
+- t1c_done <= done and (phase = "11");
+- --if (phase = "11") then
+- t1_reload_counter <= done and (r_acr(6) = '1');
+- --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;
+- elsif (phase="11") then
+- t1c <= 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;
+- if RESET_L = '0' then
+- t1c_active <= false;
+- end if;
+-
+- t1_toggle <= '0';
+- if t1c_active and t1c_done then
+- t1_toggle <= '1';
+- t1_irq <= '1';
+- elsif RESET_L = '0' or t1_w_reset_int or t1_r_reset_int or (clear_irq(6) = '1') then
+- 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;
+-
+- p_timer2_done : process(t2c,phase)
+- variable done : boolean;
+- begin
+- done := (t2c = x"0000");
+- t2c_done <= done and (phase = "11");
+- --if (phase = "11") then
+- t2_reload_counter <= done;
+- --end if;
+- end process;
+-
+- p_timer2 : process
+- variable ena : boolean;
+- begin
+- wait until rising_edge(CLK);
+- if (ENA_4 = '1') then
+- if (r_acr(5) = '0') then
+- ena := true;
+- else
+- ena := (t2_pb6_t1 = '1') and (t2_pb6 = '0'); -- falling edge
+- end if;
+-
+- if t2_load_counter or (t2_reload_counter and phase = "11") then
+- -- 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 downto 0) <= r_t2l_l;
+- t2c(15 downto 8) <= r_t2l_h;
+- else
+- if (phase="11") and ena then -- or count mode
+- t2c <= t2c - "1";
+- end if;
+- end if;
+-
+- t2_sr_ena <= (t2c(7 downto 0) = x"00") and (phase = "11");
+-
+- if t2_load_counter then
+- t2c_active <= true;
+- elsif t2c_done then
+- t2c_active <= false;
+- end if;
+- if RESET_L = '0' then
+- t2c_active <= false;
+- end if;
+-
+- if t2c_active and t2c_done then
+- t2_irq <= '1';
+- elsif RESET_L = '0' or t2_w_reset_int or t2_r_reset_int or (clear_irq(5) = '1') then
+- 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_strobe <= '1';
+- sr_cnt <= "0000";
+- sr_irq <= '0';
+- sr_out <= '1';
+- sr_off_delay <= '0';
+- 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';
+-
+- case r_acr(4 downto 2) is
+- when "000" => ena := '0'; cb1_ip := '1';
+- when "001" => ena := '1'; cb1_op := '1'; use_t2 := '1';
+- when "010" => ena := '1'; cb1_op := '1';
+- when "011" => ena := '1'; cb1_ip := '1';
+- when "100" => ena := '1'; use_t2 := '1'; free_run := '1';
+- when "101" => ena := '1'; cb1_op := '1'; use_t2 := '1';
+- when "110" => ena := '1';
+- when "111" => ena := '1'; cb1_ip := '1';
+- when others => null;
+- end case;
+-
+- -- 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
+- 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
+- if sr_write_ena then
+- r_sr <= load_data;
+- else
+- if (dir_out = '0') then
+- -- input
+- if (sr_cnt(3) = '1') or (cb1_ip = '1') then
+- if sr_strobe_rising then
+- r_sr <= r_sr(6 downto 0) & I_CB2;
+- end if;
+- end if;
+- sr_out <= '1';
+- else
+- -- output
+- if (sr_cnt(3) = '1') or (sr_off_delay = '1') or (cb1_ip = '1') or (free_run = '1') then
+- if sr_strobe_falling then
+- r_sr(7 downto 1) <= r_sr(6 downto 0);
+- r_sr(0) <= r_sr(7);
+- sr_out <= r_sr(7);
+- end if;
+- else
+- sr_out <= '1';
+- end if;
+- end if;
+- end if;
+-
+- sr_count_ena := sr_strobe_rising;
+-
+- if sr_write_ena or sr_read_ena 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 <= sr_cnt + "1";
+- end if;
+-
+- if (phase = "00") then
+- sr_off_delay <= sr_cnt(3); -- give some hold time when shifting out
+- 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;
++-- ++-- 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 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.std_logic_unsigned.all; ++ use ieee.numeric_std.all; ++ ++--library UNISIM; ++-- use UNISIM.Vcomponents.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); ++ 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); ++ 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_toggle : std_logic; ++ signal t1_irq : std_logic := '0'; ++ ++ -- timer 2 ++ signal t2c : std_logic_vector(15 downto 0); ++ signal t2c_active : boolean; ++ signal t2c_done : boolean; ++ signal t2_pb6 : std_logic; ++ signal t2_pb6_t1 : std_logic; ++ signal t2_w_reset_int : boolean; ++ signal t2_r_reset_int : boolean; ++ signal t2_load_counter : boolean; ++ signal t2_reload_counter : boolean; ++ 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_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_off_delay : std_logic; ++ ++ -- 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 : std_logic; ++ signal cb1_ip_reg : std_logic; ++ signal ca1_int : boolean; ++ signal cb1_int : boolean; ++ signal ca1_irq : std_logic; ++ signal cb1_irq : std_logic; ++ ++ signal ca2_ip_reg : std_logic; ++ signal cb2_ip_reg : 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 <= 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; ++ ++ if (r_acr(7) = '1') and (t1_toggle = '1') then ++ r_orb(7) <= not r_orb(7); -- toggle ++ end if; ++ end if; ++ end if; ++ end process; ++ ++ p_write_reg : process ++ begin ++ wait until rising_edge(CLK); ++ 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 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 ++ begin ++ wait until rising_edge(CLK); ++ ++ if ENA_4 = '1' then ++ t1_r_reset_int <= false; ++ t2_r_reset_int <= false; ++ sr_read_ena <= false; ++ r_irb_hs <= '0'; ++ r_ira_hs <= '0'; ++ ++ if (cs = '1') and (I_RW_L = '1') then ++ case I_RS is ++ --when x"0" => O_DATA <= r_irb; r_irb_hs <= '1'; ++ -- fix from Mark McDougall, untested ++ when x"0" => O_DATA <= (r_irb and not r_ddrb) or (r_orb and r_ddrb); r_irb_hs <= '1'; ++ when x"1" => O_DATA <= r_ira; 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; ++ when x"E" => O_DATA <= ('0' & r_ier); ++ when x"F" => O_DATA <= r_ira; ++ when others => null; ++ end case; ++ end if; ++ 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 listen to the CB1_OUT for the interrupt ++ if (sr_cb1_oe_l = '1') then ++ cb1_in_mux <= I_CB1; ++ else ++ cb1_in_mux <= sr_cb1_out; ++ end if; ++ end process; ++ ++ p_ca1_cb1_int : process(r_pcr, ca1_ip_reg, I_CA1, cb1_ip_reg, cb1_in_mux) ++ begin ++ if (r_pcr(0) = '0') then -- ca1 control ++ -- negative edge ++ ca1_int <= (ca1_ip_reg = '1') and (I_CA1 = '0'); ++ else ++ -- positive edge ++ ca1_int <= (ca1_ip_reg = '0') and (I_CA1 = '1'); ++ end if; ++ ++ if (r_pcr(4) = '0') then -- cb1 control ++ -- negative edge ++ cb1_int <= (cb1_ip_reg = '1') and (cb1_in_mux = '0'); ++ else ++ -- positive edge ++ cb1_int <= (cb1_ip_reg = '0') and (cb1_in_mux = '1'); ++ end if; ++ end process; ++ ++ p_ca2_cb2_int : process(r_pcr, ca2_ip_reg, I_CA2, cb2_ip_reg, I_CB2) ++ 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 = '1') and (I_CA2 = '0'); ++ else ++ -- positive edge ++ ca2_int <= (ca2_ip_reg = '0') and (I_CA2 = '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 = '1') and (I_CB2 = '0'); ++ else ++ -- positive edge ++ cb2_int <= (cb2_ip_reg = '0') and (I_CB2 = '1'); ++ end if; ++ end if; ++ end process; ++ ++ p_ca2_cb2 : process(RESET_L, CLK) ++ begin ++ if (RESET_L = '0') then ++ O_CA2 <= '0'; ++ O_CA2_OE_L <= '1'; ++ O_CB2 <= '0'; ++ 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 <= '0'; -- input ++ when "001" => O_CA2 <= '0'; -- input ++ when "010" => O_CA2 <= '0'; -- input ++ when "011" => O_CA2 <= '0'; -- 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 <= '0'; -- input ++ when "001" => O_CB2 <= '0'; -- input ++ when "010" => O_CB2 <= '0'; -- input ++ when "011" => O_CB2 <= '0'; -- 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 <= '0'; ++ cb1_ip_reg <= '0'; ++ ++ ca2_ip_reg <= '0'; ++ cb2_ip_reg <= '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 <= I_CA1; ++ cb1_ip_reg <= cb1_in_mux; ++ ++ ca2_ip_reg <= I_CA2; ++ cb2_ip_reg <= I_CB2; ++ ++ 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) ++ begin ++ -- data direction reg (ddr) 0 = input, 1 = output ++ O_PA <= r_ora; ++ O_PA_OE_L <= not r_ddra; ++ ++ if (r_acr(7) = '1') then -- not clear if r_ddrb(7) must be 1 as well ++ O_PB_OE_L(7) <= '0'; -- an output if under t1 control ++ else ++ O_PB_OE_L(7) <= not (r_ddrb(7)); ++ end if; ++ ++ O_PB_OE_L(6 downto 0) <= not r_ddrb(6 downto 0); ++ O_PB(7 downto 0) <= r_orb(7 downto 0); ++ ++ end process; ++ -- ++ -- Timer 1 ++ -- ++ p_timer1_done : process(t1c,phase,r_acr) ++ variable done : boolean; ++ begin ++ done := (t1c = x"0000"); ++ t1c_done <= done and (phase = "11"); ++ --if (phase = "11") then ++ t1_reload_counter <= done and (r_acr(6) = '1'); ++ --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; ++ elsif (phase="11") then ++ t1c <= 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; ++ if RESET_L = '0' then ++ t1c_active <= false; ++ end if; ++ ++ t1_toggle <= '0'; ++ if t1c_active and t1c_done then ++ t1_toggle <= '1'; ++ t1_irq <= '1'; ++ elsif RESET_L = '0' or t1_w_reset_int or t1_r_reset_int or (clear_irq(6) = '1') then ++ 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; ++ ++ p_timer2_done : process(t2c,phase) ++ variable done : boolean; ++ begin ++ done := (t2c = x"0000"); ++ t2c_done <= done and (phase = "11"); ++ --if (phase = "11") then ++ t2_reload_counter <= done; ++ --end if; ++ end process; ++ ++ p_timer2 : process ++ variable ena : boolean; ++ begin ++ wait until rising_edge(CLK); ++ if (ENA_4 = '1') then ++ if (r_acr(5) = '0') then ++ ena := true; ++ else ++ ena := (t2_pb6_t1 = '1') and (t2_pb6 = '0'); -- falling edge ++ end if; ++ ++ if t2_load_counter or (t2_reload_counter and phase = "11") then ++ -- 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 downto 0) <= r_t2l_l; ++ t2c(15 downto 8) <= r_t2l_h; ++ else ++ if (phase="11") and ena then -- or count mode ++ t2c <= t2c - "1"; ++ end if; ++ end if; ++ ++ t2_sr_ena <= (t2c(7 downto 0) = x"00") and (phase = "11"); ++ ++ if t2_load_counter then ++ t2c_active <= true; ++ elsif t2c_done then ++ t2c_active <= false; ++ end if; ++ if RESET_L = '0' then ++ t2c_active <= false; ++ end if; ++ ++ if t2c_active and t2c_done then ++ t2_irq <= '1'; ++ elsif RESET_L = '0' or t2_w_reset_int or t2_r_reset_int or (clear_irq(5) = '1') then ++ 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_strobe <= '1'; ++ sr_cnt <= "0000"; ++ sr_irq <= '0'; ++ sr_out <= '1'; ++ sr_off_delay <= '0'; ++ 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'; ++ ++ case r_acr(4 downto 2) is ++ when "000" => ena := '0'; cb1_ip := '1'; ++ when "001" => ena := '1'; cb1_op := '1'; use_t2 := '1'; ++ when "010" => ena := '1'; cb1_op := '1'; ++ when "011" => ena := '1'; cb1_ip := '1'; ++ when "100" => ena := '1'; use_t2 := '1'; free_run := '1'; ++ when "101" => ena := '1'; cb1_op := '1'; use_t2 := '1'; ++ when "110" => ena := '1'; ++ when "111" => ena := '1'; cb1_ip := '1'; ++ when others => null; ++ end case; ++ ++ -- 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 ++ 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 ++ if sr_write_ena then ++ r_sr <= load_data; ++ else ++ if (dir_out = '0') then ++ -- input ++ if (sr_cnt(3) = '1') or (cb1_ip = '1') then ++ if sr_strobe_rising then ++ r_sr <= r_sr(6 downto 0) & I_CB2; ++ end if; ++ end if; ++ sr_out <= '1'; ++ else ++ -- output ++ if (sr_cnt(3) = '1') or (sr_off_delay = '1') or (cb1_ip = '1') or (free_run = '1') then ++ if sr_strobe_falling then ++ r_sr(7 downto 1) <= r_sr(6 downto 0); ++ r_sr(0) <= r_sr(7); ++ sr_out <= r_sr(7); ++ end if; ++ else ++ sr_out <= '1'; ++ end if; ++ end if; ++ end if; ++ ++ sr_count_ena := sr_strobe_rising; ++ ++ if sr_write_ena or sr_read_ena 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 <= sr_cnt + "1"; ++ end if; ++ ++ if (phase = "00") then ++ sr_off_delay <= sr_cnt(3); -- give some hold time when shifting out ++ 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; +diff --git a/m6522_tb.vhd b/m6522_tb.vhd +index 3e4262d..30307d2 100644 +--- a/m6522_tb.vhd ++++ b/m6522_tb.vhd +@@ -1,378 +1,378 @@ +--- BBC Micro for Altera DE1
+---
+--- Copyright (c) 2011 Mike Stirling
+---
+--- 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 agreement from the author.
+---
+--- * License is granted for non-commercial use only. A fee may not be charged
+--- for redistributions as source code or in synthesized/hardware form without
+--- specific prior written agreement from the author.
+---
+--- 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.
+---
+-
+-library IEEE;
+-use IEEE.STD_LOGIC_1164.ALL;
+-use IEEE.NUMERIC_STD.ALL;
+-
+-entity m6522_tb is
+-end entity;
+-
+-architecture tb of m6522_tb is
+-
+-component 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 component;
+-
+-signal rs : std_logic_vector(3 downto 0) := "0000";
+-signal di : std_logic_vector(7 downto 0) := "00000000";
+-signal do : std_logic_vector(7 downto 0);
+-signal n_d_oe : std_logic;
+-signal r_nw : std_logic := '1';
+-signal cs1 : std_logic := '0';
+-signal n_cs2 : std_logic := '0';
+-signal n_irq : std_logic;
+-signal ca1_in : std_logic := '0';
+-signal ca2_in : std_logic := '0';
+-signal ca2_out : std_logic;
+-signal n_ca2_oe : std_logic;
+-signal pa_in : std_logic_vector(7 downto 0) := "00000000";
+-signal pa_out : std_logic_vector(7 downto 0);
+-signal n_pa_oe : std_logic_vector(7 downto 0);
+-signal cb1_in : std_logic := '0';
+-signal cb1_out : std_logic;
+-signal n_cb1_oe : std_logic;
+-signal cb2_in : std_logic := '0';
+-signal cb2_out : std_logic;
+-signal n_cb2_oe : std_logic;
+-signal pb_in : std_logic_vector(7 downto 0) := "00000000";
+-signal pb_out : std_logic_vector(7 downto 0);
+-signal n_pb_oe : std_logic_vector(7 downto 0);
+-
+-signal phase2 : std_logic := '0';
+-signal n_reset : std_logic := '0';
+-signal clken : std_logic := '0';
+-signal clock : std_logic := '0';
+-
+-begin
+-
+- uut: m6522 port map (
+- rs, di, do, n_d_oe,
+- r_nw, cs1, n_cs2, n_irq,
+- ca1_in, ca2_in, ca2_out, n_ca2_oe,
+- pa_in, pa_out, n_pa_oe,
+- cb1_in, cb1_out, n_cb1_oe,
+- cb2_in, cb2_out, n_cb2_oe,
+- pb_in, pb_out, n_pb_oe,
+- phase2, n_reset, clken, clock
+- );
+-
+- clock <= not clock after 125 ns; -- 4x 1 MHz
+- phase2 <= not phase2 after 500 ns;
+- clken <= '1'; -- all cycles enabled
+-
+- process
+- begin
+- wait for 1 us;
+- -- Release reset
+- n_reset <= '1';
+- end process;
+-
+- process
+-
+- procedure reg_write(
+- a : in std_logic_vector(3 downto 0);
+- d : in std_logic_vector(7 downto 0)) is
+- begin
+- wait until falling_edge(phase2);
+- rs <= a;
+- di <= d;
+- cs1 <= '1';
+- r_nw <= '0';
+- wait until falling_edge(phase2);
+- cs1 <= '0';
+- r_nw <= '1';
+- end procedure;
+-
+- procedure reg_read(
+- a : in std_logic_vector(3 downto 0)) is
+- begin
+- wait until falling_edge(phase2);
+- rs <= a;
+- cs1 <= '1';
+- r_nw <= '1';
+- wait until falling_edge(phase2);
+- cs1 <= '0';
+- end procedure;
+-
+- begin
+- wait for 2 us;
+-
+- -- Set port A and B to output
+- reg_write("0010","11111111");
+- reg_write("0011","11111111");
+-
+- -- Write to port B
+- reg_write("0000","10101010");
+- -- Write to port B
+- reg_write("0000","01010101");
+- -- Write to port A (no handshake)
+- reg_write("1111","10101010");
+- -- Write to port A (with handshake)
+- reg_write("0001","01010101");
+-
+- -- Set port A and B to input
+- reg_write("0010","00000000");
+- reg_write("0011","00000000");
+-
+- -- Apply input stimuli and read from ports
+- pa_in <= "10101010";
+- pb_in <= "01010101";
+- reg_read("0000");
+- reg_read("0001");
+-
+- -- Test CA1 interrupt
+- ca1_in <= '0';
+- reg_write("1100","00000001"); -- PCR - interrupt on rising edge
+- reg_write("1101","01111111"); -- Clear interrupts
+- reg_write("1110","01111111"); -- Disable all interrupts
+- reg_write("1110","10000010"); -- Enable CA1 interrupt
+- ca1_in <= '1'; -- Trigger event
+- wait for 2 us;
+- reg_read("1101");
+- reg_read("0001"); -- Should clear interrupt
+- wait for 2 us;
+- reg_write("1100","00000000"); -- PCR - interrupt on falling edge
+- ca1_in <= '0'; -- Trigger event
+- wait for 2 us;
+- reg_read("1101");
+- reg_write("1101","00000010"); -- Should clear interrupt
+- wait for 2 us;
+- reg_write("1110","00000010"); -- Disable CA1 interrupt
+-
+- -- Test CB1 interrupt
+- cb1_in <= '0';
+- reg_write("1100","00010000"); -- PCR - interrupt on rising edge
+- reg_write("1101","01111111"); -- Clear interrupts
+- reg_write("1110","01111111"); -- Disable all interrupts
+- reg_write("1110","10010000"); -- Enable CB1 interrupt
+- cb1_in <= '1'; -- Trigger event
+- wait for 2 us;
+- reg_read("1101");
+- reg_read("0000"); -- Should clear interrupt
+- wait for 2 us;
+- reg_write("1100","00000000"); -- PCR - interrupt on falling edge
+- cb1_in <= '0'; -- Trigger event
+- wait for 2 us;
+- reg_read("1101");
+- reg_write("1101","00010000"); -- Should clear interrupt
+- wait for 2 us;
+- reg_write("1110","00010000"); -- Disable CA1 interrupt
+-
+- -- Test CA2 interrupt modes
+- reg_write("1101","01111111"); -- Clear interrupts
+- reg_write("1110","01111111"); -- Disable all interrupts
+- reg_write("1110","10000001"); -- Enable CA2 interrupt
+- -- mode 2 (+ve edge, clear on read/write)
+- reg_write("1100","00000100"); -- PCR
+- ca2_in <= '1'; -- Trigger event
+- wait for 2 us;
+- reg_read("1101");
+- reg_read("1111"); -- Should not clear interrupt
+- reg_read("0001"); -- Should clear interrupt
+- wait for 2 us;
+- -- mode 0 (-ve edge, clear on read/write)
+- reg_write("1100","00000000"); -- PCR
+- ca2_in <= '0'; -- Trigger event
+- wait for 2 us;
+- reg_read("1101");
+- reg_read("1111"); -- Should not clear interrupt
+- reg_read("0001"); -- Should clear interrupt
+- wait for 2 us;
+- -- mode 3 (+ve edge, don't clear on read/write)
+- reg_write("1100","00000110");
+- ca2_in <= '1'; -- Trigger event
+- wait for 2 us;
+- reg_read("1101");
+- reg_read("1111"); -- Should not clear interrupt
+- reg_read("0001"); -- Should not clear interrupt
+- reg_write("1101","00000001"); -- Should clear interrupt
+- wait for 2 us;
+- -- mode 1 (-ve edge, don't clear on read/write)
+- reg_write("1100","00000010");
+- ca2_in <= '0'; -- Trigger event
+- wait for 2 us;
+- reg_read("1101");
+- reg_read("1111"); -- Should not clear interrupt
+- reg_read("0001"); -- Should not clear interrupt
+- reg_write("1101","00000001"); -- Should clear interrupt
+- wait for 2 us;
+-
+- -- Test CA2 output modes
+- -- mode 4 (set low on read/write of ORA, set high on CA1 interrupt edge)
+- reg_write("1100","00001000");
+- -- mode 5 (set low for 1 cycle on read/write ORA)
+- reg_write("1100","00001010");
+- -- mode 6 (held low)
+- reg_write("1100","00001100");
+- -- mode 7 (held high)
+- reg_write("1100","00001110");
+-
+- -- Test CB2 interrupt modes
+- reg_write("1101","01111111"); -- Clear interrupts
+- reg_write("1110","01111111"); -- Disable all interrupts
+- reg_write("1110","10001000"); -- Enable CB2 interrupt
+- -- mode 2 (+ve edge, clear on read/write)
+- reg_write("1100","01000000"); -- PCR
+- cb2_in <= '1'; -- Trigger event
+- wait for 2 us;
+- reg_read("1101");
+- reg_read("0000"); -- Should clear interrupt
+- wait for 2 us;
+- -- mode 0 (-ve edge, clear on read/write)
+- reg_write("1100","00000000"); -- PCR
+- cb2_in <= '0'; -- Trigger event
+- wait for 2 us;
+- reg_read("1101");
+- reg_read("0000"); -- Should clear interrupt
+- wait for 2 us;
+- -- mode 3 (+ve edge, don't clear on read/write)
+- reg_write("1100","01100000");
+- cb2_in <= '1'; -- Trigger event
+- wait for 2 us;
+- reg_read("1101");
+- reg_read("0000"); -- Should not clear interrupt
+- reg_write("1101","00001000"); -- Should clear interrupt
+- wait for 2 us;
+- -- mode 1 (-ve edge, don't clear on read/write)
+- reg_write("1100","00100000");
+- cb2_in <= '0'; -- Trigger event
+- wait for 2 us;
+- reg_read("1101");
+- reg_read("0000"); -- Should not clear interrupt
+- reg_write("1101","00001000"); -- Should clear interrupt
+- wait for 2 us;
+-
+- -- Test CB2 output modes
+- -- mode 4 (set low on read/write of ORA, set high on CA1 interrupt edge)
+- reg_write("1100","10000000");
+- -- mode 5 (set low for 1 cycle on read/write ORA)
+- reg_write("1100","10100000");
+- -- mode 6 (held low)
+- reg_write("1100","11000000");
+- -- mode 7 (held high)
+- reg_write("1100","11100000");
+-
+- -- Timer 1 timeout
+- reg_write("1101","01111111"); -- Clear interrupts
+- reg_write("1110","01111111"); -- Disable all interrupts
+- reg_write("1110","11000000"); -- Enable timer 1 interrupt
+- -- Count to 16
+- reg_write("0100","00010000");
+- reg_write("0101","00000000");
+- wait for 50 us;
+- -- Count to 16
+- reg_write("0100","00010000");
+- reg_write("0101","00000000"); -- Should clear interrupt
+- wait for 50 us;
+- reg_read("0100"); -- Should clear interrupt
+-
+- -- Timer 2 timeout
+- reg_write("1101","01111111"); -- Clear interrupts
+- reg_write("1110","01111111"); -- Disable all interrupts
+- reg_write("1110","10100000"); -- Enable timer 2 interrupt
+- -- Count to 16
+- reg_write("1000","00010000");
+- reg_write("1001","00000000");
+- wait for 50 us;
+- -- Count to 16
+- reg_write("1000","00010000");
+- reg_write("1001","00000000"); -- Should clear interrupt
+- wait for 50 us;
+- reg_read("1000"); -- Should clear interrupt
+-
+- -- Timer 2 test similar to BBC usage (speech interrupt)
+- -- PB6 high
+- pb_in(6) <= '1';
+- reg_write("1101","01111111"); -- Clear interrupts
+- reg_write("1110","01111111"); -- Disable all interrupts
+- reg_write("1011","00100000"); -- Timer 2 PB6 counter mode
+- reg_write("1000","00000001"); -- Start at 1
+- reg_write("1001","00000000");
+- reg_write("1110","10100000"); -- Enable timer 2 interrupt
+- wait for 5 us;
+- -- Generate falling edge
+- pb_in(6) <= '0';
+- wait for 5 us;
+- -- Clear interrupt
+- reg_write("1101","00100000");
+- -- Zero timer high byte
+- reg_write("1001","00000000");
+-
+- wait;
+- end process;
+-
+-end architecture;
++-- BBC Micro for Altera DE1 ++-- ++-- Copyright (c) 2011 Mike Stirling ++-- ++-- 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 agreement from the author. ++-- ++-- * License is granted for non-commercial use only. A fee may not be charged ++-- for redistributions as source code or in synthesized/hardware form without ++-- specific prior written agreement from the author. ++-- ++-- 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. ++-- ++ ++library IEEE; ++use IEEE.STD_LOGIC_1164.ALL; ++use IEEE.NUMERIC_STD.ALL; ++ ++entity m6522_tb is ++end entity; ++ ++architecture tb of m6522_tb is ++ ++component 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 component; ++ ++signal rs : std_logic_vector(3 downto 0) := "0000"; ++signal di : std_logic_vector(7 downto 0) := "00000000"; ++signal do : std_logic_vector(7 downto 0); ++signal n_d_oe : std_logic; ++signal r_nw : std_logic := '1'; ++signal cs1 : std_logic := '0'; ++signal n_cs2 : std_logic := '0'; ++signal n_irq : std_logic; ++signal ca1_in : std_logic := '0'; ++signal ca2_in : std_logic := '0'; ++signal ca2_out : std_logic; ++signal n_ca2_oe : std_logic; ++signal pa_in : std_logic_vector(7 downto 0) := "00000000"; ++signal pa_out : std_logic_vector(7 downto 0); ++signal n_pa_oe : std_logic_vector(7 downto 0); ++signal cb1_in : std_logic := '0'; ++signal cb1_out : std_logic; ++signal n_cb1_oe : std_logic; ++signal cb2_in : std_logic := '0'; ++signal cb2_out : std_logic; ++signal n_cb2_oe : std_logic; ++signal pb_in : std_logic_vector(7 downto 0) := "00000000"; ++signal pb_out : std_logic_vector(7 downto 0); ++signal n_pb_oe : std_logic_vector(7 downto 0); ++ ++signal phase2 : std_logic := '0'; ++signal n_reset : std_logic := '0'; ++signal clken : std_logic := '0'; ++signal clock : std_logic := '0'; ++ ++begin ++ ++ uut: m6522 port map ( ++ rs, di, do, n_d_oe, ++ r_nw, cs1, n_cs2, n_irq, ++ ca1_in, ca2_in, ca2_out, n_ca2_oe, ++ pa_in, pa_out, n_pa_oe, ++ cb1_in, cb1_out, n_cb1_oe, ++ cb2_in, cb2_out, n_cb2_oe, ++ pb_in, pb_out, n_pb_oe, ++ phase2, n_reset, clken, clock ++ ); ++ ++ clock <= not clock after 125 ns; -- 4x 1 MHz ++ phase2 <= not phase2 after 500 ns; ++ clken <= '1'; -- all cycles enabled ++ ++ process ++ begin ++ wait for 1 us; ++ -- Release reset ++ n_reset <= '1'; ++ end process; ++ ++ process ++ ++ procedure reg_write( ++ a : in std_logic_vector(3 downto 0); ++ d : in std_logic_vector(7 downto 0)) is ++ begin ++ wait until falling_edge(phase2); ++ rs <= a; ++ di <= d; ++ cs1 <= '1'; ++ r_nw <= '0'; ++ wait until falling_edge(phase2); ++ cs1 <= '0'; ++ r_nw <= '1'; ++ end procedure; ++ ++ procedure reg_read( ++ a : in std_logic_vector(3 downto 0)) is ++ begin ++ wait until falling_edge(phase2); ++ rs <= a; ++ cs1 <= '1'; ++ r_nw <= '1'; ++ wait until falling_edge(phase2); ++ cs1 <= '0'; ++ end procedure; ++ ++ begin ++ wait for 2 us; ++ ++ -- Set port A and B to output ++ reg_write("0010","11111111"); ++ reg_write("0011","11111111"); ++ ++ -- Write to port B ++ reg_write("0000","10101010"); ++ -- Write to port B ++ reg_write("0000","01010101"); ++ -- Write to port A (no handshake) ++ reg_write("1111","10101010"); ++ -- Write to port A (with handshake) ++ reg_write("0001","01010101"); ++ ++ -- Set port A and B to input ++ reg_write("0010","00000000"); ++ reg_write("0011","00000000"); ++ ++ -- Apply input stimuli and read from ports ++ pa_in <= "10101010"; ++ pb_in <= "01010101"; ++ reg_read("0000"); ++ reg_read("0001"); ++ ++ -- Test CA1 interrupt ++ ca1_in <= '0'; ++ reg_write("1100","00000001"); -- PCR - interrupt on rising edge ++ reg_write("1101","01111111"); -- Clear interrupts ++ reg_write("1110","01111111"); -- Disable all interrupts ++ reg_write("1110","10000010"); -- Enable CA1 interrupt ++ ca1_in <= '1'; -- Trigger event ++ wait for 2 us; ++ reg_read("1101"); ++ reg_read("0001"); -- Should clear interrupt ++ wait for 2 us; ++ reg_write("1100","00000000"); -- PCR - interrupt on falling edge ++ ca1_in <= '0'; -- Trigger event ++ wait for 2 us; ++ reg_read("1101"); ++ reg_write("1101","00000010"); -- Should clear interrupt ++ wait for 2 us; ++ reg_write("1110","00000010"); -- Disable CA1 interrupt ++ ++ -- Test CB1 interrupt ++ cb1_in <= '0'; ++ reg_write("1100","00010000"); -- PCR - interrupt on rising edge ++ reg_write("1101","01111111"); -- Clear interrupts ++ reg_write("1110","01111111"); -- Disable all interrupts ++ reg_write("1110","10010000"); -- Enable CB1 interrupt ++ cb1_in <= '1'; -- Trigger event ++ wait for 2 us; ++ reg_read("1101"); ++ reg_read("0000"); -- Should clear interrupt ++ wait for 2 us; ++ reg_write("1100","00000000"); -- PCR - interrupt on falling edge ++ cb1_in <= '0'; -- Trigger event ++ wait for 2 us; ++ reg_read("1101"); ++ reg_write("1101","00010000"); -- Should clear interrupt ++ wait for 2 us; ++ reg_write("1110","00010000"); -- Disable CA1 interrupt ++ ++ -- Test CA2 interrupt modes ++ reg_write("1101","01111111"); -- Clear interrupts ++ reg_write("1110","01111111"); -- Disable all interrupts ++ reg_write("1110","10000001"); -- Enable CA2 interrupt ++ -- mode 2 (+ve edge, clear on read/write) ++ reg_write("1100","00000100"); -- PCR ++ ca2_in <= '1'; -- Trigger event ++ wait for 2 us; ++ reg_read("1101"); ++ reg_read("1111"); -- Should not clear interrupt ++ reg_read("0001"); -- Should clear interrupt ++ wait for 2 us; ++ -- mode 0 (-ve edge, clear on read/write) ++ reg_write("1100","00000000"); -- PCR ++ ca2_in <= '0'; -- Trigger event ++ wait for 2 us; ++ reg_read("1101"); ++ reg_read("1111"); -- Should not clear interrupt ++ reg_read("0001"); -- Should clear interrupt ++ wait for 2 us; ++ -- mode 3 (+ve edge, don't clear on read/write) ++ reg_write("1100","00000110"); ++ ca2_in <= '1'; -- Trigger event ++ wait for 2 us; ++ reg_read("1101"); ++ reg_read("1111"); -- Should not clear interrupt ++ reg_read("0001"); -- Should not clear interrupt ++ reg_write("1101","00000001"); -- Should clear interrupt ++ wait for 2 us; ++ -- mode 1 (-ve edge, don't clear on read/write) ++ reg_write("1100","00000010"); ++ ca2_in <= '0'; -- Trigger event ++ wait for 2 us; ++ reg_read("1101"); ++ reg_read("1111"); -- Should not clear interrupt ++ reg_read("0001"); -- Should not clear interrupt ++ reg_write("1101","00000001"); -- Should clear interrupt ++ wait for 2 us; ++ ++ -- Test CA2 output modes ++ -- mode 4 (set low on read/write of ORA, set high on CA1 interrupt edge) ++ reg_write("1100","00001000"); ++ -- mode 5 (set low for 1 cycle on read/write ORA) ++ reg_write("1100","00001010"); ++ -- mode 6 (held low) ++ reg_write("1100","00001100"); ++ -- mode 7 (held high) ++ reg_write("1100","00001110"); ++ ++ -- Test CB2 interrupt modes ++ reg_write("1101","01111111"); -- Clear interrupts ++ reg_write("1110","01111111"); -- Disable all interrupts ++ reg_write("1110","10001000"); -- Enable CB2 interrupt ++ -- mode 2 (+ve edge, clear on read/write) ++ reg_write("1100","01000000"); -- PCR ++ cb2_in <= '1'; -- Trigger event ++ wait for 2 us; ++ reg_read("1101"); ++ reg_read("0000"); -- Should clear interrupt ++ wait for 2 us; ++ -- mode 0 (-ve edge, clear on read/write) ++ reg_write("1100","00000000"); -- PCR ++ cb2_in <= '0'; -- Trigger event ++ wait for 2 us; ++ reg_read("1101"); ++ reg_read("0000"); -- Should clear interrupt ++ wait for 2 us; ++ -- mode 3 (+ve edge, don't clear on read/write) ++ reg_write("1100","01100000"); ++ cb2_in <= '1'; -- Trigger event ++ wait for 2 us; ++ reg_read("1101"); ++ reg_read("0000"); -- Should not clear interrupt ++ reg_write("1101","00001000"); -- Should clear interrupt ++ wait for 2 us; ++ -- mode 1 (-ve edge, don't clear on read/write) ++ reg_write("1100","00100000"); ++ cb2_in <= '0'; -- Trigger event ++ wait for 2 us; ++ reg_read("1101"); ++ reg_read("0000"); -- Should not clear interrupt ++ reg_write("1101","00001000"); -- Should clear interrupt ++ wait for 2 us; ++ ++ -- Test CB2 output modes ++ -- mode 4 (set low on read/write of ORA, set high on CA1 interrupt edge) ++ reg_write("1100","10000000"); ++ -- mode 5 (set low for 1 cycle on read/write ORA) ++ reg_write("1100","10100000"); ++ -- mode 6 (held low) ++ reg_write("1100","11000000"); ++ -- mode 7 (held high) ++ reg_write("1100","11100000"); ++ ++ -- Timer 1 timeout ++ reg_write("1101","01111111"); -- Clear interrupts ++ reg_write("1110","01111111"); -- Disable all interrupts ++ reg_write("1110","11000000"); -- Enable timer 1 interrupt ++ -- Count to 16 ++ reg_write("0100","00010000"); ++ reg_write("0101","00000000"); ++ wait for 50 us; ++ -- Count to 16 ++ reg_write("0100","00010000"); ++ reg_write("0101","00000000"); -- Should clear interrupt ++ wait for 50 us; ++ reg_read("0100"); -- Should clear interrupt ++ ++ -- Timer 2 timeout ++ reg_write("1101","01111111"); -- Clear interrupts ++ reg_write("1110","01111111"); -- Disable all interrupts ++ reg_write("1110","10100000"); -- Enable timer 2 interrupt ++ -- Count to 16 ++ reg_write("1000","00010000"); ++ reg_write("1001","00000000"); ++ wait for 50 us; ++ -- Count to 16 ++ reg_write("1000","00010000"); ++ reg_write("1001","00000000"); -- Should clear interrupt ++ wait for 50 us; ++ reg_read("1000"); -- Should clear interrupt ++ ++ -- Timer 2 test similar to BBC usage (speech interrupt) ++ -- PB6 high ++ pb_in(6) <= '1'; ++ reg_write("1101","01111111"); -- Clear interrupts ++ reg_write("1110","01111111"); -- Disable all interrupts ++ reg_write("1011","00100000"); -- Timer 2 PB6 counter mode ++ reg_write("1000","00000001"); -- Start at 1 ++ reg_write("1001","00000000"); ++ reg_write("1110","10100000"); -- Enable timer 2 interrupt ++ wait for 5 us; ++ -- Generate falling edge ++ pb_in(6) <= '0'; ++ wait for 5 us; ++ -- Clear interrupt ++ reg_write("1101","00100000"); ++ -- Zero timer high byte ++ reg_write("1001","00000000"); ++ ++ wait; ++ end process; ++ ++end architecture; +diff --git a/mc6845.vhd b/mc6845.vhd +index 31208ea..c102501 100644 +--- a/mc6845.vhd ++++ b/mc6845.vhd +@@ -1,481 +1,481 @@ +--- BBC Micro for Altera DE1
+---
+--- Copyright (c) 2011 Mike Stirling
+---
+--- 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 agreement from the author.
+---
+--- * License is granted for non-commercial use only. A fee may not be charged
+--- for redistributions as source code or in synthesized/hardware form without
+--- specific prior written agreement from the author.
+---
+--- 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.
+---
+--- MC6845 CRTC
+---
+--- Synchronous implementation for FPGA
+---
+--- (C) 2011 Mike Stirling
+---
+-library IEEE;
+-use IEEE.STD_LOGIC_1164.ALL;
+-use IEEE.NUMERIC_STD.ALL;
+-
+-entity mc6845 is
+-port (
+- CLOCK : in std_logic;
+- CLKEN : in std_logic;
+- nRESET : in std_logic;
+-
+- -- Bus interface
+- ENABLE : in std_logic;
+- R_nW : in std_logic;
+- RS : in std_logic;
+- DI : in std_logic_vector(7 downto 0);
+- DO : out std_logic_vector(7 downto 0);
+-
+- -- Display interface
+- VSYNC : out std_logic;
+- HSYNC : out std_logic;
+- DE : out std_logic;
+- CURSOR : out std_logic;
+- LPSTB : in std_logic;
+-
+- -- Memory interface
+- MA : out std_logic_vector(13 downto 0);
+- RA : out std_logic_vector(4 downto 0)
+- );
+-end entity;
+-
+-architecture rtl of mc6845 is
+-
+--- Host-accessible registers
+-signal addr_reg : std_logic_vector(4 downto 0); -- Currently addressed register
+--- These are write-only
+-signal r00_h_total : unsigned(7 downto 0); -- Horizontal total, chars
+-signal r01_h_displayed : unsigned(7 downto 0); -- Horizontal active, chars
+-signal r02_h_sync_pos : unsigned(7 downto 0); -- Horizontal sync position, chars
+-signal r03_v_sync_width : unsigned(3 downto 0); -- Vertical sync width, scan lines (0=16 lines)
+-signal r03_h_sync_width : unsigned(3 downto 0); -- Horizontal sync width, chars (0=no sync)
+-signal r04_v_total : unsigned(6 downto 0); -- Vertical total, character rows
+-signal r05_v_total_adj : unsigned(4 downto 0); -- Vertical offset, scan lines
+-signal r06_v_displayed : unsigned(6 downto 0); -- Vertical active, character rows
+-signal r07_v_sync_pos : unsigned(6 downto 0); -- Vertical sync position, character rows
+-signal r08_interlace : std_logic_vector(1 downto 0);
+-signal r09_max_scan_line_addr : unsigned(4 downto 0);
+-signal r10_cursor_mode : std_logic_vector(1 downto 0);
+-signal r10_cursor_start : unsigned(4 downto 0); -- Cursor start, scan lines
+-signal r11_cursor_end : unsigned(4 downto 0); -- Cursor end, scan lines
+-signal r12_start_addr_h : unsigned(5 downto 0);
+-signal r13_start_addr_l : unsigned(7 downto 0);
+--- These are read/write
+-signal r14_cursor_h : unsigned(5 downto 0);
+-signal r15_cursor_l : unsigned(7 downto 0);
+--- These are read-only
+-signal r16_light_pen_h : unsigned(5 downto 0);
+-signal r17_light_pen_l : unsigned(7 downto 0);
+-
+-
+--- Timing generation
+--- Horizontal counter counts position on line
+-signal h_counter : unsigned(7 downto 0);
+--- HSYNC counter counts duration of sync pulse
+-signal h_sync_counter : unsigned(3 downto 0);
+--- Row counter counts current character row
+-signal row_counter : unsigned(6 downto 0);
+--- Line counter counts current line within each character row
+-signal line_counter : unsigned(4 downto 0);
+--- VSYNC counter counts duration of sync pulse
+-signal v_sync_counter : unsigned(3 downto 0);
+--- Field counter counts number of complete fields for cursor flash
+-signal field_counter : unsigned(5 downto 0);
+-
+--- Internal signals
+-signal h_sync_start : std_logic;
+-signal h_half_way : std_logic;
+-signal h_display : std_logic;
+-signal hs : std_logic;
+-signal v_display : std_logic;
+-signal vs : std_logic;
+-signal odd_field : std_logic;
+-signal ma_i : unsigned(13 downto 0);
+-signal ma_row_start : unsigned(13 downto 0); -- Start address of current character row
+-signal cursor_i : std_logic;
+-signal lpstb_i : std_logic;
+-
+-
+-begin
+- HSYNC <= hs; -- External HSYNC driven directly from internal signal
++-- BBC Micro for Altera DE1 ++-- ++-- Copyright (c) 2011 Mike Stirling ++-- ++-- 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 agreement from the author. ++-- ++-- * License is granted for non-commercial use only. A fee may not be charged ++-- for redistributions as source code or in synthesized/hardware form without ++-- specific prior written agreement from the author. ++-- ++-- 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. ++-- ++-- MC6845 CRTC ++-- ++-- Synchronous implementation for FPGA ++-- ++-- (C) 2011 Mike Stirling ++-- ++library IEEE; ++use IEEE.STD_LOGIC_1164.ALL; ++use IEEE.NUMERIC_STD.ALL; ++ ++entity mc6845 is ++port ( ++ CLOCK : in std_logic; ++ CLKEN : in std_logic; ++ nRESET : in std_logic; ++ ++ -- Bus interface ++ ENABLE : in std_logic; ++ R_nW : in std_logic; ++ RS : in std_logic; ++ DI : in std_logic_vector(7 downto 0); ++ DO : out std_logic_vector(7 downto 0); ++ ++ -- Display interface ++ VSYNC : out std_logic; ++ HSYNC : out std_logic; ++ DE : out std_logic; ++ CURSOR : out std_logic; ++ LPSTB : in std_logic; ++ ++ -- Memory interface ++ MA : out std_logic_vector(13 downto 0); ++ RA : out std_logic_vector(4 downto 0) ++ ); ++end entity; ++ ++architecture rtl of mc6845 is ++ ++-- Host-accessible registers ++signal addr_reg : std_logic_vector(4 downto 0); -- Currently addressed register ++-- These are write-only ++signal r00_h_total : unsigned(7 downto 0); -- Horizontal total, chars ++signal r01_h_displayed : unsigned(7 downto 0); -- Horizontal active, chars ++signal r02_h_sync_pos : unsigned(7 downto 0); -- Horizontal sync position, chars ++signal r03_v_sync_width : unsigned(3 downto 0); -- Vertical sync width, scan lines (0=16 lines) ++signal r03_h_sync_width : unsigned(3 downto 0); -- Horizontal sync width, chars (0=no sync) ++signal r04_v_total : unsigned(6 downto 0); -- Vertical total, character rows ++signal r05_v_total_adj : unsigned(4 downto 0); -- Vertical offset, scan lines ++signal r06_v_displayed : unsigned(6 downto 0); -- Vertical active, character rows ++signal r07_v_sync_pos : unsigned(6 downto 0); -- Vertical sync position, character rows ++signal r08_interlace : std_logic_vector(1 downto 0); ++signal r09_max_scan_line_addr : unsigned(4 downto 0); ++signal r10_cursor_mode : std_logic_vector(1 downto 0); ++signal r10_cursor_start : unsigned(4 downto 0); -- Cursor start, scan lines ++signal r11_cursor_end : unsigned(4 downto 0); -- Cursor end, scan lines ++signal r12_start_addr_h : unsigned(5 downto 0); ++signal r13_start_addr_l : unsigned(7 downto 0); ++-- These are read/write ++signal r14_cursor_h : unsigned(5 downto 0); ++signal r15_cursor_l : unsigned(7 downto 0); ++-- These are read-only ++signal r16_light_pen_h : unsigned(5 downto 0); ++signal r17_light_pen_l : unsigned(7 downto 0); ++ ++ ++-- Timing generation ++-- Horizontal counter counts position on line ++signal h_counter : unsigned(7 downto 0); ++-- HSYNC counter counts duration of sync pulse ++signal h_sync_counter : unsigned(3 downto 0); ++-- Row counter counts current character row ++signal row_counter : unsigned(6 downto 0); ++-- Line counter counts current line within each character row ++signal line_counter : unsigned(4 downto 0); ++-- VSYNC counter counts duration of sync pulse ++signal v_sync_counter : unsigned(3 downto 0); ++-- Field counter counts number of complete fields for cursor flash ++signal field_counter : unsigned(5 downto 0); ++ ++-- Internal signals ++signal h_sync_start : std_logic; ++signal h_half_way : std_logic; ++signal h_display : std_logic; ++signal hs : std_logic; ++signal v_display : std_logic; ++signal vs : std_logic; ++signal odd_field : std_logic; ++signal ma_i : unsigned(13 downto 0); ++signal ma_row_start : unsigned(13 downto 0); -- Start address of current character row ++signal cursor_i : std_logic; ++signal lpstb_i : std_logic; ++ ++ ++begin ++ HSYNC <= hs; -- External HSYNC driven directly from internal signal + VSYNC <= vs; -- External VSYNC driven directly from internal signal +- DE <= h_display and v_display;
+-
+- -- Cursor output generated combinatorially from the internal signal in
+- -- accordance with the currently selected cursor mode
+- CURSOR <= cursor_i when r10_cursor_mode = "00" else
+- '0' when r10_cursor_mode = "01" else
+- (cursor_i and field_counter(4)) when r10_cursor_mode = "10" else
+- (cursor_i and field_counter(5));
+-
+- -- Synchronous register access. Enabled on every clock.
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- -- Reset registers to defaults
+- addr_reg <= (others => '0');
+- r00_h_total <= (others => '0');
+- r01_h_displayed <= (others => '0');
+- r02_h_sync_pos <= (others => '0');
+- r03_v_sync_width <= (others => '0');
+- r03_h_sync_width <= (others => '0');
+- r04_v_total <= (others => '0');
+- r05_v_total_adj <= (others => '0');
+- r06_v_displayed <= (others => '0');
+- r07_v_sync_pos <= (others => '0');
+- r08_interlace <= (others => '0');
+- r09_max_scan_line_addr <= (others => '0');
+- r10_cursor_mode <= (others => '0');
+- r10_cursor_start <= (others => '0');
+- r11_cursor_end <= (others => '0');
+- r12_start_addr_h <= (others => '0');
+- r13_start_addr_l <= (others => '0');
+- r14_cursor_h <= (others => '0');
+- r15_cursor_l <= (others => '0');
+-
+- DO <= (others => '0');
+- elsif rising_edge(CLOCK) then
+- if ENABLE = '1' then
+- if R_nW = '1' then
+- -- Read
+- case addr_reg is
+- when "01110" =>
+- DO <= "00" & std_logic_vector(r14_cursor_h);
+- when "01111" =>
+- DO <= std_logic_vector(r15_cursor_l);
+- when "10000" =>
+- DO <= "00" & std_logic_vector(r16_light_pen_h);
+- when "10001" =>
+- DO <= std_logic_vector(r17_light_pen_l);
+- when others =>
+- DO <= (others => '0');
+- end case;
+- else
+- -- Write
+- if RS = '0' then
+- addr_reg <= DI(4 downto 0);
+- else
+- case addr_reg is
+- when "00000" =>
+- r00_h_total <= unsigned(DI);
+- when "00001" =>
+- r01_h_displayed <= unsigned(DI);
+- when "00010" =>
+- r02_h_sync_pos <= unsigned(DI);
+- when "00011" =>
+- r03_v_sync_width <= unsigned(DI(7 downto 4));
+- r03_h_sync_width <= unsigned(DI(3 downto 0));
+- when "00100" =>
+- r04_v_total <= unsigned(DI(6 downto 0));
+- when "00101" =>
+- r05_v_total_adj <= unsigned(DI(4 downto 0));
+- when "00110" =>
+- r06_v_displayed <= unsigned(DI(6 downto 0));
+- when "00111" =>
+- r07_v_sync_pos <= unsigned(DI(6 downto 0));
+- when "01000" =>
+- r08_interlace <= DI(1 downto 0);
+- when "01001" =>
+- r09_max_scan_line_addr <= unsigned(DI(4 downto 0));
+- when "01010" =>
+- r10_cursor_mode <= DI(6 downto 5);
+- r10_cursor_start <= unsigned(DI(4 downto 0));
+- when "01011" =>
+- r11_cursor_end <= unsigned(DI(4 downto 0));
+- when "01100" =>
+- r12_start_addr_h <= unsigned(DI(5 downto 0));
+- when "01101" =>
+- r13_start_addr_l <= unsigned(DI(7 downto 0));
+- when "01110" =>
+- r14_cursor_h <= unsigned(DI(5 downto 0));
+- when "01111" =>
+- r15_cursor_l <= unsigned(DI(7 downto 0));
+- when others =>
+- null;
+- end case;
+- end if;
+- end if;
+- end if;
+- end if;
+- end process; -- registers
+-
+- -- Horizontal, vertical and address counters
+- process(CLOCK,nRESET)
+- variable ma_row_start : unsigned(13 downto 0);
+- variable max_scan_line : unsigned(4 downto 0);
+- begin
+- if nRESET = '0' then
+- -- H
+- h_counter <= (others => '0');
+-
+- -- V
+- line_counter <= (others => '0');
+- row_counter <= (others => '0');
+- odd_field <= '0';
+-
+- -- Fields (cursor flash)
+- field_counter <= (others => '0');
+-
+- -- Addressing
+- ma_row_start := (others => '0');
+- ma_i <= (others => '0');
+- elsif rising_edge(CLOCK) and CLKEN='1' then
+- -- Horizontal counter increments on each clock, wrapping at
+- -- h_total
+- if h_counter = r00_h_total then
+- -- h_total reached
+- h_counter <= (others => '0');
+-
+- -- In interlace sync + video mode mask off the LSb of the
+- -- max scan line address
+- if r08_interlace = "11" then
+- max_scan_line := r09_max_scan_line_addr(4 downto 1) & "0";
+- else
+- max_scan_line := r09_max_scan_line_addr;
+- end if;
+-
+- -- Scan line counter increments, wrapping at max_scan_line_addr
+- if line_counter = max_scan_line then
+- -- Next character row
+- -- FIXME: No support for v_total_adj yet
+- line_counter <= (others => '0');
+- if row_counter = r04_v_total then
+- -- If in interlace mode we toggle to the opposite field.
+- -- Save on some logic by doing this here rather than at the
+- -- end of v_total_adj - it shouldn't make any difference to the
+- -- output
+- if r08_interlace(0) = '1' then
+- odd_field <= not odd_field;
+- else
+- odd_field <= '0';
+- end if;
+-
+- -- Address is loaded from start address register at the top of
+- -- each field and the row counter is reset
+- ma_row_start := r12_start_addr_h & r13_start_addr_l;
+- row_counter <= (others => '0');
+-
+- -- Increment field counter
+- field_counter <= field_counter + 1;
+- else
+- -- On all other character rows within the field the row start address is
+- -- increased by h_displayed and the row counter is incremented
+- ma_row_start := ma_row_start + r01_h_displayed;
+- row_counter <= row_counter + 1;
+- end if;
+- else
+- -- Next scan line. Count in twos in interlaced sync+video mode
+- if r08_interlace = "11" then
+- line_counter <= line_counter + 2;
+- line_counter(0) <= '0'; -- Force to even
+- else
+- line_counter <= line_counter + 1;
+- end if;
+- end if;
+-
+- -- Memory address preset to row start at the beginning of each
+- -- scan line
+- ma_i <= ma_row_start;
+- else
+- -- Increment horizontal counter
+- h_counter <= h_counter + 1;
+- -- Increment memory address
+- ma_i <= ma_i + 1;
+- end if;
+- end if;
+- end process;
+-
+- -- Signals to mark hsync and half way points for generating
+- -- vsync in even and odd fields
+- process(h_counter)
+- begin
+- h_sync_start <= '0';
+- h_half_way <= '0';
+-
+- if h_counter = r02_h_sync_pos then
+- h_sync_start <= '1';
+- end if;
+- if h_counter = "0" & r02_h_sync_pos(7 downto 1) then
+- h_half_way <= '1';
+- end if;
+- end process;
+-
+- -- Video timing and sync counters
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- -- H
+- h_display <= '0';
+- hs <= '0';
+- h_sync_counter <= (others => '0');
+-
+- -- V
+- v_display <= '0';
+- vs <= '0';
+- v_sync_counter <= (others => '0');
+- elsif rising_edge(CLOCK) and CLKEN = '1' then
+- -- Horizontal active video
+- if h_counter = 0 then
+- -- Start of active video
+- h_display <= '1';
+- end if;
+- if h_counter = r01_h_displayed then
+- -- End of active video
+- h_display <= '0';
+- end if;
+-
+- -- Horizontal sync
+- if h_sync_start = '1' or hs = '1' then
+- -- In horizontal sync
+- hs <= '1';
+- h_sync_counter <= h_sync_counter + 1;
+- else
+- h_sync_counter <= (others => '0');
+- end if;
+- if h_sync_counter = r03_h_sync_width then
+- -- Terminate hsync after h_sync_width (0 means no hsync so this
+- -- can immediately override the setting above)
+- hs <= '0';
+- end if;
+-
+- -- Vertical active video
+- if row_counter = 0 then
+- -- Start of active video
+- v_display <= '1';
+- end if;
+- if row_counter = r06_v_displayed then
+- -- End of active video
+- v_display <= '0';
+- end if;
+-
+- -- Vertical sync occurs either at the same time as the horizontal sync (even fields)
+- -- or half a line later (odd fields)
+- if (odd_field = '0' and h_sync_start = '1') or (odd_field = '1' and h_half_way = '1') then
+- if (row_counter = r07_v_sync_pos and line_counter = 0) or vs = '1' then
+- -- In vertical sync
+- vs <= '1';
+- v_sync_counter <= v_sync_counter + 1;
+- else
+- v_sync_counter <= (others => '0');
+- end if;
+- if v_sync_counter = r03_v_sync_width and vs = '1' then
+- -- Terminate vsync after v_sync_width (0 means 16 lines so this is
+- -- masked by 'vs' to ensure a full turn of the counter in this case)
+- vs <= '0';
+- end if;
+- end if;
+- end if;
+- end process;
+-
+- -- Address generation
+- process(CLOCK,nRESET)
+- variable slv_line : std_logic_vector(4 downto 0);
+- begin
+- if nRESET = '0' then
+- RA <= (others => '0');
+- MA <= (others => '0');
+- elsif rising_edge(CLOCK) and CLKEN = '1' then
+- slv_line := std_logic_vector(line_counter);
+-
+- -- Character row address is just the scan line counter delayed by
+- -- one clock to line up with the syncs.
+- if r08_interlace = "11" then
+- -- In interlace sync and video mode the LSb is determined by the
+- -- field number. The line counter counts up in 2s in this case.
+- RA <= slv_line(4 downto 1) & (slv_line(0) or odd_field);
+- else
+- RA <= slv_line;
+- end if;
+- -- Internal memory address delayed by one cycle as well
+- MA <= std_logic_vector(ma_i);
+- end if;
+- end process;
+-
+- -- Cursor control
+- process(CLOCK,nRESET)
+- variable cursor_line : std_logic;
+- begin
+- -- Internal cursor enable signal delayed by 1 clock to line up
+- -- with address outputs
+- if nRESET = '0' then
+- cursor_i <= '0';
+- cursor_line := '0';
+- elsif rising_edge(CLOCK) and CLKEN = '1' then
+- if h_display = '1' and v_display = '1' and ma_i = r14_cursor_h & r15_cursor_l then
+- if line_counter = 0 then
+- -- Suppress wrap around if last line is > max scan line
+- cursor_line := '0';
+- end if;
+- if line_counter = r10_cursor_start then
+- -- First cursor scanline
+- cursor_line := '1';
+- end if;
+-
+- -- Cursor output is asserted within the current cursor character
+- -- on the selected lines only
+- cursor_i <= cursor_line;
+-
+- if line_counter = r11_cursor_end then
+- -- Last cursor scanline
+- cursor_line := '0';
+- end if;
+- else
+- -- Cursor is off in all character positions apart from the
+- -- selected one
+- cursor_i <= '0';
+- end if;
+- end if;
+- end process;
+-
+- -- Light pen capture
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- lpstb_i <= '0';
+- r16_light_pen_h <= (others => '0');
+- r17_light_pen_l <= (others => '0');
+- elsif rising_edge(CLOCK) and CLKEN = '1' then
+- -- Register light-pen strobe input
+- lpstb_i <= LPSTB;
+-
+- if LPSTB = '1' and lpstb_i = '0' then
+- -- Capture address on rising edge
+- r16_light_pen_h <= ma_i(13 downto 8);
+- r17_light_pen_l <= ma_i(7 downto 0);
+- end if;
+- end if;
+- end process;
+-end architecture;
+-
+-
++ DE <= h_display and v_display; ++ ++ -- Cursor output generated combinatorially from the internal signal in ++ -- accordance with the currently selected cursor mode ++ CURSOR <= cursor_i when r10_cursor_mode = "00" else ++ '0' when r10_cursor_mode = "01" else ++ (cursor_i and field_counter(4)) when r10_cursor_mode = "10" else ++ (cursor_i and field_counter(5)); ++ ++ -- Synchronous register access. Enabled on every clock. ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ -- Reset registers to defaults ++ addr_reg <= (others => '0'); ++ r00_h_total <= (others => '0'); ++ r01_h_displayed <= (others => '0'); ++ r02_h_sync_pos <= (others => '0'); ++ r03_v_sync_width <= (others => '0'); ++ r03_h_sync_width <= (others => '0'); ++ r04_v_total <= (others => '0'); ++ r05_v_total_adj <= (others => '0'); ++ r06_v_displayed <= (others => '0'); ++ r07_v_sync_pos <= (others => '0'); ++ r08_interlace <= (others => '0'); ++ r09_max_scan_line_addr <= (others => '0'); ++ r10_cursor_mode <= (others => '0'); ++ r10_cursor_start <= (others => '0'); ++ r11_cursor_end <= (others => '0'); ++ r12_start_addr_h <= (others => '0'); ++ r13_start_addr_l <= (others => '0'); ++ r14_cursor_h <= (others => '0'); ++ r15_cursor_l <= (others => '0'); ++ ++ DO <= (others => '0'); ++ elsif rising_edge(CLOCK) then ++ if ENABLE = '1' then ++ if R_nW = '1' then ++ -- Read ++ case addr_reg is ++ when "01110" => ++ DO <= "00" & std_logic_vector(r14_cursor_h); ++ when "01111" => ++ DO <= std_logic_vector(r15_cursor_l); ++ when "10000" => ++ DO <= "00" & std_logic_vector(r16_light_pen_h); ++ when "10001" => ++ DO <= std_logic_vector(r17_light_pen_l); ++ when others => ++ DO <= (others => '0'); ++ end case; ++ else ++ -- Write ++ if RS = '0' then ++ addr_reg <= DI(4 downto 0); ++ else ++ case addr_reg is ++ when "00000" => ++ r00_h_total <= unsigned(DI); ++ when "00001" => ++ r01_h_displayed <= unsigned(DI); ++ when "00010" => ++ r02_h_sync_pos <= unsigned(DI); ++ when "00011" => ++ r03_v_sync_width <= unsigned(DI(7 downto 4)); ++ r03_h_sync_width <= unsigned(DI(3 downto 0)); ++ when "00100" => ++ r04_v_total <= unsigned(DI(6 downto 0)); ++ when "00101" => ++ r05_v_total_adj <= unsigned(DI(4 downto 0)); ++ when "00110" => ++ r06_v_displayed <= unsigned(DI(6 downto 0)); ++ when "00111" => ++ r07_v_sync_pos <= unsigned(DI(6 downto 0)); ++ when "01000" => ++ r08_interlace <= DI(1 downto 0); ++ when "01001" => ++ r09_max_scan_line_addr <= unsigned(DI(4 downto 0)); ++ when "01010" => ++ r10_cursor_mode <= DI(6 downto 5); ++ r10_cursor_start <= unsigned(DI(4 downto 0)); ++ when "01011" => ++ r11_cursor_end <= unsigned(DI(4 downto 0)); ++ when "01100" => ++ r12_start_addr_h <= unsigned(DI(5 downto 0)); ++ when "01101" => ++ r13_start_addr_l <= unsigned(DI(7 downto 0)); ++ when "01110" => ++ r14_cursor_h <= unsigned(DI(5 downto 0)); ++ when "01111" => ++ r15_cursor_l <= unsigned(DI(7 downto 0)); ++ when others => ++ null; ++ end case; ++ end if; ++ end if; ++ end if; ++ end if; ++ end process; -- registers ++ ++ -- Horizontal, vertical and address counters ++ process(CLOCK,nRESET) ++ variable ma_row_start : unsigned(13 downto 0); ++ variable max_scan_line : unsigned(4 downto 0); ++ begin ++ if nRESET = '0' then ++ -- H ++ h_counter <= (others => '0'); ++ ++ -- V ++ line_counter <= (others => '0'); ++ row_counter <= (others => '0'); ++ odd_field <= '0'; ++ ++ -- Fields (cursor flash) ++ field_counter <= (others => '0'); ++ ++ -- Addressing ++ ma_row_start := (others => '0'); ++ ma_i <= (others => '0'); ++ elsif rising_edge(CLOCK) and CLKEN='1' then ++ -- Horizontal counter increments on each clock, wrapping at ++ -- h_total ++ if h_counter = r00_h_total then ++ -- h_total reached ++ h_counter <= (others => '0'); ++ ++ -- In interlace sync + video mode mask off the LSb of the ++ -- max scan line address ++ if r08_interlace = "11" then ++ max_scan_line := r09_max_scan_line_addr(4 downto 1) & "0"; ++ else ++ max_scan_line := r09_max_scan_line_addr; ++ end if; ++ ++ -- Scan line counter increments, wrapping at max_scan_line_addr ++ if line_counter = max_scan_line then ++ -- Next character row ++ -- FIXME: No support for v_total_adj yet ++ line_counter <= (others => '0'); ++ if row_counter = r04_v_total then ++ -- If in interlace mode we toggle to the opposite field. ++ -- Save on some logic by doing this here rather than at the ++ -- end of v_total_adj - it shouldn't make any difference to the ++ -- output ++ if r08_interlace(0) = '1' then ++ odd_field <= not odd_field; ++ else ++ odd_field <= '0'; ++ end if; ++ ++ -- Address is loaded from start address register at the top of ++ -- each field and the row counter is reset ++ ma_row_start := r12_start_addr_h & r13_start_addr_l; ++ row_counter <= (others => '0'); ++ ++ -- Increment field counter ++ field_counter <= field_counter + 1; ++ else ++ -- On all other character rows within the field the row start address is ++ -- increased by h_displayed and the row counter is incremented ++ ma_row_start := ma_row_start + r01_h_displayed; ++ row_counter <= row_counter + 1; ++ end if; ++ else ++ -- Next scan line. Count in twos in interlaced sync+video mode ++ if r08_interlace = "11" then ++ line_counter <= line_counter + 2; ++ line_counter(0) <= '0'; -- Force to even ++ else ++ line_counter <= line_counter + 1; ++ end if; ++ end if; ++ ++ -- Memory address preset to row start at the beginning of each ++ -- scan line ++ ma_i <= ma_row_start; ++ else ++ -- Increment horizontal counter ++ h_counter <= h_counter + 1; ++ -- Increment memory address ++ ma_i <= ma_i + 1; ++ end if; ++ end if; ++ end process; ++ ++ -- Signals to mark hsync and half way points for generating ++ -- vsync in even and odd fields ++ process(h_counter) ++ begin ++ h_sync_start <= '0'; ++ h_half_way <= '0'; ++ ++ if h_counter = r02_h_sync_pos then ++ h_sync_start <= '1'; ++ end if; ++ if h_counter = "0" & r02_h_sync_pos(7 downto 1) then ++ h_half_way <= '1'; ++ end if; ++ end process; ++ ++ -- Video timing and sync counters ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ -- H ++ h_display <= '0'; ++ hs <= '0'; ++ h_sync_counter <= (others => '0'); ++ ++ -- V ++ v_display <= '0'; ++ vs <= '0'; ++ v_sync_counter <= (others => '0'); ++ elsif rising_edge(CLOCK) and CLKEN = '1' then ++ -- Horizontal active video ++ if h_counter = 0 then ++ -- Start of active video ++ h_display <= '1'; ++ end if; ++ if h_counter = r01_h_displayed then ++ -- End of active video ++ h_display <= '0'; ++ end if; ++ ++ -- Horizontal sync ++ if h_sync_start = '1' or hs = '1' then ++ -- In horizontal sync ++ hs <= '1'; ++ h_sync_counter <= h_sync_counter + 1; ++ else ++ h_sync_counter <= (others => '0'); ++ end if; ++ if h_sync_counter = r03_h_sync_width then ++ -- Terminate hsync after h_sync_width (0 means no hsync so this ++ -- can immediately override the setting above) ++ hs <= '0'; ++ end if; ++ ++ -- Vertical active video ++ if row_counter = 0 then ++ -- Start of active video ++ v_display <= '1'; ++ end if; ++ if row_counter = r06_v_displayed then ++ -- End of active video ++ v_display <= '0'; ++ end if; ++ ++ -- Vertical sync occurs either at the same time as the horizontal sync (even fields) ++ -- or half a line later (odd fields) ++ if (odd_field = '0' and h_sync_start = '1') or (odd_field = '1' and h_half_way = '1') then ++ if (row_counter = r07_v_sync_pos and line_counter = 0) or vs = '1' then ++ -- In vertical sync ++ vs <= '1'; ++ v_sync_counter <= v_sync_counter + 1; ++ else ++ v_sync_counter <= (others => '0'); ++ end if; ++ if v_sync_counter = r03_v_sync_width and vs = '1' then ++ -- Terminate vsync after v_sync_width (0 means 16 lines so this is ++ -- masked by 'vs' to ensure a full turn of the counter in this case) ++ vs <= '0'; ++ end if; ++ end if; ++ end if; ++ end process; ++ ++ -- Address generation ++ process(CLOCK,nRESET) ++ variable slv_line : std_logic_vector(4 downto 0); ++ begin ++ if nRESET = '0' then ++ RA <= (others => '0'); ++ MA <= (others => '0'); ++ elsif rising_edge(CLOCK) and CLKEN = '1' then ++ slv_line := std_logic_vector(line_counter); ++ ++ -- Character row address is just the scan line counter delayed by ++ -- one clock to line up with the syncs. ++ if r08_interlace = "11" then ++ -- In interlace sync and video mode the LSb is determined by the ++ -- field number. The line counter counts up in 2s in this case. ++ RA <= slv_line(4 downto 1) & (slv_line(0) or odd_field); ++ else ++ RA <= slv_line; ++ end if; ++ -- Internal memory address delayed by one cycle as well ++ MA <= std_logic_vector(ma_i); ++ end if; ++ end process; ++ ++ -- Cursor control ++ process(CLOCK,nRESET) ++ variable cursor_line : std_logic; ++ begin ++ -- Internal cursor enable signal delayed by 1 clock to line up ++ -- with address outputs ++ if nRESET = '0' then ++ cursor_i <= '0'; ++ cursor_line := '0'; ++ elsif rising_edge(CLOCK) and CLKEN = '1' then ++ if h_display = '1' and v_display = '1' and ma_i = r14_cursor_h & r15_cursor_l then ++ if line_counter = 0 then ++ -- Suppress wrap around if last line is > max scan line ++ cursor_line := '0'; ++ end if; ++ if line_counter = r10_cursor_start then ++ -- First cursor scanline ++ cursor_line := '1'; ++ end if; ++ ++ -- Cursor output is asserted within the current cursor character ++ -- on the selected lines only ++ cursor_i <= cursor_line; ++ ++ if line_counter = r11_cursor_end then ++ -- Last cursor scanline ++ cursor_line := '0'; ++ end if; ++ else ++ -- Cursor is off in all character positions apart from the ++ -- selected one ++ cursor_i <= '0'; ++ end if; ++ end if; ++ end process; ++ ++ -- Light pen capture ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ lpstb_i <= '0'; ++ r16_light_pen_h <= (others => '0'); ++ r17_light_pen_l <= (others => '0'); ++ elsif rising_edge(CLOCK) and CLKEN = '1' then ++ -- Register light-pen strobe input ++ lpstb_i <= LPSTB; ++ ++ if LPSTB = '1' and lpstb_i = '0' then ++ -- Capture address on rising edge ++ r16_light_pen_h <= ma_i(13 downto 8); ++ r17_light_pen_l <= ma_i(7 downto 0); ++ end if; ++ end if; ++ end process; ++end architecture; ++ ++ +diff --git a/pll32.ppf b/pll32.ppf +index 1ba6b2c..71486cf 100644 +--- a/pll32.ppf ++++ b/pll32.ppf +@@ -1,11 +1,11 @@ +-<?xml version="1.0" encoding="UTF-8" ?>
+-<!DOCTYPE pinplan>
+-<pinplan intended_family="Cyclone II" variation_name="pll32" megafunction_name="ALTPLL" specifies="all_ports">
+-<global>
+-<pin name="areset" direction="input" scope="external" />
+-<pin name="inclk0" direction="input" scope="external" source="clock" />
+-<pin name="c0" direction="output" scope="external" source="clock" />
+-<pin name="locked" direction="output" scope="external" />
+-
+-</global>
+-</pinplan>
++<?xml version="1.0" encoding="UTF-8" ?> ++<!DOCTYPE pinplan> ++<pinplan intended_family="Cyclone II" variation_name="pll32" megafunction_name="ALTPLL" specifies="all_ports"> ++<global> ++<pin name="areset" direction="input" scope="external" /> ++<pin name="inclk0" direction="input" scope="external" source="clock" /> ++<pin name="c0" direction="output" scope="external" source="clock" /> ++<pin name="locked" direction="output" scope="external" /> ++ ++</global> ++</pinplan> +diff --git a/pll32.qip b/pll32.qip +index f78bd93..e82abed 100644 +--- a/pll32.qip ++++ b/pll32.qip +@@ -1,4 +1,4 @@ +-set_global_assignment -name IP_TOOL_NAME "ALTPLL"
+-set_global_assignment -name IP_TOOL_VERSION "9.1"
+-set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "pll32.vhd"]
+-set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll32.ppf"]
++set_global_assignment -name IP_TOOL_NAME "ALTPLL" ++set_global_assignment -name IP_TOOL_VERSION "9.1" ++set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "pll32.vhd"] ++set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll32.ppf"] +diff --git a/pll32.vhd b/pll32.vhd +index 43df1aa..ab53700 100644 +--- a/pll32.vhd ++++ b/pll32.vhd +@@ -1,365 +1,365 @@ +--- megafunction wizard: %ALTPLL%
+--- GENERATION: STANDARD
+--- VERSION: WM1.0
+--- MODULE: altpll
+-
+--- ============================================================
+--- File Name: pll32.vhd
+--- Megafunction Name(s):
+--- altpll
+---
+--- Simulation Library Files(s):
+--- altera_mf
+--- ============================================================
+--- ************************************************************
+--- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+---
+--- 9.1 Build 222 10/21/2009 SJ Web Edition
+--- ************************************************************
+-
+-
+---Copyright (C) 1991-2009 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.
+-
+-
+-LIBRARY ieee;
+-USE ieee.std_logic_1164.all;
+-
+-LIBRARY altera_mf;
+-USE altera_mf.all;
+-
+-ENTITY pll32 IS
+- PORT
+- (
+- areset : IN STD_LOGIC := '0';
+- inclk0 : IN STD_LOGIC := '0';
+- c0 : OUT STD_LOGIC ;
+- locked : OUT STD_LOGIC
+- );
+-END pll32;
+-
+-
+-ARCHITECTURE SYN OF pll32 IS
+-
+- SIGNAL sub_wire0 : STD_LOGIC_VECTOR (5 DOWNTO 0);
+- SIGNAL sub_wire1 : STD_LOGIC ;
+- SIGNAL sub_wire2 : STD_LOGIC ;
+- SIGNAL sub_wire3 : STD_LOGIC ;
+- SIGNAL sub_wire4 : STD_LOGIC_VECTOR (1 DOWNTO 0);
+- SIGNAL sub_wire5_bv : BIT_VECTOR (0 DOWNTO 0);
+- SIGNAL sub_wire5 : STD_LOGIC_VECTOR (0 DOWNTO 0);
+-
+-
+-
+- COMPONENT altpll
+- GENERIC (
+- clk0_divide_by : NATURAL;
+- clk0_duty_cycle : NATURAL;
+- clk0_multiply_by : NATURAL;
+- clk0_phase_shift : STRING;
+- compensate_clock : STRING;
+- gate_lock_signal : STRING;
+- inclk0_input_frequency : NATURAL;
+- intended_device_family : STRING;
+- invalid_lock_multiplier : NATURAL;
+- lpm_hint : STRING;
+- lpm_type : STRING;
+- operation_mode : STRING;
+- port_activeclock : STRING;
+- port_areset : STRING;
+- port_clkbad0 : STRING;
+- port_clkbad1 : STRING;
+- port_clkloss : STRING;
+- port_clkswitch : STRING;
+- port_configupdate : STRING;
+- port_fbin : STRING;
+- port_inclk0 : STRING;
+- port_inclk1 : STRING;
+- port_locked : STRING;
+- port_pfdena : STRING;
+- port_phasecounterselect : STRING;
+- port_phasedone : STRING;
+- port_phasestep : STRING;
+- port_phaseupdown : STRING;
+- port_pllena : STRING;
+- port_scanaclr : STRING;
+- port_scanclk : STRING;
+- port_scanclkena : STRING;
+- port_scandata : STRING;
+- port_scandataout : STRING;
+- port_scandone : STRING;
+- port_scanread : STRING;
+- port_scanwrite : STRING;
+- port_clk0 : STRING;
+- port_clk1 : STRING;
+- port_clk2 : STRING;
+- port_clk3 : STRING;
+- port_clk4 : STRING;
+- port_clk5 : STRING;
+- port_clkena0 : STRING;
+- port_clkena1 : STRING;
+- port_clkena2 : STRING;
+- port_clkena3 : STRING;
+- port_clkena4 : STRING;
+- port_clkena5 : STRING;
+- port_extclk0 : STRING;
+- port_extclk1 : STRING;
+- port_extclk2 : STRING;
+- port_extclk3 : STRING;
+- valid_lock_multiplier : NATURAL
+- );
+- PORT (
+- inclk : IN STD_LOGIC_VECTOR (1 DOWNTO 0);
+- locked : OUT STD_LOGIC ;
+- areset : IN STD_LOGIC ;
+- clk : OUT STD_LOGIC_VECTOR (5 DOWNTO 0)
+- );
+- END COMPONENT;
+-
+-BEGIN
+- sub_wire5_bv(0 DOWNTO 0) <= "0";
+- sub_wire5 <= To_stdlogicvector(sub_wire5_bv);
+- sub_wire1 <= sub_wire0(0);
+- c0 <= sub_wire1;
+- locked <= sub_wire2;
+- sub_wire3 <= inclk0;
+- sub_wire4 <= sub_wire5(0 DOWNTO 0) & sub_wire3;
+-
+- altpll_component : altpll
+- GENERIC MAP (
+- clk0_divide_by => 3,
+- clk0_duty_cycle => 50,
+- clk0_multiply_by => 4,
+- clk0_phase_shift => "0",
+- compensate_clock => "CLK0",
+- gate_lock_signal => "NO",
+- inclk0_input_frequency => 41666,
+- intended_device_family => "Cyclone II",
+- invalid_lock_multiplier => 5,
+- lpm_hint => "CBX_MODULE_PREFIX=pll32",
+- lpm_type => "altpll",
+- operation_mode => "NORMAL",
+- port_activeclock => "PORT_UNUSED",
+- port_areset => "PORT_USED",
+- port_clkbad0 => "PORT_UNUSED",
+- port_clkbad1 => "PORT_UNUSED",
+- port_clkloss => "PORT_UNUSED",
+- port_clkswitch => "PORT_UNUSED",
+- port_configupdate => "PORT_UNUSED",
+- port_fbin => "PORT_UNUSED",
+- port_inclk0 => "PORT_USED",
+- port_inclk1 => "PORT_UNUSED",
+- port_locked => "PORT_USED",
+- port_pfdena => "PORT_UNUSED",
+- port_phasecounterselect => "PORT_UNUSED",
+- port_phasedone => "PORT_UNUSED",
+- port_phasestep => "PORT_UNUSED",
+- port_phaseupdown => "PORT_UNUSED",
+- port_pllena => "PORT_UNUSED",
+- port_scanaclr => "PORT_UNUSED",
+- port_scanclk => "PORT_UNUSED",
+- port_scanclkena => "PORT_UNUSED",
+- port_scandata => "PORT_UNUSED",
+- port_scandataout => "PORT_UNUSED",
+- port_scandone => "PORT_UNUSED",
+- port_scanread => "PORT_UNUSED",
+- port_scanwrite => "PORT_UNUSED",
+- port_clk0 => "PORT_USED",
+- port_clk1 => "PORT_UNUSED",
+- port_clk2 => "PORT_UNUSED",
+- port_clk3 => "PORT_UNUSED",
+- port_clk4 => "PORT_UNUSED",
+- port_clk5 => "PORT_UNUSED",
+- port_clkena0 => "PORT_UNUSED",
+- port_clkena1 => "PORT_UNUSED",
+- port_clkena2 => "PORT_UNUSED",
+- port_clkena3 => "PORT_UNUSED",
+- port_clkena4 => "PORT_UNUSED",
+- port_clkena5 => "PORT_UNUSED",
+- port_extclk0 => "PORT_UNUSED",
+- port_extclk1 => "PORT_UNUSED",
+- port_extclk2 => "PORT_UNUSED",
+- port_extclk3 => "PORT_UNUSED",
+- valid_lock_multiplier => 1
+- )
+- PORT MAP (
+- inclk => sub_wire4,
+- areset => areset,
+- clk => sub_wire0,
+- locked => sub_wire2
+- );
+-
+-
+-
+-END SYN;
+-
+--- ============================================================
+--- CNX file retrieval info
+--- ============================================================
+--- Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0"
+--- Retrieval info: PRIVATE: BANDWIDTH STRING "1.000"
+--- Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "0"
+--- Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz"
+--- Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low"
+--- Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1"
+--- Retrieval info: PRIVATE: BANDWIDTH_USE_CUSTOM STRING "0"
+--- Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0"
+--- Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0"
+--- Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0"
+--- Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "1"
+--- Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0"
+--- Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0"
+--- Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0"
+--- Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0"
+--- Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "e0"
+--- Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "7"
+--- Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "1"
+--- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000"
+--- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "32.000000"
+--- Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0"
+--- Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0"
+--- Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1"
+--- Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "1"
+--- Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0"
+--- Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575"
+--- Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1"
+--- Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "24.000"
+--- Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz"
+--- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000"
+--- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1"
+--- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1"
+--- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz"
+--- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II"
+--- Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1"
+--- Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1"
+--- Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1"
+--- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "312.000"
+--- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0"
+--- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg"
+--- Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any"
+--- Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0"
+--- Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "1"
+--- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1"
+--- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "32.00000000"
+--- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "1"
+--- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz"
+--- Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "0"
+--- Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0"
+--- Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000"
+--- Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0"
+--- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg"
+--- Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0"
+--- Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1"
+--- Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1"
+--- Retrieval info: PRIVATE: PLL_ENA_CHECK STRING "0"
+--- Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0"
+--- Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0"
+--- Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0"
+--- Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0"
+--- Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0"
+--- Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0"
+--- Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0"
+--- Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll32.mif"
+--- Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0"
+--- Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "0"
+--- Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0"
+--- Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0"
+--- Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0"
+--- Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000"
+--- Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz"
+--- Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500"
+--- Retrieval info: PRIVATE: SPREAD_USE STRING "0"
+--- Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0"
+--- Retrieval info: PRIVATE: STICKY_CLK0 STRING "1"
+--- Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1"
+--- Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1"
+--- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
+--- Retrieval info: PRIVATE: USE_CLK0 STRING "1"
+--- Retrieval info: PRIVATE: USE_CLKENA0 STRING "0"
+--- Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0"
+--- Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0"
+--- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
+--- Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "3"
+--- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50"
+--- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "4"
+--- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0"
+--- Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0"
+--- Retrieval info: CONSTANT: GATE_LOCK_SIGNAL STRING "NO"
+--- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "41666"
+--- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II"
+--- Retrieval info: CONSTANT: INVALID_LOCK_MULTIPLIER NUMERIC "5"
+--- Retrieval info: CONSTANT: LPM_TYPE STRING "altpll"
+--- Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL"
+--- Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED"
+--- Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED"
+--- Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED"
+--- Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED"
+--- Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED"
+--- Retrieval info: CONSTANT: VALID_LOCK_MULTIPLIER NUMERIC "1"
+--- Retrieval info: USED_PORT: @clk 0 0 6 0 OUTPUT_CLK_EXT VCC "@clk[5..0]"
+--- Retrieval info: USED_PORT: @extclk 0 0 4 0 OUTPUT_CLK_EXT VCC "@extclk[3..0]"
+--- Retrieval info: USED_PORT: @inclk 0 0 2 0 INPUT_CLK_EXT VCC "@inclk[1..0]"
+--- Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset"
+--- Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0"
+--- Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0"
+--- Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked"
+--- Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0
+--- Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0
+--- Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0
+--- Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0
+--- Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0
+--- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.vhd TRUE
+--- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.ppf TRUE
+--- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.inc FALSE
+--- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.cmp FALSE
+--- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.bsf FALSE
+--- Retrieval info: GEN_FILE: TYPE_NORMAL pll32_inst.vhd FALSE
+--- Retrieval info: LIB_FILE: altera_mf
+--- Retrieval info: CBX_MODULE_PREFIX: ON
++-- megafunction wizard: %ALTPLL% ++-- GENERATION: STANDARD ++-- VERSION: WM1.0 ++-- MODULE: altpll ++ ++-- ============================================================ ++-- File Name: pll32.vhd ++-- Megafunction Name(s): ++-- altpll ++-- ++-- Simulation Library Files(s): ++-- altera_mf ++-- ============================================================ ++-- ************************************************************ ++-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! ++-- ++-- 9.1 Build 222 10/21/2009 SJ Web Edition ++-- ************************************************************ ++ ++ ++--Copyright (C) 1991-2009 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. ++ ++ ++LIBRARY ieee; ++USE ieee.std_logic_1164.all; ++ ++LIBRARY altera_mf; ++USE altera_mf.all; ++ ++ENTITY pll32 IS ++ PORT ++ ( ++ areset : IN STD_LOGIC := '0'; ++ inclk0 : IN STD_LOGIC := '0'; ++ c0 : OUT STD_LOGIC ; ++ locked : OUT STD_LOGIC ++ ); ++END pll32; ++ ++ ++ARCHITECTURE SYN OF pll32 IS ++ ++ SIGNAL sub_wire0 : STD_LOGIC_VECTOR (5 DOWNTO 0); ++ SIGNAL sub_wire1 : STD_LOGIC ; ++ SIGNAL sub_wire2 : STD_LOGIC ; ++ SIGNAL sub_wire3 : STD_LOGIC ; ++ SIGNAL sub_wire4 : STD_LOGIC_VECTOR (1 DOWNTO 0); ++ SIGNAL sub_wire5_bv : BIT_VECTOR (0 DOWNTO 0); ++ SIGNAL sub_wire5 : STD_LOGIC_VECTOR (0 DOWNTO 0); ++ ++ ++ ++ COMPONENT altpll ++ GENERIC ( ++ clk0_divide_by : NATURAL; ++ clk0_duty_cycle : NATURAL; ++ clk0_multiply_by : NATURAL; ++ clk0_phase_shift : STRING; ++ compensate_clock : STRING; ++ gate_lock_signal : STRING; ++ inclk0_input_frequency : NATURAL; ++ intended_device_family : STRING; ++ invalid_lock_multiplier : NATURAL; ++ lpm_hint : STRING; ++ lpm_type : STRING; ++ operation_mode : STRING; ++ port_activeclock : STRING; ++ port_areset : STRING; ++ port_clkbad0 : STRING; ++ port_clkbad1 : STRING; ++ port_clkloss : STRING; ++ port_clkswitch : STRING; ++ port_configupdate : STRING; ++ port_fbin : STRING; ++ port_inclk0 : STRING; ++ port_inclk1 : STRING; ++ port_locked : STRING; ++ port_pfdena : STRING; ++ port_phasecounterselect : STRING; ++ port_phasedone : STRING; ++ port_phasestep : STRING; ++ port_phaseupdown : STRING; ++ port_pllena : STRING; ++ port_scanaclr : STRING; ++ port_scanclk : STRING; ++ port_scanclkena : STRING; ++ port_scandata : STRING; ++ port_scandataout : STRING; ++ port_scandone : STRING; ++ port_scanread : STRING; ++ port_scanwrite : STRING; ++ port_clk0 : STRING; ++ port_clk1 : STRING; ++ port_clk2 : STRING; ++ port_clk3 : STRING; ++ port_clk4 : STRING; ++ port_clk5 : STRING; ++ port_clkena0 : STRING; ++ port_clkena1 : STRING; ++ port_clkena2 : STRING; ++ port_clkena3 : STRING; ++ port_clkena4 : STRING; ++ port_clkena5 : STRING; ++ port_extclk0 : STRING; ++ port_extclk1 : STRING; ++ port_extclk2 : STRING; ++ port_extclk3 : STRING; ++ valid_lock_multiplier : NATURAL ++ ); ++ PORT ( ++ inclk : IN STD_LOGIC_VECTOR (1 DOWNTO 0); ++ locked : OUT STD_LOGIC ; ++ areset : IN STD_LOGIC ; ++ clk : OUT STD_LOGIC_VECTOR (5 DOWNTO 0) ++ ); ++ END COMPONENT; ++ ++BEGIN ++ sub_wire5_bv(0 DOWNTO 0) <= "0"; ++ sub_wire5 <= To_stdlogicvector(sub_wire5_bv); ++ sub_wire1 <= sub_wire0(0); ++ c0 <= sub_wire1; ++ locked <= sub_wire2; ++ sub_wire3 <= inclk0; ++ sub_wire4 <= sub_wire5(0 DOWNTO 0) & sub_wire3; ++ ++ altpll_component : altpll ++ GENERIC MAP ( ++ clk0_divide_by => 3, ++ clk0_duty_cycle => 50, ++ clk0_multiply_by => 4, ++ clk0_phase_shift => "0", ++ compensate_clock => "CLK0", ++ gate_lock_signal => "NO", ++ inclk0_input_frequency => 41666, ++ intended_device_family => "Cyclone II", ++ invalid_lock_multiplier => 5, ++ lpm_hint => "CBX_MODULE_PREFIX=pll32", ++ lpm_type => "altpll", ++ operation_mode => "NORMAL", ++ port_activeclock => "PORT_UNUSED", ++ port_areset => "PORT_USED", ++ port_clkbad0 => "PORT_UNUSED", ++ port_clkbad1 => "PORT_UNUSED", ++ port_clkloss => "PORT_UNUSED", ++ port_clkswitch => "PORT_UNUSED", ++ port_configupdate => "PORT_UNUSED", ++ port_fbin => "PORT_UNUSED", ++ port_inclk0 => "PORT_USED", ++ port_inclk1 => "PORT_UNUSED", ++ port_locked => "PORT_USED", ++ port_pfdena => "PORT_UNUSED", ++ port_phasecounterselect => "PORT_UNUSED", ++ port_phasedone => "PORT_UNUSED", ++ port_phasestep => "PORT_UNUSED", ++ port_phaseupdown => "PORT_UNUSED", ++ port_pllena => "PORT_UNUSED", ++ port_scanaclr => "PORT_UNUSED", ++ port_scanclk => "PORT_UNUSED", ++ port_scanclkena => "PORT_UNUSED", ++ port_scandata => "PORT_UNUSED", ++ port_scandataout => "PORT_UNUSED", ++ port_scandone => "PORT_UNUSED", ++ port_scanread => "PORT_UNUSED", ++ port_scanwrite => "PORT_UNUSED", ++ port_clk0 => "PORT_USED", ++ port_clk1 => "PORT_UNUSED", ++ port_clk2 => "PORT_UNUSED", ++ port_clk3 => "PORT_UNUSED", ++ port_clk4 => "PORT_UNUSED", ++ port_clk5 => "PORT_UNUSED", ++ port_clkena0 => "PORT_UNUSED", ++ port_clkena1 => "PORT_UNUSED", ++ port_clkena2 => "PORT_UNUSED", ++ port_clkena3 => "PORT_UNUSED", ++ port_clkena4 => "PORT_UNUSED", ++ port_clkena5 => "PORT_UNUSED", ++ port_extclk0 => "PORT_UNUSED", ++ port_extclk1 => "PORT_UNUSED", ++ port_extclk2 => "PORT_UNUSED", ++ port_extclk3 => "PORT_UNUSED", ++ valid_lock_multiplier => 1 ++ ) ++ PORT MAP ( ++ inclk => sub_wire4, ++ areset => areset, ++ clk => sub_wire0, ++ locked => sub_wire2 ++ ); ++ ++ ++ ++END SYN; ++ ++-- ============================================================ ++-- CNX file retrieval info ++-- ============================================================ ++-- Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" ++-- Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" ++-- Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "0" ++-- Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" ++-- Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" ++-- Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" ++-- Retrieval info: PRIVATE: BANDWIDTH_USE_CUSTOM STRING "0" ++-- Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" ++-- Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" ++-- Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" ++-- Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "1" ++-- Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" ++-- Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" ++-- Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" ++-- Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" ++-- Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "e0" ++-- Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "7" ++-- Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "1" ++-- Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" ++-- Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "32.000000" ++-- Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" ++-- Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" ++-- Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" ++-- Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "1" ++-- Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "0" ++-- Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" ++-- Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" ++-- Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "24.000" ++-- Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" ++-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" ++-- Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" ++-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" ++-- Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" ++-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II" ++-- Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" ++-- Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" ++-- Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" ++-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "312.000" ++-- Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" ++-- Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" ++-- Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" ++-- Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" ++-- Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "1" ++-- Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" ++-- Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "32.00000000" ++-- Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "1" ++-- Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" ++-- Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "0" ++-- Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" ++-- Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" ++-- Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" ++-- Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" ++-- Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" ++-- Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" ++-- Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" ++-- Retrieval info: PRIVATE: PLL_ENA_CHECK STRING "0" ++-- Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" ++-- Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" ++-- Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" ++-- Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" ++-- Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" ++-- Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" ++-- Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" ++-- Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll32.mif" ++-- Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" ++-- Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "0" ++-- Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" ++-- Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" ++-- Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" ++-- Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" ++-- Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" ++-- Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" ++-- Retrieval info: PRIVATE: SPREAD_USE STRING "0" ++-- Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" ++-- Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" ++-- Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" ++-- Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" ++-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" ++-- Retrieval info: PRIVATE: USE_CLK0 STRING "1" ++-- Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" ++-- Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" ++-- Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" ++-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all ++-- Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "3" ++-- Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" ++-- Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "4" ++-- Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" ++-- Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" ++-- Retrieval info: CONSTANT: GATE_LOCK_SIGNAL STRING "NO" ++-- Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "41666" ++-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II" ++-- Retrieval info: CONSTANT: INVALID_LOCK_MULTIPLIER NUMERIC "5" ++-- Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" ++-- Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" ++-- Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED" ++-- Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" ++-- Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" ++-- Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" ++-- Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" ++-- Retrieval info: CONSTANT: VALID_LOCK_MULTIPLIER NUMERIC "1" ++-- Retrieval info: USED_PORT: @clk 0 0 6 0 OUTPUT_CLK_EXT VCC "@clk[5..0]" ++-- Retrieval info: USED_PORT: @extclk 0 0 4 0 OUTPUT_CLK_EXT VCC "@extclk[3..0]" ++-- Retrieval info: USED_PORT: @inclk 0 0 2 0 INPUT_CLK_EXT VCC "@inclk[1..0]" ++-- Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset" ++-- Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" ++-- Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" ++-- Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" ++-- Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 ++-- Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 ++-- Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 ++-- Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 ++-- Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0 ++-- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.vhd TRUE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.ppf TRUE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.inc FALSE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.cmp FALSE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL pll32.bsf FALSE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL pll32_inst.vhd FALSE ++-- Retrieval info: LIB_FILE: altera_mf ++-- Retrieval info: CBX_MODULE_PREFIX: ON +diff --git a/ps2_intf.vhd b/ps2_intf.vhd +index dc8440f..015a7d0 100644 +--- a/ps2_intf.vhd ++++ b/ps2_intf.vhd +@@ -1,157 +1,157 @@ +--- ZX Spectrum for Altera DE1
+---
+--- Copyright (c) 2009-2011 Mike Stirling
+---
+--- 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 agreement from the author.
+---
+--- * License is granted for non-commercial use only. A fee may not be charged
+--- for redistributions as source code or in synthesized/hardware form without
+--- specific prior written agreement from the author.
+---
+--- 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.
+---
+-
+--- PS/2 interface (input only)
+--- Based loosely on ps2_ctrl.vhd (c) ALSE. http://www.alse-fr.com
+-library IEEE;
+-use IEEE.STD_LOGIC_1164.ALL;
+-use IEEE.NUMERIC_STD.ALL;
+-
+--- This is input-only for the time being
+-entity ps2_intf is
+-generic (filter_length : positive := 8);
+-port(
+- CLK : in std_logic;
+- nRESET : in std_logic;
+-
+- -- PS/2 interface (could be bi-dir)
+- PS2_CLK : in std_logic;
+- PS2_DATA : in std_logic;
+-
+- -- Byte-wide data interface - only valid for one clock
+- -- so must be latched externally if required
+- DATA : out std_logic_vector(7 downto 0);
+- VALID : out std_logic;
+- ERROR : out std_logic
+- );
+-end ps2_intf;
+-
+-architecture ps2_intf_arch of ps2_intf is
+-subtype filter_t is std_logic_vector(filter_length-1 downto 0);
+-signal clk_filter : filter_t;
+-
+-signal ps2_clk_in : std_logic;
+-signal ps2_dat_in : std_logic;
+--- Goes high when a clock falling edge is detected
+-signal clk_edge : std_logic;
+-signal bit_count : unsigned (3 downto 0);
+-signal shiftreg : std_logic_vector(8 downto 0);
+-signal parity : std_logic;
+-begin
+- -- Register input signals
+- process(nRESET,CLK)
+- begin
+- if nRESET = '0' then
+- ps2_clk_in <= '1';
+- ps2_dat_in <= '1';
+- clk_filter <= (others => '1');
+- clk_edge <= '0';
+- elsif rising_edge(CLK) then
+- -- Register inputs (and filter clock)
+- ps2_dat_in <= PS2_DATA;
+- clk_filter <= PS2_CLK & clk_filter(clk_filter'high downto 1);
+- clk_edge <= '0';
+-
+- if clk_filter = filter_t'(others => '1') then
+- -- Filtered clock is high
+- ps2_clk_in <= '1';
+- elsif clk_filter = filter_t'(others => '0') then
+- -- Filter clock is low, check for edge
+- if ps2_clk_in = '1' then
+- clk_edge <= '1';
+- end if;
+- ps2_clk_in <= '0';
+- end if;
+- end if;
+- end process;
+-
+- -- Shift in keyboard data
+- process(nRESET,CLK)
+- begin
+- if nRESET = '0' then
+- bit_count <= (others => '0');
+- shiftreg <= (others => '0');
+- parity <= '0';
+- DATA <= (others => '0');
+- VALID <= '0';
+- ERROR <= '0';
+- elsif rising_edge(CLK) then
+- -- Clear flags
+- VALID <= '0';
+- ERROR <= '0';
+-
+- if clk_edge = '1' then
+- -- We have a new bit from the keyboard for processing
+- if bit_count = 0 then
+- -- Idle state, check for start bit (0) only and don't
+- -- start counting bits until we get it
+-
+- parity <= '0';
+-
+- if ps2_dat_in = '0' then
+- -- This is a start bit
+- bit_count <= bit_count + 1;
+- end if;
+- else
+- -- Running. 8-bit data comes in LSb first followed by
+- -- a single stop bit (1)
+- if bit_count < 10 then
+- -- Shift in data and parity (9 bits)
+- bit_count <= bit_count + 1;
+- shiftreg <= ps2_dat_in & shiftreg(shiftreg'high downto 1);
+- parity <= parity xor ps2_dat_in; -- Calculate parity
+- elsif ps2_dat_in = '1' then
+- -- Valid stop bit received
+- bit_count <= (others => '0'); -- back to idle
+- if parity = '1' then
+- -- Parity correct, submit data to host
+- DATA <= shiftreg(7 downto 0);
+- VALID <= '1';
+- else
+- -- Error
+- ERROR <= '1';
+- end if;
+- else
+- -- Invalid stop bit
+- bit_count <= (others => '0'); -- back to idle
+- ERROR <= '1';
+- end if;
+- end if;
+- end if;
+- end if;
+- end process;
+-end ps2_intf_arch;
++-- ZX Spectrum for Altera DE1 ++-- ++-- Copyright (c) 2009-2011 Mike Stirling ++-- ++-- 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 agreement from the author. ++-- ++-- * License is granted for non-commercial use only. A fee may not be charged ++-- for redistributions as source code or in synthesized/hardware form without ++-- specific prior written agreement from the author. ++-- ++-- 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. ++-- ++ ++-- PS/2 interface (input only) ++-- Based loosely on ps2_ctrl.vhd (c) ALSE. http://www.alse-fr.com ++library IEEE; ++use IEEE.STD_LOGIC_1164.ALL; ++use IEEE.NUMERIC_STD.ALL; ++ ++-- This is input-only for the time being ++entity ps2_intf is ++generic (filter_length : positive := 8); ++port( ++ CLK : in std_logic; ++ nRESET : in std_logic; ++ ++ -- PS/2 interface (could be bi-dir) ++ PS2_CLK : in std_logic; ++ PS2_DATA : in std_logic; ++ ++ -- Byte-wide data interface - only valid for one clock ++ -- so must be latched externally if required ++ DATA : out std_logic_vector(7 downto 0); ++ VALID : out std_logic; ++ ERROR : out std_logic ++ ); ++end ps2_intf; ++ ++architecture ps2_intf_arch of ps2_intf is ++subtype filter_t is std_logic_vector(filter_length-1 downto 0); ++signal clk_filter : filter_t; ++ ++signal ps2_clk_in : std_logic; ++signal ps2_dat_in : std_logic; ++-- Goes high when a clock falling edge is detected ++signal clk_edge : std_logic; ++signal bit_count : unsigned (3 downto 0); ++signal shiftreg : std_logic_vector(8 downto 0); ++signal parity : std_logic; ++begin ++ -- Register input signals ++ process(nRESET,CLK) ++ begin ++ if nRESET = '0' then ++ ps2_clk_in <= '1'; ++ ps2_dat_in <= '1'; ++ clk_filter <= (others => '1'); ++ clk_edge <= '0'; ++ elsif rising_edge(CLK) then ++ -- Register inputs (and filter clock) ++ ps2_dat_in <= PS2_DATA; ++ clk_filter <= PS2_CLK & clk_filter(clk_filter'high downto 1); ++ clk_edge <= '0'; ++ ++ if clk_filter = filter_t'(others => '1') then ++ -- Filtered clock is high ++ ps2_clk_in <= '1'; ++ elsif clk_filter = filter_t'(others => '0') then ++ -- Filter clock is low, check for edge ++ if ps2_clk_in = '1' then ++ clk_edge <= '1'; ++ end if; ++ ps2_clk_in <= '0'; ++ end if; ++ end if; ++ end process; ++ ++ -- Shift in keyboard data ++ process(nRESET,CLK) ++ begin ++ if nRESET = '0' then ++ bit_count <= (others => '0'); ++ shiftreg <= (others => '0'); ++ parity <= '0'; ++ DATA <= (others => '0'); ++ VALID <= '0'; ++ ERROR <= '0'; ++ elsif rising_edge(CLK) then ++ -- Clear flags ++ VALID <= '0'; ++ ERROR <= '0'; ++ ++ if clk_edge = '1' then ++ -- We have a new bit from the keyboard for processing ++ if bit_count = 0 then ++ -- Idle state, check for start bit (0) only and don't ++ -- start counting bits until we get it ++ ++ parity <= '0'; ++ ++ if ps2_dat_in = '0' then ++ -- This is a start bit ++ bit_count <= bit_count + 1; ++ end if; ++ else ++ -- Running. 8-bit data comes in LSb first followed by ++ -- a single stop bit (1) ++ if bit_count < 10 then ++ -- Shift in data and parity (9 bits) ++ bit_count <= bit_count + 1; ++ shiftreg <= ps2_dat_in & shiftreg(shiftreg'high downto 1); ++ parity <= parity xor ps2_dat_in; -- Calculate parity ++ elsif ps2_dat_in = '1' then ++ -- Valid stop bit received ++ bit_count <= (others => '0'); -- back to idle ++ if parity = '1' then ++ -- Parity correct, submit data to host ++ DATA <= shiftreg(7 downto 0); ++ VALID <= '1'; ++ else ++ -- Error ++ ERROR <= '1'; ++ end if; ++ else ++ -- Invalid stop bit ++ bit_count <= (others => '0'); -- back to idle ++ ERROR <= '1'; ++ end if; ++ end if; ++ end if; ++ end if; ++ end process; ++end ps2_intf_arch; +diff --git a/saa5050.vhd b/saa5050.vhd +index 57dd999..f198aa8 100644 +--- a/saa5050.vhd ++++ b/saa5050.vhd +@@ -1,391 +1,391 @@ +--- BBC Micro for Altera DE1
+---
+--- Copyright (c) 2011 Mike Stirling
+---
+--- 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 agreement from the author.
+---
+--- * License is granted for non-commercial use only. A fee may not be charged
+--- for redistributions as source code or in synthesized/hardware form without
+--- specific prior written agreement from the author.
+---
+--- 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.
+---
+--- SAA5050 teletext generator
+---
+--- Synchronous implementation for FPGA. Certain TV-specific functions are
+--- not implemented. e.g.
+---
+--- No /SI pin - 'TEXT' mode is permanently enabled
+--- No remote control features (/DATA, DLIM)
+--- No large character support
+--- No support for box overlay (BLAN, PO, DE)
+--- No character rounding, although this may be added
+---
+--- FIXME: Hold graphics not supported - this needs to be added
+---
+--- (C) 2011 Mike Stirling
+---
+-library IEEE;
+-use IEEE.STD_LOGIC_1164.ALL;
+-use IEEE.NUMERIC_STD.ALL;
+-
+-entity saa5050 is
+-port (
+- CLOCK : in std_logic;
+- -- 6 MHz dot clock enable
+- CLKEN : in std_logic;
+- -- Async reset
+- nRESET : in std_logic;
+-
+- -- Character data input (in the bus clock domain)
+- DI_CLOCK : in std_logic;
+- DI_CLKEN : in std_logic;
+- DI : in std_logic_vector(6 downto 0);
+-
+- -- Timing inputs
+- -- General line reset (not used)
+- GLR : in std_logic; -- /HSYNC
+- -- Data entry window - high during VSYNC.
+- -- Resets ROM row counter and drives 'flash' signal
+- DEW : in std_logic; -- VSYNC
+- -- Character rounding select - high during even field
+- CRS : in std_logic; -- FIELD
+- -- Load output shift register enable - high during active video
+- LOSE : in std_logic; -- DE
+-
+- -- Video out
+- R : out std_logic;
+- G : out std_logic;
+- B : out std_logic;
+- Y : out std_logic
+- );
+-end entity;
+-
+-architecture rtl of saa5050 is
+-
+-component saa5050_rom IS
+- PORT
+- (
+- address : IN STD_LOGIC_VECTOR (11 DOWNTO 0);
+- clock : IN STD_LOGIC ;
+- q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
+- );
+-end component;
+-
+--- Register inputs in the bus clock domain
+-signal di_r : std_logic_vector(6 downto 0);
+-signal dew_r : std_logic;
+-signal lose_r : std_logic;
+--- Data input registered in the pixel clock domain
+-signal code : std_logic_vector(6 downto 0);
+-signal line_addr : unsigned(3 downto 0);
+-signal rom_address : std_logic_vector(11 downto 0);
+-signal rom_data : std_logic_vector(7 downto 0);
+-
+--- Delayed display enable derived from LOSE by delaying for one character
+-signal disp_enable : std_logic;
+--- Latched timing signals for detection of falling edges
+-signal dew_latch : std_logic;
+-signal lose_latch : std_logic;
+-signal disp_enable_latch : std_logic;
+-
+--- Row and column addressing is handled externally. We just need to
+--- keep track of which of the 10 lines we are on within the character...
+-signal line_counter : unsigned(3 downto 0);
+--- ... and which of the 6 pixels we are on within each line
+-signal pixel_counter : unsigned(2 downto 0);
+--- We also need to count frames to implement the flash feature.
+--- The datasheet says this is 0.75 Hz with a 3:1 on/off ratio, so it
+--- is probably a /64 counter, which gives us 0.78 Hz
+-signal flash_counter : unsigned(5 downto 0);
+--- Output shift register
+-signal shift_reg : std_logic_vector(5 downto 0);
+-
+--- Flash mask
+-signal flash : std_logic;
+-
+--- Current display state
+--- Foreground colour (B2, G1, R0)
+-signal fg : std_logic_vector(2 downto 0);
+--- Background colour (B2, G1, R0)
+-signal bg : std_logic_vector(2 downto 0);
+-signal conceal : std_logic;
+-signal gfx : std_logic;
+-signal gfx_sep : std_logic;
+-signal gfx_hold : std_logic;
+-signal is_flash : std_logic;
+-signal double_high : std_logic;
+--- Set in first row of double height
+-signal double_high1 : std_logic;
+--- Set in second row of double height
+-signal double_high2 : std_logic;
+-
+-begin
+- char_rom: saa5050_rom port map (
+- rom_address,
+- CLOCK,
+- rom_data
+- );
+-
+- -- Generate flash signal for 3:1 ratio
+- flash <= flash_counter(5) and flash_counter(4);
+-
+- -- Sync inputs
+- process(DI_CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- di_r <= (others => '0');
+- dew_r <= '0';
+- lose_r <= '0';
+- elsif rising_edge(DI_CLOCK) and DI_CLKEN = '1' then
+- di_r <= DI;
+- dew_r <= DEW;
+- lose_r <= LOSE;
+- end if;
+- end process;
+-
+- -- Register data into pixel clock domain
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- code <= (others => '0');
+- elsif rising_edge(CLOCK) and CLKEN = '1' then
+- code <= di_r;
+- end if;
+- end process;
+-
+- -- Generate character rom address in pixel clock domain
+- -- This is done combinatorially since all the inputs are already
+- -- registered and the address is re-registered by the ROM
+- line_addr <= line_counter when double_high = '0' else
+- ("0" & line_counter(3 downto 1)) when double_high2 = '0' else
+- ("0" & line_counter(3 downto 1)) + 5;
+- rom_address <= (others => '0') when (double_high = '0' and double_high2 = '1') else
+- gfx & code & std_logic_vector(line_addr);
+-
+- -- Character row and pixel counters
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- dew_latch <= '0';
+- lose_latch <= '0';
+- disp_enable <= '0';
+- disp_enable_latch <= '0';
+- double_high1 <= '0';
+- double_high2 <= '0';
+- line_counter <= (others => '0');
+- pixel_counter <= (others => '0');
+- flash_counter <= (others => '0');
+- elsif rising_edge(CLOCK) and CLKEN = '1' then
+- -- Register syncs for edge detection
+- dew_latch <= dew_r;
+- lose_latch <= lose_r;
+- disp_enable_latch <= disp_enable;
+-
+- -- When first entering double-height mode start on top row
+- if double_high = '1' and double_high1 = '0' and double_high2 = '0' then
+- double_high1 <= '1';
+- end if;
+-
+- -- Count pixels between 0 and 5
+- if pixel_counter = 5 then
+- -- Start of next character and delayed display enable
+- pixel_counter <= (others => '0');
+- disp_enable <= lose_latch;
+- else
+- pixel_counter <= pixel_counter + 1;
+- end if;
+-
+- -- Rising edge of LOSE is the start of the active line
+- if lose_r = '1' and lose_latch = '0' then
+- -- Reset pixel counter - small offset to make the output
+- -- line up with the cursor from the video ULA
+- pixel_counter <= "011";
+- end if;
+-
+- -- Count frames on end of VSYNC (falling edge of DEW)
+- if dew_r = '0' and dew_latch = '1' then
+- flash_counter <= flash_counter + 1;
+- end if;
+-
+- if dew_r = '1' then
+- -- Reset line counter and double height state during VSYNC
+- line_counter <= (others => '0');
+- double_high1 <= '0';
+- double_high2 <= '0';
+- else
+- -- Count lines on end of active video (falling edge of disp_enable)
+- if disp_enable = '0' and disp_enable_latch = '1' then
+- if line_counter = 9 then
+- line_counter <= (others => '0');
+-
+- -- Keep track of which row we are on for double-height
+- -- The double_high flag can be cleared before the end of a row, but if
+- -- double height characters are used anywhere on a row then the double_high1
+- -- flag will be set and remain set until the next row. This is used
+- -- to determine that the bottom half of the characters should be shown if
+- -- double_high is set once again on the row below.
+- double_high1 <= '0';
+- double_high2 <= double_high1;
+- else
+- line_counter <= line_counter + 1;
+- end if;
+- end if;
+- end if;
+- end if;
+- end process;
+-
+- -- Shift register
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- shift_reg <= (others => '0');
+- elsif rising_edge(CLOCK) and CLKEN = '1' then
+- if disp_enable = '1' and pixel_counter = 0 then
+- -- Load the shift register with the ROM bit pattern
+- -- at the start of each character while disp_enable is asserted.
+- shift_reg <= rom_data(5 downto 0);
+-
+- -- If bit 7 of the ROM data is set then this is a graphics
+- -- character and separated/hold graphics modes apply.
+- -- We don't just assume this to be the case if gfx=1 because
+- -- these modes don't apply to caps even in graphics mode
+- if rom_data(7) = '1' then
+- -- Apply a mask for separated graphics mode
+- if gfx_sep = '1' then
+- shift_reg(5) <= '0';
+- shift_reg(2) <= '0';
+- if line_counter = 2 or line_counter = 6 or line_counter = 9 then
+- shift_reg <= (others => '0');
+- end if;
+- end if;
+- end if;
+- else
+- -- Pump the shift register
+- shift_reg <= shift_reg(4 downto 0) & "0";
+- end if;
+- end if;
+- end process;
+-
+- -- Control character handling
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- fg <= (others => '1');
+- bg <= (others => '0');
+- conceal <= '0';
+- gfx <= '0';
+- gfx_sep <= '0';
+- gfx_hold <= '0';
+- is_flash <= '0';
+- double_high <= '0';
+- elsif rising_edge(CLOCK) and CLKEN = '1' then
+- if disp_enable = '0' then
+- -- Reset to start of line defaults
+- fg <= (others => '1');
+- bg <= (others => '0');
+- conceal <= '0';
+- gfx <= '0';
+- gfx_sep <= '0';
+- gfx_hold <= '0';
+- is_flash <= '0';
+- double_high <= '0';
+- elsif pixel_counter = 0 then
+- -- Latch new control codes at the start of each character
+- if code(6 downto 5) = "00" then
+- if code(3) = '0' then
+- -- Colour and graphics setting clears conceal mode
+- conceal <= '0';
+-
+- -- Select graphics or alpha mode
+- gfx <= code(4);
+-
+- -- 0 would be black but is not allowed so has no effect,
+- -- otherwise set the colour
+- if code(2 downto 0) /= "000" then
+- fg <= code(2 downto 0);
+- end if;
+- else
+- case code(4 downto 0) is
+- -- FLASH
+- when "01000" => is_flash <= '1';
+- -- STEADY
+- when "01001" => is_flash <= '0';
+- -- NORMAL HEIGHT
+- when "01100" => double_high <= '0';
+- -- DOUBLE HEIGHT
+- when "01101" => double_high <= '1';
+- -- CONCEAL
+- when "11000" => conceal <= '1';
+- -- CONTIGUOUS GFX
+- when "11001" => gfx_sep <= '0';
+- -- SEPARATED GFX
+- when "11010" => gfx_sep <= '1';
+- -- BLACK BACKGROUND
+- when "11100" => bg <= (others => '0');
+- -- NEW BACKGROUND
+- when "11101" => bg <= fg;
+- -- HOLD GFX
+- when "11110" => gfx_hold <= '1';
+- -- RELEASE GFX
+- when "11111" => gfx_hold <= '0';
+-
+- when others => null;
+- end case;
+- end if;
+- end if;
+- end if;
+- end if;
+- end process;
+-
+- -- Output
+- process(CLOCK,nRESET)
+- variable pixel : std_logic;
+- begin
+- pixel := shift_reg(5) and not ((flash and is_flash) or conceal);
+-
+- if nRESET = '0' then
+- R <= '0';
+- G <= '0';
+- B <= '0';
+- elsif rising_edge(CLOCK) and CLKEN = '1' then
+- -- Generate mono output
+- Y <= pixel;
+-
+- -- Generate colour output
+- if pixel = '1' then
+- R <= fg(0);
+- G <= fg(1);
+- B <= fg(2);
+- else
+- R <= bg(0);
+- G <= bg(1);
+- B <= bg(2);
+- end if;
+- end if;
+- end process;
+-end architecture;
++-- BBC Micro for Altera DE1 ++-- ++-- Copyright (c) 2011 Mike Stirling ++-- ++-- 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 agreement from the author. ++-- ++-- * License is granted for non-commercial use only. A fee may not be charged ++-- for redistributions as source code or in synthesized/hardware form without ++-- specific prior written agreement from the author. ++-- ++-- 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. ++-- ++-- SAA5050 teletext generator ++-- ++-- Synchronous implementation for FPGA. Certain TV-specific functions are ++-- not implemented. e.g. ++-- ++-- No /SI pin - 'TEXT' mode is permanently enabled ++-- No remote control features (/DATA, DLIM) ++-- No large character support ++-- No support for box overlay (BLAN, PO, DE) ++-- No character rounding, although this may be added ++-- ++-- FIXME: Hold graphics not supported - this needs to be added ++-- ++-- (C) 2011 Mike Stirling ++-- ++library IEEE; ++use IEEE.STD_LOGIC_1164.ALL; ++use IEEE.NUMERIC_STD.ALL; ++ ++entity saa5050 is ++port ( ++ CLOCK : in std_logic; ++ -- 6 MHz dot clock enable ++ CLKEN : in std_logic; ++ -- Async reset ++ nRESET : in std_logic; ++ ++ -- Character data input (in the bus clock domain) ++ DI_CLOCK : in std_logic; ++ DI_CLKEN : in std_logic; ++ DI : in std_logic_vector(6 downto 0); ++ ++ -- Timing inputs ++ -- General line reset (not used) ++ GLR : in std_logic; -- /HSYNC ++ -- Data entry window - high during VSYNC. ++ -- Resets ROM row counter and drives 'flash' signal ++ DEW : in std_logic; -- VSYNC ++ -- Character rounding select - high during even field ++ CRS : in std_logic; -- FIELD ++ -- Load output shift register enable - high during active video ++ LOSE : in std_logic; -- DE ++ ++ -- Video out ++ R : out std_logic; ++ G : out std_logic; ++ B : out std_logic; ++ Y : out std_logic ++ ); ++end entity; ++ ++architecture rtl of saa5050 is ++ ++component saa5050_rom IS ++ PORT ++ ( ++ address : IN STD_LOGIC_VECTOR (11 DOWNTO 0); ++ clock : IN STD_LOGIC ; ++ q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) ++ ); ++end component; ++ ++-- Register inputs in the bus clock domain ++signal di_r : std_logic_vector(6 downto 0); ++signal dew_r : std_logic; ++signal lose_r : std_logic; ++-- Data input registered in the pixel clock domain ++signal code : std_logic_vector(6 downto 0); ++signal line_addr : unsigned(3 downto 0); ++signal rom_address : std_logic_vector(11 downto 0); ++signal rom_data : std_logic_vector(7 downto 0); ++ ++-- Delayed display enable derived from LOSE by delaying for one character ++signal disp_enable : std_logic; ++-- Latched timing signals for detection of falling edges ++signal dew_latch : std_logic; ++signal lose_latch : std_logic; ++signal disp_enable_latch : std_logic; ++ ++-- Row and column addressing is handled externally. We just need to ++-- keep track of which of the 10 lines we are on within the character... ++signal line_counter : unsigned(3 downto 0); ++-- ... and which of the 6 pixels we are on within each line ++signal pixel_counter : unsigned(2 downto 0); ++-- We also need to count frames to implement the flash feature. ++-- The datasheet says this is 0.75 Hz with a 3:1 on/off ratio, so it ++-- is probably a /64 counter, which gives us 0.78 Hz ++signal flash_counter : unsigned(5 downto 0); ++-- Output shift register ++signal shift_reg : std_logic_vector(5 downto 0); ++ ++-- Flash mask ++signal flash : std_logic; ++ ++-- Current display state ++-- Foreground colour (B2, G1, R0) ++signal fg : std_logic_vector(2 downto 0); ++-- Background colour (B2, G1, R0) ++signal bg : std_logic_vector(2 downto 0); ++signal conceal : std_logic; ++signal gfx : std_logic; ++signal gfx_sep : std_logic; ++signal gfx_hold : std_logic; ++signal is_flash : std_logic; ++signal double_high : std_logic; ++-- Set in first row of double height ++signal double_high1 : std_logic; ++-- Set in second row of double height ++signal double_high2 : std_logic; ++ ++begin ++ char_rom: saa5050_rom port map ( ++ rom_address, ++ CLOCK, ++ rom_data ++ ); ++ ++ -- Generate flash signal for 3:1 ratio ++ flash <= flash_counter(5) and flash_counter(4); ++ ++ -- Sync inputs ++ process(DI_CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ di_r <= (others => '0'); ++ dew_r <= '0'; ++ lose_r <= '0'; ++ elsif rising_edge(DI_CLOCK) and DI_CLKEN = '1' then ++ di_r <= DI; ++ dew_r <= DEW; ++ lose_r <= LOSE; ++ end if; ++ end process; ++ ++ -- Register data into pixel clock domain ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ code <= (others => '0'); ++ elsif rising_edge(CLOCK) and CLKEN = '1' then ++ code <= di_r; ++ end if; ++ end process; ++ ++ -- Generate character rom address in pixel clock domain ++ -- This is done combinatorially since all the inputs are already ++ -- registered and the address is re-registered by the ROM ++ line_addr <= line_counter when double_high = '0' else ++ ("0" & line_counter(3 downto 1)) when double_high2 = '0' else ++ ("0" & line_counter(3 downto 1)) + 5; ++ rom_address <= (others => '0') when (double_high = '0' and double_high2 = '1') else ++ gfx & code & std_logic_vector(line_addr); ++ ++ -- Character row and pixel counters ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ dew_latch <= '0'; ++ lose_latch <= '0'; ++ disp_enable <= '0'; ++ disp_enable_latch <= '0'; ++ double_high1 <= '0'; ++ double_high2 <= '0'; ++ line_counter <= (others => '0'); ++ pixel_counter <= (others => '0'); ++ flash_counter <= (others => '0'); ++ elsif rising_edge(CLOCK) and CLKEN = '1' then ++ -- Register syncs for edge detection ++ dew_latch <= dew_r; ++ lose_latch <= lose_r; ++ disp_enable_latch <= disp_enable; ++ ++ -- When first entering double-height mode start on top row ++ if double_high = '1' and double_high1 = '0' and double_high2 = '0' then ++ double_high1 <= '1'; ++ end if; ++ ++ -- Count pixels between 0 and 5 ++ if pixel_counter = 5 then ++ -- Start of next character and delayed display enable ++ pixel_counter <= (others => '0'); ++ disp_enable <= lose_latch; ++ else ++ pixel_counter <= pixel_counter + 1; ++ end if; ++ ++ -- Rising edge of LOSE is the start of the active line ++ if lose_r = '1' and lose_latch = '0' then ++ -- Reset pixel counter - small offset to make the output ++ -- line up with the cursor from the video ULA ++ pixel_counter <= "011"; ++ end if; ++ ++ -- Count frames on end of VSYNC (falling edge of DEW) ++ if dew_r = '0' and dew_latch = '1' then ++ flash_counter <= flash_counter + 1; ++ end if; ++ ++ if dew_r = '1' then ++ -- Reset line counter and double height state during VSYNC ++ line_counter <= (others => '0'); ++ double_high1 <= '0'; ++ double_high2 <= '0'; ++ else ++ -- Count lines on end of active video (falling edge of disp_enable) ++ if disp_enable = '0' and disp_enable_latch = '1' then ++ if line_counter = 9 then ++ line_counter <= (others => '0'); ++ ++ -- Keep track of which row we are on for double-height ++ -- The double_high flag can be cleared before the end of a row, but if ++ -- double height characters are used anywhere on a row then the double_high1 ++ -- flag will be set and remain set until the next row. This is used ++ -- to determine that the bottom half of the characters should be shown if ++ -- double_high is set once again on the row below. ++ double_high1 <= '0'; ++ double_high2 <= double_high1; ++ else ++ line_counter <= line_counter + 1; ++ end if; ++ end if; ++ end if; ++ end if; ++ end process; ++ ++ -- Shift register ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ shift_reg <= (others => '0'); ++ elsif rising_edge(CLOCK) and CLKEN = '1' then ++ if disp_enable = '1' and pixel_counter = 0 then ++ -- Load the shift register with the ROM bit pattern ++ -- at the start of each character while disp_enable is asserted. ++ shift_reg <= rom_data(5 downto 0); ++ ++ -- If bit 7 of the ROM data is set then this is a graphics ++ -- character and separated/hold graphics modes apply. ++ -- We don't just assume this to be the case if gfx=1 because ++ -- these modes don't apply to caps even in graphics mode ++ if rom_data(7) = '1' then ++ -- Apply a mask for separated graphics mode ++ if gfx_sep = '1' then ++ shift_reg(5) <= '0'; ++ shift_reg(2) <= '0'; ++ if line_counter = 2 or line_counter = 6 or line_counter = 9 then ++ shift_reg <= (others => '0'); ++ end if; ++ end if; ++ end if; ++ else ++ -- Pump the shift register ++ shift_reg <= shift_reg(4 downto 0) & "0"; ++ end if; ++ end if; ++ end process; ++ ++ -- Control character handling ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ fg <= (others => '1'); ++ bg <= (others => '0'); ++ conceal <= '0'; ++ gfx <= '0'; ++ gfx_sep <= '0'; ++ gfx_hold <= '0'; ++ is_flash <= '0'; ++ double_high <= '0'; ++ elsif rising_edge(CLOCK) and CLKEN = '1' then ++ if disp_enable = '0' then ++ -- Reset to start of line defaults ++ fg <= (others => '1'); ++ bg <= (others => '0'); ++ conceal <= '0'; ++ gfx <= '0'; ++ gfx_sep <= '0'; ++ gfx_hold <= '0'; ++ is_flash <= '0'; ++ double_high <= '0'; ++ elsif pixel_counter = 0 then ++ -- Latch new control codes at the start of each character ++ if code(6 downto 5) = "00" then ++ if code(3) = '0' then ++ -- Colour and graphics setting clears conceal mode ++ conceal <= '0'; ++ ++ -- Select graphics or alpha mode ++ gfx <= code(4); ++ ++ -- 0 would be black but is not allowed so has no effect, ++ -- otherwise set the colour ++ if code(2 downto 0) /= "000" then ++ fg <= code(2 downto 0); ++ end if; ++ else ++ case code(4 downto 0) is ++ -- FLASH ++ when "01000" => is_flash <= '1'; ++ -- STEADY ++ when "01001" => is_flash <= '0'; ++ -- NORMAL HEIGHT ++ when "01100" => double_high <= '0'; ++ -- DOUBLE HEIGHT ++ when "01101" => double_high <= '1'; ++ -- CONCEAL ++ when "11000" => conceal <= '1'; ++ -- CONTIGUOUS GFX ++ when "11001" => gfx_sep <= '0'; ++ -- SEPARATED GFX ++ when "11010" => gfx_sep <= '1'; ++ -- BLACK BACKGROUND ++ when "11100" => bg <= (others => '0'); ++ -- NEW BACKGROUND ++ when "11101" => bg <= fg; ++ -- HOLD GFX ++ when "11110" => gfx_hold <= '1'; ++ -- RELEASE GFX ++ when "11111" => gfx_hold <= '0'; ++ ++ when others => null; ++ end case; ++ end if; ++ end if; ++ end if; ++ end if; ++ end process; ++ ++ -- Output ++ process(CLOCK,nRESET) ++ variable pixel : std_logic; ++ begin ++ pixel := shift_reg(5) and not ((flash and is_flash) or conceal); ++ ++ if nRESET = '0' then ++ R <= '0'; ++ G <= '0'; ++ B <= '0'; ++ elsif rising_edge(CLOCK) and CLKEN = '1' then ++ -- Generate mono output ++ Y <= pixel; ++ ++ -- Generate colour output ++ if pixel = '1' then ++ R <= fg(0); ++ G <= fg(1); ++ B <= fg(2); ++ else ++ R <= bg(0); ++ G <= bg(1); ++ B <= bg(2); ++ end if; ++ end if; ++ end process; ++end architecture; +diff --git a/saa5050_rom.qip b/saa5050_rom.qip +index e9513f7..be776f1 100644 +--- a/saa5050_rom.qip ++++ b/saa5050_rom.qip +@@ -1,3 +1,3 @@ +-set_global_assignment -name IP_TOOL_NAME "ROM: 1-PORT"
+-set_global_assignment -name IP_TOOL_VERSION "9.1"
+-set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "saa5050_rom.vhd"]
++set_global_assignment -name IP_TOOL_NAME "ROM: 1-PORT" ++set_global_assignment -name IP_TOOL_VERSION "9.1" ++set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "saa5050_rom.vhd"] +diff --git a/saa5050_rom.vhd b/saa5050_rom.vhd +index 7541c0b..e1c702d 100644 +--- a/saa5050_rom.vhd ++++ b/saa5050_rom.vhd +@@ -1,168 +1,168 @@ +--- megafunction wizard: %ROM: 1-PORT%
+--- GENERATION: STANDARD
+--- VERSION: WM1.0
+--- MODULE: altsyncram
+-
+--- ============================================================
+--- File Name: saa5050_rom.vhd
+--- Megafunction Name(s):
+--- altsyncram
+---
+--- Simulation Library Files(s):
+--- altera_mf
+--- ============================================================
+--- ************************************************************
+--- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE!
+---
+--- 9.1 Build 222 10/21/2009 SJ Web Edition
+--- ************************************************************
+-
+-
+---Copyright (C) 1991-2009 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.
+-
+-
+-LIBRARY ieee;
+-USE ieee.std_logic_1164.all;
+-
+-LIBRARY altera_mf;
+-USE altera_mf.all;
+-
+-ENTITY saa5050_rom IS
+- PORT
+- (
+- address : IN STD_LOGIC_VECTOR (11 DOWNTO 0);
+- clock : IN STD_LOGIC ;
+- q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
+- );
+-END saa5050_rom;
+-
+-
+-ARCHITECTURE SYN OF saa5050_rom IS
+-
+- SIGNAL sub_wire0 : STD_LOGIC_VECTOR (7 DOWNTO 0);
+-
+-
+-
+- COMPONENT altsyncram
+- GENERIC (
+- clock_enable_input_a : STRING;
+- clock_enable_output_a : STRING;
+- init_file : STRING;
+- intended_device_family : STRING;
+- lpm_hint : STRING;
+- lpm_type : STRING;
+- numwords_a : NATURAL;
+- operation_mode : STRING;
+- outdata_aclr_a : STRING;
+- outdata_reg_a : STRING;
+- widthad_a : NATURAL;
+- width_a : NATURAL;
+- width_byteena_a : NATURAL
+- );
+- PORT (
+- clock0 : IN STD_LOGIC ;
+- address_a : IN STD_LOGIC_VECTOR (11 DOWNTO 0);
+- q_a : OUT STD_LOGIC_VECTOR (7 DOWNTO 0)
+- );
+- END COMPONENT;
+-
+-BEGIN
+- q <= sub_wire0(7 DOWNTO 0);
+-
+- altsyncram_component : altsyncram
+- GENERIC MAP (
+- clock_enable_input_a => "BYPASS",
+- clock_enable_output_a => "BYPASS",
+- init_file => "./roms/saa5050/saa5050.hex",
+- intended_device_family => "Cyclone II",
+- lpm_hint => "ENABLE_RUNTIME_MOD=NO",
+- lpm_type => "altsyncram",
+- numwords_a => 4096,
+- operation_mode => "ROM",
+- outdata_aclr_a => "NONE",
+- outdata_reg_a => "UNREGISTERED",
+- widthad_a => 12,
+- width_a => 8,
+- width_byteena_a => 1
+- )
+- PORT MAP (
+- clock0 => clock,
+- address_a => address,
+- q_a => sub_wire0
+- );
+-
+-
+-
+-END SYN;
+-
+--- ============================================================
+--- CNX file retrieval info
+--- ============================================================
+--- Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0"
+--- Retrieval info: PRIVATE: AclrAddr NUMERIC "0"
+--- Retrieval info: PRIVATE: AclrByte NUMERIC "0"
+--- Retrieval info: PRIVATE: AclrOutput NUMERIC "0"
+--- Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "0"
+--- Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8"
+--- Retrieval info: PRIVATE: BlankMemory NUMERIC "0"
+--- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0"
+--- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0"
+--- Retrieval info: PRIVATE: Clken NUMERIC "0"
+--- Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0"
+--- Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A"
+--- Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0"
+--- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II"
+--- 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/saa5050/saa5050.hex"
+--- Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "4096"
+--- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0"
+--- Retrieval info: PRIVATE: RegAddr NUMERIC "1"
+--- Retrieval info: PRIVATE: RegOutput NUMERIC "0"
+--- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0"
+--- Retrieval info: PRIVATE: SingleClock NUMERIC "1"
+--- Retrieval info: PRIVATE: UseDQRAM NUMERIC "0"
+--- Retrieval info: PRIVATE: WidthAddr NUMERIC "12"
+--- Retrieval info: PRIVATE: WidthData NUMERIC "8"
+--- Retrieval info: PRIVATE: rden NUMERIC "0"
+--- 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/saa5050/saa5050.hex"
+--- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II"
+--- Retrieval info: CONSTANT: LPM_HINT STRING "ENABLE_RUNTIME_MOD=NO"
+--- Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram"
+--- Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "4096"
+--- Retrieval info: CONSTANT: OPERATION_MODE STRING "ROM"
+--- Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE"
+--- Retrieval info: CONSTANT: OUTDATA_REG_A STRING "UNREGISTERED"
+--- Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "12"
+--- Retrieval info: CONSTANT: WIDTH_A NUMERIC "8"
+--- Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1"
+--- Retrieval info: USED_PORT: address 0 0 12 0 INPUT NODEFVAL address[11..0]
+--- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL clock
+--- Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL q[7..0]
+--- Retrieval info: CONNECT: @address_a 0 0 12 0 address 0 0 12 0
+--- Retrieval info: CONNECT: q 0 0 8 0 @q_a 0 0 8 0
+--- Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0
+--- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all
+--- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.vhd TRUE
+--- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.inc FALSE
+--- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.cmp FALSE
+--- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.bsf FALSE
+--- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom_inst.vhd FALSE
+--- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom_waveforms.html FALSE
+--- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom_wave*.jpg FALSE
+--- Retrieval info: LIB_FILE: altera_mf
++-- megafunction wizard: %ROM: 1-PORT% ++-- GENERATION: STANDARD ++-- VERSION: WM1.0 ++-- MODULE: altsyncram ++ ++-- ============================================================ ++-- File Name: saa5050_rom.vhd ++-- Megafunction Name(s): ++-- altsyncram ++-- ++-- Simulation Library Files(s): ++-- altera_mf ++-- ============================================================ ++-- ************************************************************ ++-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! ++-- ++-- 9.1 Build 222 10/21/2009 SJ Web Edition ++-- ************************************************************ ++ ++ ++--Copyright (C) 1991-2009 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. ++ ++ ++LIBRARY ieee; ++USE ieee.std_logic_1164.all; ++ ++LIBRARY altera_mf; ++USE altera_mf.all; ++ ++ENTITY saa5050_rom IS ++ PORT ++ ( ++ address : IN STD_LOGIC_VECTOR (11 DOWNTO 0); ++ clock : IN STD_LOGIC ; ++ q : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) ++ ); ++END saa5050_rom; ++ ++ ++ARCHITECTURE SYN OF saa5050_rom IS ++ ++ SIGNAL sub_wire0 : STD_LOGIC_VECTOR (7 DOWNTO 0); ++ ++ ++ ++ COMPONENT altsyncram ++ GENERIC ( ++ clock_enable_input_a : STRING; ++ clock_enable_output_a : STRING; ++ init_file : STRING; ++ intended_device_family : STRING; ++ lpm_hint : STRING; ++ lpm_type : STRING; ++ numwords_a : NATURAL; ++ operation_mode : STRING; ++ outdata_aclr_a : STRING; ++ outdata_reg_a : STRING; ++ widthad_a : NATURAL; ++ width_a : NATURAL; ++ width_byteena_a : NATURAL ++ ); ++ PORT ( ++ clock0 : IN STD_LOGIC ; ++ address_a : IN STD_LOGIC_VECTOR (11 DOWNTO 0); ++ q_a : OUT STD_LOGIC_VECTOR (7 DOWNTO 0) ++ ); ++ END COMPONENT; ++ ++BEGIN ++ q <= sub_wire0(7 DOWNTO 0); ++ ++ altsyncram_component : altsyncram ++ GENERIC MAP ( ++ clock_enable_input_a => "BYPASS", ++ clock_enable_output_a => "BYPASS", ++ init_file => "./roms/saa5050/saa5050.hex", ++ intended_device_family => "Cyclone II", ++ lpm_hint => "ENABLE_RUNTIME_MOD=NO", ++ lpm_type => "altsyncram", ++ numwords_a => 4096, ++ operation_mode => "ROM", ++ outdata_aclr_a => "NONE", ++ outdata_reg_a => "UNREGISTERED", ++ widthad_a => 12, ++ width_a => 8, ++ width_byteena_a => 1 ++ ) ++ PORT MAP ( ++ clock0 => clock, ++ address_a => address, ++ q_a => sub_wire0 ++ ); ++ ++ ++ ++END SYN; ++ ++-- ============================================================ ++-- CNX file retrieval info ++-- ============================================================ ++-- Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0" ++-- Retrieval info: PRIVATE: AclrAddr NUMERIC "0" ++-- Retrieval info: PRIVATE: AclrByte NUMERIC "0" ++-- Retrieval info: PRIVATE: AclrOutput NUMERIC "0" ++-- Retrieval info: PRIVATE: BYTE_ENABLE NUMERIC "0" ++-- Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "8" ++-- Retrieval info: PRIVATE: BlankMemory NUMERIC "0" ++-- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "0" ++-- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "0" ++-- Retrieval info: PRIVATE: Clken NUMERIC "0" ++-- Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0" ++-- Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_A" ++-- Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "0" ++-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II" ++-- 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/saa5050/saa5050.hex" ++-- Retrieval info: PRIVATE: NUMWORDS_A NUMERIC "4096" ++-- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" ++-- Retrieval info: PRIVATE: RegAddr NUMERIC "1" ++-- Retrieval info: PRIVATE: RegOutput NUMERIC "0" ++-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" ++-- Retrieval info: PRIVATE: SingleClock NUMERIC "1" ++-- Retrieval info: PRIVATE: UseDQRAM NUMERIC "0" ++-- Retrieval info: PRIVATE: WidthAddr NUMERIC "12" ++-- Retrieval info: PRIVATE: WidthData NUMERIC "8" ++-- Retrieval info: PRIVATE: rden NUMERIC "0" ++-- 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/saa5050/saa5050.hex" ++-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II" ++-- Retrieval info: CONSTANT: LPM_HINT STRING "ENABLE_RUNTIME_MOD=NO" ++-- Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram" ++-- Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "4096" ++-- Retrieval info: CONSTANT: OPERATION_MODE STRING "ROM" ++-- Retrieval info: CONSTANT: OUTDATA_ACLR_A STRING "NONE" ++-- Retrieval info: CONSTANT: OUTDATA_REG_A STRING "UNREGISTERED" ++-- Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "12" ++-- Retrieval info: CONSTANT: WIDTH_A NUMERIC "8" ++-- Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" ++-- Retrieval info: USED_PORT: address 0 0 12 0 INPUT NODEFVAL address[11..0] ++-- Retrieval info: USED_PORT: clock 0 0 0 0 INPUT NODEFVAL clock ++-- Retrieval info: USED_PORT: q 0 0 8 0 OUTPUT NODEFVAL q[7..0] ++-- Retrieval info: CONNECT: @address_a 0 0 12 0 address 0 0 12 0 ++-- Retrieval info: CONNECT: q 0 0 8 0 @q_a 0 0 8 0 ++-- Retrieval info: CONNECT: @clock0 0 0 0 0 clock 0 0 0 0 ++-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all ++-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.vhd TRUE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.inc FALSE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.cmp FALSE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom.bsf FALSE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom_inst.vhd FALSE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom_waveforms.html FALSE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL saa5050_rom_wave*.jpg FALSE ++-- Retrieval info: LIB_FILE: altera_mf +diff --git a/seg7.vhd b/seg7.vhd +index a61e679..566b1f6 100644 +--- a/seg7.vhd ++++ b/seg7.vhd +@@ -1,68 +1,68 @@ +--- BBC Micro for Altera DE1
+---
+--- Copyright (c) 2009-2011 Mike Stirling
+---
+--- 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 agreement from the author.
+---
+--- * License is granted for non-commercial use only. A fee may not be charged
+--- for redistributions as source code or in synthesized/hardware form without
+--- specific prior written agreement from the author.
+---
+--- 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.
+---
+-
+-library ieee;
+-use ieee.std_logic_1164.all;
+-
+--- Convert BCD to 7-segment display characters
+-entity seg7 is
+-port (
+- D : in std_logic_vector(3 downto 0);
+- Q : out std_logic_vector(6 downto 0)
+-);
+-end seg7;
+-
+-architecture seg7_arch of seg7 is
+-begin
+- Q <= "1000000" when D = "0000" else
+- "1111001" when D = "0001" else
+- "0100100" when D = "0010" else
+- "0110000" when D = "0011" else
+- "0011001" when D = "0100" else
+- "0010010" when D = "0101" else
+- "0000010" when D = "0110" else
+- "1111000" when D = "0111" else
+- "0000000" when D = "1000" else
+- "0010000" when D = "1001" else
+- "0001000" when D = "1010" else
+- "0000011" when D = "1011" else
+- "1000110" when D = "1100" else
+- "0100001" when D = "1101" else
+- "0000110" when D = "1110" else
+- "0001110";
+-end seg7_arch;
+-
++-- BBC Micro for Altera DE1 ++-- ++-- Copyright (c) 2009-2011 Mike Stirling ++-- ++-- 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 agreement from the author. ++-- ++-- * License is granted for non-commercial use only. A fee may not be charged ++-- for redistributions as source code or in synthesized/hardware form without ++-- specific prior written agreement from the author. ++-- ++-- 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. ++-- ++ ++library ieee; ++use ieee.std_logic_1164.all; ++ ++-- Convert BCD to 7-segment display characters ++entity seg7 is ++port ( ++ D : in std_logic_vector(3 downto 0); ++ Q : out std_logic_vector(6 downto 0) ++); ++end seg7; ++ ++architecture seg7_arch of seg7 is ++begin ++ Q <= "1000000" when D = "0000" else ++ "1111001" when D = "0001" else ++ "0100100" when D = "0010" else ++ "0110000" when D = "0011" else ++ "0011001" when D = "0100" else ++ "0010010" when D = "0101" else ++ "0000010" when D = "0110" else ++ "1111000" when D = "0111" else ++ "0000000" when D = "1000" else ++ "0010000" when D = "1001" else ++ "0001000" when D = "1010" else ++ "0000011" when D = "1011" else ++ "1000110" when D = "1100" else ++ "0100001" when D = "1101" else ++ "0000110" when D = "1110" else ++ "0001110"; ++end seg7_arch; ++ +diff --git a/sn76489-1.0/sn76489_top.vhd b/sn76489-1.0/sn76489_top.vhd +index 277f601..deb8170 100644 +--- a/sn76489-1.0/sn76489_top.vhd ++++ b/sn76489-1.0/sn76489_top.vhd +@@ -196,15 +196,15 @@ begin + noise_o => noise_s + ); + +-
++ + -- Register output +- process(clock_i)
+- begin
+- if res_n_i = '0' then
+- aout_o <= (others => '0');
+- elsif rising_edge(clock_i) then
+- aout_o <= tone1_s + tone2_s + tone3_s + noise_s;
+- end if;
+- end process;
++ process(clock_i) ++ begin ++ if res_n_i = '0' then ++ aout_o <= (others => '0'); ++ elsif rising_edge(clock_i) then ++ aout_o <= tone1_s + tone2_s + tone3_s + noise_s; ++ end if; ++ end process; + + end struct; +diff --git a/vidproc.vhd b/vidproc.vhd +index 6d5f91f..25f3d75 100644 +--- a/vidproc.vhd ++++ b/vidproc.vhd +@@ -1,279 +1,279 @@ +--- BBC Micro for Altera DE1
+---
+--- Copyright (c) 2011 Mike Stirling
+---
+--- 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 agreement from the author.
+---
+--- * License is granted for non-commercial use only. A fee may not be charged
+--- for redistributions as source code or in synthesized/hardware form without
+--- specific prior written agreement from the author.
+---
+--- 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.
+---
+--- BBC Micro "VIDPROC" Video ULA
+---
+--- Synchronous implementation for FPGA
+---
+--- (C) 2011 Mike Stirling
+---
+-library IEEE;
+-use IEEE.STD_LOGIC_1164.ALL;
+-use IEEE.NUMERIC_STD.ALL;
+-
+-entity vidproc is
+-port (
+- CLOCK : in std_logic;
+- -- Clock enable qualifies display cycles (interleaved with CPU cycles)
+- CLKEN : in std_logic;
+- nRESET : in std_logic;
+-
+- -- Clock enable output to CRTC
+- CLKEN_CRTC : out std_logic;
+-
+- -- Bus interface
+- ENABLE : in std_logic;
+- A0 : in std_logic;
+- -- CPU data bus (for register writes)
+- DI_CPU : in std_logic_vector(7 downto 0);
+- -- Display RAM data bus (for display data fetch)
+- DI_RAM : in std_logic_vector(7 downto 0);
+-
+- -- Control interface
+- nINVERT : in std_logic;
+- DISEN : in std_logic;
+- CURSOR : in std_logic;
+-
+- -- Video in (teletext mode)
+- R_IN : in std_logic;
+- G_IN : in std_logic;
+- B_IN : in std_logic;
+-
+- -- Video out
+- R : out std_logic;
+- G : out std_logic;
+- B : out std_logic
+- );
+-end entity;
+-
+-architecture rtl of vidproc is
+--- Write-only registers
+-signal r0_cursor0 : std_logic;
+-signal r0_cursor1 : std_logic;
+-signal r0_cursor2 : std_logic;
+-signal r0_crtc_2mhz : std_logic;
+-signal r0_pixel_rate : std_logic_vector(1 downto 0);
+-signal r0_teletext : std_logic;
+-signal r0_flash : std_logic;
+-
+-type palette_t is array(0 to 15) of std_logic_vector(3 downto 0);
+-signal palette : palette_t;
+-
+--- Pixel shift register
+-signal shiftreg : std_logic_vector(7 downto 0);
+--- Delayed display enable
+-signal delayed_disen : std_logic;
+-
+--- Internal clock enable generation
+-signal clken_pixel : std_logic;
+-signal clken_fetch : std_logic;
+-signal clken_counter : unsigned(3 downto 0);
+-
+--- Cursor generation - can span up to 32 pixels
+--- Segments 0 and 1 are 8 pixels wide
+--- Segment 2 is 16 pixels wide
+-signal cursor_invert : std_logic;
+-signal cursor_active : std_logic;
+-signal cursor_counter : unsigned(1 downto 0);
+-
+-begin
+- -- Synchronous register access, enabled on every clock
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- r0_cursor0 <= '0';
+- r0_cursor1 <= '0';
+- r0_cursor2 <= '0';
+- r0_crtc_2mhz <= '0';
+- r0_pixel_rate <= "00";
+- r0_teletext <= '0';
+- r0_flash <= '0';
+-
+- for colour in 0 to 15 loop
+- palette(colour) <= (others => '0');
+- end loop;
+- elsif rising_edge(CLOCK) then
+- if ENABLE = '1' then
+- if A0 = '0' then
+- -- Access control register
+- r0_cursor0 <= DI_CPU(7);
+- r0_cursor1 <= DI_CPU(6);
+- r0_cursor2 <= DI_CPU(5);
+- r0_crtc_2mhz <= DI_CPU(4);
+- r0_pixel_rate <= DI_CPU(3 downto 2);
+- r0_teletext <= DI_CPU(1);
+- r0_flash <= DI_CPU(0);
+- else
+- -- Access palette register
+- palette(to_integer(unsigned(DI_CPU(7 downto 4)))) <= DI_CPU(3 downto 0);
+- end if;
+- end if;
+- end if;
+- end process;
+-
+- -- Clock enable generation.
+- -- Pixel clock can be divided by 1,2,4 or 8 depending on the value
+- -- programmed at r0_pixel_rate
+- -- 00 = /8, 01 = /4, 10 = /2, 11 = /1
+- clken_pixel <=
+- CLKEN when r0_pixel_rate = "11" else
+- (CLKEN and not clken_counter(0)) when r0_pixel_rate = "10" else
+- (CLKEN and not (clken_counter(0) or clken_counter(1))) when r0_pixel_rate = "01" else
+- (CLKEN and not (clken_counter(0) or clken_counter(1) or clken_counter(2)));
+- -- The CRT controller is always enabled in the 15th cycle, so that the result
+- -- is ready for latching into the shift register in cycle 0. If 2 MHz mode is
+- -- selected then the CRTC is also enabled in the 7th cycle
+- CLKEN_CRTC <= CLKEN and
+- clken_counter(0) and clken_counter(1) and clken_counter(2) and
+- (clken_counter(3) or r0_crtc_2mhz);
+- -- The result is fetched from the CRTC in cycle 0 and also cycle 8 if 2 MHz
+- -- mode is selected. This is used for reloading the shift register as well as
+- -- counting cursor pixels
+- clken_fetch <= CLKEN and not (clken_counter(0) or clken_counter(1) or clken_counter(2) or
+- (clken_counter(3) and not r0_crtc_2mhz));
+-
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- clken_counter <= (others => '0');
+- elsif rising_edge(CLOCK) and CLKEN = '1' then
+- -- Increment internal cycle counter during each video clock
+- clken_counter <= clken_counter + 1;
+- end if;
+- end process;
+-
+- -- Fetch control
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- shiftreg <= (others => '0');
+- elsif rising_edge(CLOCK) and clken_pixel = '1' then
+- if clken_fetch = '1' then
+- -- Fetch next byte from RAM into shift register. This always occurs in
+- -- cycle 0, and also in cycle 8 if the CRTC is clocked at double rate.
+- shiftreg <= DI_RAM;
+- else
+- -- Clock shift register and input '1' at LSB
+- shiftreg <= shiftreg(6 downto 0) & "1";
+- end if;
+- end if;
+- end process;
+-
+- -- Cursor generation
+- cursor_invert <= cursor_active and
+- ((r0_cursor0 and not (cursor_counter(0) or cursor_counter(1))) or
+- (r0_cursor1 and cursor_counter(0) and not cursor_counter(1)) or
+- (r0_cursor2 and cursor_counter(1)));
+- process(CLOCK,nRESET)
+- begin
+- if nRESET = '0' then
+- cursor_active <= '0';
+- cursor_counter <= (others => '0');
+- elsif rising_edge(CLOCK) and clken_fetch = '1' then
+- if CURSOR = '1' or cursor_active = '1' then
+- -- Latch cursor
+- cursor_active <= '1';
+-
+- -- Reset on counter wrap
+- if cursor_counter = "11" then
+- cursor_active <= '0';
+- end if;
+-
+- -- Increment counter
+- if cursor_active = '0' then
+- -- Reset
+- cursor_counter <= (others => '0');
+- else
+- -- Increment
+- cursor_counter <= cursor_counter + 1;
+- end if;
+- end if;
+- end if;
+- end process;
+-
+- -- Pixel generation
+- -- The new shift register contents are loaded during
+- -- cycle 0 (and 8) but will not be read here until the next cycle.
+- -- By running this process on every single video tick instead of at
+- -- the pixel rate we ensure that the resulting delay is minimal and
+- -- constant (running this at the pixel rate would cause
+- -- the display to move slightly depending on which mode was selected).
+- process(CLOCK,nRESET)
+- variable palette_a : std_logic_vector(3 downto 0);
+- variable dot_val : std_logic_vector(3 downto 0);
+- variable red_val : std_logic;
+- variable green_val : std_logic;
+- variable blue_val : std_logic;
+- begin
+- if nRESET = '0' then
+- R <= '0';
+- G <= '0';
+- B <= '0';
+- delayed_disen <= '0';
+- elsif rising_edge(CLOCK) and CLKEN = '1' then
+- -- Look up dot value in the palette. Bits are as follows:
+- -- bit 3 - FLASH
+- -- bit 2 - Not BLUE
+- -- bit 1 - Not GREEN
+- -- bit 0 - Not RED
+- palette_a := shiftreg(7) & shiftreg(5) & shiftreg(3) & shiftreg(1);
+- dot_val := palette(to_integer(unsigned(palette_a)));
+-
+- -- Apply flash inversion if required
+- red_val := (dot_val(3) and r0_flash) xor not dot_val(0);
+- green_val := (dot_val(3) and r0_flash) xor not dot_val(1);
+- blue_val := (dot_val(3) and r0_flash) xor not dot_val(2);
+-
+- -- To output
+- -- FIXME: INVERT option
+- if r0_teletext = '0' then
+- -- Cursor can extend outside the bounds of the screen, so
+- -- it is not affected by DISEN
+- R <= (red_val and delayed_disen) xor cursor_invert;
+- G <= (green_val and delayed_disen) xor cursor_invert;
+- B <= (blue_val and delayed_disen) xor cursor_invert;
+- else
+- R <= R_IN xor cursor_invert;
+- G <= G_IN xor cursor_invert;
+- B <= B_IN xor cursor_invert;
+- end if;
+-
+- -- Display enable signal delayed by one clock
+- delayed_disen <= DISEN;
+- end if;
+- end process;
+-end architecture;
+-
++-- BBC Micro for Altera DE1 ++-- ++-- Copyright (c) 2011 Mike Stirling ++-- ++-- 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 agreement from the author. ++-- ++-- * License is granted for non-commercial use only. A fee may not be charged ++-- for redistributions as source code or in synthesized/hardware form without ++-- specific prior written agreement from the author. ++-- ++-- 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. ++-- ++-- BBC Micro "VIDPROC" Video ULA ++-- ++-- Synchronous implementation for FPGA ++-- ++-- (C) 2011 Mike Stirling ++-- ++library IEEE; ++use IEEE.STD_LOGIC_1164.ALL; ++use IEEE.NUMERIC_STD.ALL; ++ ++entity vidproc is ++port ( ++ CLOCK : in std_logic; ++ -- Clock enable qualifies display cycles (interleaved with CPU cycles) ++ CLKEN : in std_logic; ++ nRESET : in std_logic; ++ ++ -- Clock enable output to CRTC ++ CLKEN_CRTC : out std_logic; ++ ++ -- Bus interface ++ ENABLE : in std_logic; ++ A0 : in std_logic; ++ -- CPU data bus (for register writes) ++ DI_CPU : in std_logic_vector(7 downto 0); ++ -- Display RAM data bus (for display data fetch) ++ DI_RAM : in std_logic_vector(7 downto 0); ++ ++ -- Control interface ++ nINVERT : in std_logic; ++ DISEN : in std_logic; ++ CURSOR : in std_logic; ++ ++ -- Video in (teletext mode) ++ R_IN : in std_logic; ++ G_IN : in std_logic; ++ B_IN : in std_logic; ++ ++ -- Video out ++ R : out std_logic; ++ G : out std_logic; ++ B : out std_logic ++ ); ++end entity; ++ ++architecture rtl of vidproc is ++-- Write-only registers ++signal r0_cursor0 : std_logic; ++signal r0_cursor1 : std_logic; ++signal r0_cursor2 : std_logic; ++signal r0_crtc_2mhz : std_logic; ++signal r0_pixel_rate : std_logic_vector(1 downto 0); ++signal r0_teletext : std_logic; ++signal r0_flash : std_logic; ++ ++type palette_t is array(0 to 15) of std_logic_vector(3 downto 0); ++signal palette : palette_t; ++ ++-- Pixel shift register ++signal shiftreg : std_logic_vector(7 downto 0); ++-- Delayed display enable ++signal delayed_disen : std_logic; ++ ++-- Internal clock enable generation ++signal clken_pixel : std_logic; ++signal clken_fetch : std_logic; ++signal clken_counter : unsigned(3 downto 0); ++ ++-- Cursor generation - can span up to 32 pixels ++-- Segments 0 and 1 are 8 pixels wide ++-- Segment 2 is 16 pixels wide ++signal cursor_invert : std_logic; ++signal cursor_active : std_logic; ++signal cursor_counter : unsigned(1 downto 0); ++ ++begin ++ -- Synchronous register access, enabled on every clock ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ r0_cursor0 <= '0'; ++ r0_cursor1 <= '0'; ++ r0_cursor2 <= '0'; ++ r0_crtc_2mhz <= '0'; ++ r0_pixel_rate <= "00"; ++ r0_teletext <= '0'; ++ r0_flash <= '0'; ++ ++ for colour in 0 to 15 loop ++ palette(colour) <= (others => '0'); ++ end loop; ++ elsif rising_edge(CLOCK) then ++ if ENABLE = '1' then ++ if A0 = '0' then ++ -- Access control register ++ r0_cursor0 <= DI_CPU(7); ++ r0_cursor1 <= DI_CPU(6); ++ r0_cursor2 <= DI_CPU(5); ++ r0_crtc_2mhz <= DI_CPU(4); ++ r0_pixel_rate <= DI_CPU(3 downto 2); ++ r0_teletext <= DI_CPU(1); ++ r0_flash <= DI_CPU(0); ++ else ++ -- Access palette register ++ palette(to_integer(unsigned(DI_CPU(7 downto 4)))) <= DI_CPU(3 downto 0); ++ end if; ++ end if; ++ end if; ++ end process; ++ ++ -- Clock enable generation. ++ -- Pixel clock can be divided by 1,2,4 or 8 depending on the value ++ -- programmed at r0_pixel_rate ++ -- 00 = /8, 01 = /4, 10 = /2, 11 = /1 ++ clken_pixel <= ++ CLKEN when r0_pixel_rate = "11" else ++ (CLKEN and not clken_counter(0)) when r0_pixel_rate = "10" else ++ (CLKEN and not (clken_counter(0) or clken_counter(1))) when r0_pixel_rate = "01" else ++ (CLKEN and not (clken_counter(0) or clken_counter(1) or clken_counter(2))); ++ -- The CRT controller is always enabled in the 15th cycle, so that the result ++ -- is ready for latching into the shift register in cycle 0. If 2 MHz mode is ++ -- selected then the CRTC is also enabled in the 7th cycle ++ CLKEN_CRTC <= CLKEN and ++ clken_counter(0) and clken_counter(1) and clken_counter(2) and ++ (clken_counter(3) or r0_crtc_2mhz); ++ -- The result is fetched from the CRTC in cycle 0 and also cycle 8 if 2 MHz ++ -- mode is selected. This is used for reloading the shift register as well as ++ -- counting cursor pixels ++ clken_fetch <= CLKEN and not (clken_counter(0) or clken_counter(1) or clken_counter(2) or ++ (clken_counter(3) and not r0_crtc_2mhz)); ++ ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ clken_counter <= (others => '0'); ++ elsif rising_edge(CLOCK) and CLKEN = '1' then ++ -- Increment internal cycle counter during each video clock ++ clken_counter <= clken_counter + 1; ++ end if; ++ end process; ++ ++ -- Fetch control ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ shiftreg <= (others => '0'); ++ elsif rising_edge(CLOCK) and clken_pixel = '1' then ++ if clken_fetch = '1' then ++ -- Fetch next byte from RAM into shift register. This always occurs in ++ -- cycle 0, and also in cycle 8 if the CRTC is clocked at double rate. ++ shiftreg <= DI_RAM; ++ else ++ -- Clock shift register and input '1' at LSB ++ shiftreg <= shiftreg(6 downto 0) & "1"; ++ end if; ++ end if; ++ end process; ++ ++ -- Cursor generation ++ cursor_invert <= cursor_active and ++ ((r0_cursor0 and not (cursor_counter(0) or cursor_counter(1))) or ++ (r0_cursor1 and cursor_counter(0) and not cursor_counter(1)) or ++ (r0_cursor2 and cursor_counter(1))); ++ process(CLOCK,nRESET) ++ begin ++ if nRESET = '0' then ++ cursor_active <= '0'; ++ cursor_counter <= (others => '0'); ++ elsif rising_edge(CLOCK) and clken_fetch = '1' then ++ if CURSOR = '1' or cursor_active = '1' then ++ -- Latch cursor ++ cursor_active <= '1'; ++ ++ -- Reset on counter wrap ++ if cursor_counter = "11" then ++ cursor_active <= '0'; ++ end if; ++ ++ -- Increment counter ++ if cursor_active = '0' then ++ -- Reset ++ cursor_counter <= (others => '0'); ++ else ++ -- Increment ++ cursor_counter <= cursor_counter + 1; ++ end if; ++ end if; ++ end if; ++ end process; ++ ++ -- Pixel generation ++ -- The new shift register contents are loaded during ++ -- cycle 0 (and 8) but will not be read here until the next cycle. ++ -- By running this process on every single video tick instead of at ++ -- the pixel rate we ensure that the resulting delay is minimal and ++ -- constant (running this at the pixel rate would cause ++ -- the display to move slightly depending on which mode was selected). ++ process(CLOCK,nRESET) ++ variable palette_a : std_logic_vector(3 downto 0); ++ variable dot_val : std_logic_vector(3 downto 0); ++ variable red_val : std_logic; ++ variable green_val : std_logic; ++ variable blue_val : std_logic; ++ begin ++ if nRESET = '0' then ++ R <= '0'; ++ G <= '0'; ++ B <= '0'; ++ delayed_disen <= '0'; ++ elsif rising_edge(CLOCK) and CLKEN = '1' then ++ -- Look up dot value in the palette. Bits are as follows: ++ -- bit 3 - FLASH ++ -- bit 2 - Not BLUE ++ -- bit 1 - Not GREEN ++ -- bit 0 - Not RED ++ palette_a := shiftreg(7) & shiftreg(5) & shiftreg(3) & shiftreg(1); ++ dot_val := palette(to_integer(unsigned(palette_a))); ++ ++ -- Apply flash inversion if required ++ red_val := (dot_val(3) and r0_flash) xor not dot_val(0); ++ green_val := (dot_val(3) and r0_flash) xor not dot_val(1); ++ blue_val := (dot_val(3) and r0_flash) xor not dot_val(2); ++ ++ -- To output ++ -- FIXME: INVERT option ++ if r0_teletext = '0' then ++ -- Cursor can extend outside the bounds of the screen, so ++ -- it is not affected by DISEN ++ R <= (red_val and delayed_disen) xor cursor_invert; ++ G <= (green_val and delayed_disen) xor cursor_invert; ++ B <= (blue_val and delayed_disen) xor cursor_invert; ++ else ++ R <= R_IN xor cursor_invert; ++ G <= G_IN xor cursor_invert; ++ B <= B_IN xor cursor_invert; ++ end if; ++ ++ -- Display enable signal delayed by one clock ++ delayed_disen <= DISEN; ++ end if; ++ end process; ++end architecture; ++ diff --git a/de1/fpga-bbc-pq/master/missing-process-sensitivity.patch b/de1/fpga-bbc-pq/master/missing-process-sensitivity.patch new file mode 100644 index 0000000..994998a --- /dev/null +++ b/de1/fpga-bbc-pq/master/missing-process-sensitivity.patch @@ -0,0 +1,234 @@ +diff --git a/bbc_micro_de1.vhd b/bbc_micro_de1.vhd +index 194f93a..25b3b43 100644 +--- a/bbc_micro_de1.vhd ++++ b/bbc_micro_de1.vhd +@@ -1012,7 +1012,7 @@ begin + end if; + end process; + +- cycle_stretch: process(clock,reset_n) ++ cycle_stretch: process(clock,reset_n,mhz2_clken) + begin + if reset_n = '0' then + cpu_cycle_mask <= '0'; +@@ -1170,7 +1170,7 @@ begin + video_data <= SRAM_DQ(7 downto 0); + + -- Synchronous outputs to SRAM +- process(clock,reset_n) ++ process(clock,reset_n,ram_enable,cpu_r_nw) + variable ram_write : std_logic; + begin + ram_write := ram_enable and not cpu_r_nw; +@@ -1290,9 +1290,10 @@ begin + SD_nCS <= '0'; -- CS + user_via_cb2_in <= SD_MISO; -- SDI + user_via_pb_in <= user_via_pb_out; ++ + + -- ROM select latch +- process(clock,reset_n) ++ process(clock,reset_n,romsel_enable) + begin + if reset_n = '0' then + romsel <= (others => '0'); +@@ -1313,7 +1314,7 @@ begin + shift_lock_led_n <= ic32(7); + + +- process(clock,reset_n) ++ process(clock,reset_n,sys_via_pb_out) + variable bit_num : integer; + begin + bit_num := to_integer(unsigned(sys_via_pb_out(2 downto 0))); +diff --git a/debugger.vhd b/debugger.vhd +index a7a9d7d..5431b47 100644 +--- a/debugger.vhd ++++ b/debugger.vhd +@@ -213,7 +213,7 @@ begin + end process; + + -- Set watchpoint address +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,mode) + begin + if nRESET = '0' then + watchpoint <= (others => '1'); +@@ -232,7 +232,7 @@ begin + end process; + + -- Set breakpoint address +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,mode) + begin + if nRESET = '0' then + breakpoint <= (others => '1'); +diff --git a/i2c_loader.vhd b/i2c_loader.vhd +index e0a7115..5152c7b 100644 +--- a/i2c_loader.vhd ++++ b/i2c_loader.vhd +@@ -132,7 +132,7 @@ begin + end process; + + -- The I2C loader process +- process(nRESET,CLK) ++ process(nRESET,CLK,clken) + begin + if nRESET = '0' then + scl_out <= '1'; +diff --git a/mc6845.vhd b/mc6845.vhd +index c102501..c28152d 100644 +--- a/mc6845.vhd ++++ b/mc6845.vhd +@@ -231,7 +231,7 @@ begin + end process; -- registers + + -- Horizontal, vertical and address counters +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,CLKEN) + variable ma_row_start : unsigned(13 downto 0); + variable max_scan_line : unsigned(4 downto 0); + begin +@@ -318,7 +318,7 @@ begin + + -- Signals to mark hsync and half way points for generating + -- vsync in even and odd fields +- process(h_counter) ++ process(h_counter,r02_h_sync_pos) + begin + h_sync_start <= '0'; + h_half_way <= '0'; +@@ -332,7 +332,7 @@ begin + end process; + + -- Video timing and sync counters +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,CLKEN) + begin + if nRESET = '0' then + -- H +@@ -399,7 +399,7 @@ begin + end process; + + -- Address generation +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,CLKEN) + variable slv_line : std_logic_vector(4 downto 0); + begin + if nRESET = '0' then +@@ -423,7 +423,7 @@ begin + end process; + + -- Cursor control +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,CLKEN) + variable cursor_line : std_logic; + begin + -- Internal cursor enable signal delayed by 1 clock to line up +@@ -459,7 +459,7 @@ begin + end process; + + -- Light pen capture +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,CLKEN) + begin + if nRESET = '0' then + lpstb_i <= '0'; +diff --git a/saa5050.vhd b/saa5050.vhd +index 573aaa3..d082339 100644 +--- a/saa5050.vhd ++++ b/saa5050.vhd +@@ -155,7 +155,7 @@ begin + flash <= flash_counter(5) and flash_counter(4); + + -- Sync inputs +- process(DI_CLOCK,nRESET) ++ process(DI_CLOCK,nRESET,DI_CLKEN) + begin + if nRESET = '0' then + di_r <= (others => '0'); +@@ -169,7 +169,7 @@ begin + end process; + + -- Register data into pixel clock domain +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,CLKEN) + begin + if nRESET = '0' then + code <= (others => '0'); +@@ -188,7 +188,7 @@ begin + gfx & code & std_logic_vector(line_addr); + + -- Character row and pixel counters +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,CLKEN) + begin + if nRESET = '0' then + dew_latch <= '0'; +@@ -260,7 +260,7 @@ begin + end process; + + -- Shift register +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,CLKEN) + begin + if nRESET = '0' then + shift_reg <= (others => '0'); +@@ -292,7 +292,7 @@ begin + end process; + + -- Control character handling +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,CLKEN) + begin + if nRESET = '0' then + fg <= (others => '1'); +@@ -363,7 +363,7 @@ begin + end process; + + -- Output +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,CLKEN,shift_reg,flash,conceal,is_flash) + variable pixel : std_logic; + begin + pixel := shift_reg(5) and not ((flash and is_flash) or conceal); +diff --git a/vidproc.vhd b/vidproc.vhd +index 25f3d75..e53bb46 100644 +--- a/vidproc.vhd ++++ b/vidproc.vhd +@@ -165,7 +165,7 @@ begin + clken_fetch <= CLKEN and not (clken_counter(0) or clken_counter(1) or clken_counter(2) or + (clken_counter(3) and not r0_crtc_2mhz)); + +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,CLKEN) + begin + if nRESET = '0' then + clken_counter <= (others => '0'); +@@ -176,7 +176,7 @@ begin + end process; + + -- Fetch control +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,clken_pixel) + begin + if nRESET = '0' then + shiftreg <= (others => '0'); +@@ -197,7 +197,7 @@ begin + ((r0_cursor0 and not (cursor_counter(0) or cursor_counter(1))) or + (r0_cursor1 and cursor_counter(0) and not cursor_counter(1)) or + (r0_cursor2 and cursor_counter(1))); +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,clken_fetch) + begin + if nRESET = '0' then + cursor_active <= '0'; +@@ -231,7 +231,7 @@ begin + -- the pixel rate we ensure that the resulting delay is minimal and + -- constant (running this at the pixel rate would cause + -- the display to move slightly depending on which mode was selected). +- process(CLOCK,nRESET) ++ process(CLOCK,nRESET,CLKEN) + variable palette_a : std_logic_vector(3 downto 0); + variable dot_val : std_logic_vector(3 downto 0); + variable red_val : std_logic; diff --git a/de1/fpga-bbc-pq/master/other-floating-pins.patch b/de1/fpga-bbc-pq/master/other-floating-pins.patch new file mode 100644 index 0000000..2eb6ee7 --- /dev/null +++ b/de1/fpga-bbc-pq/master/other-floating-pins.patch @@ -0,0 +1,57 @@ +diff --git a/bbc_micro_de1.vhd b/bbc_micro_de1.vhd +index fa7b2e8..991fb40 100644 +--- a/bbc_micro_de1.vhd ++++ b/bbc_micro_de1.vhd +@@ -781,6 +781,8 @@ begin + LEDR(2) -- WATCHPOINT + ); + ++ debug_aux <= (others => '0'); ++ + -- 6502 CPU + cpu : T65 port map ( + cpu_mode, +@@ -929,7 +931,10 @@ begin + mhz4_clken, + clock + ); +- ++ ++ user_via_ca2_in <='0'; ++ user_via_pa_in <=(others => '0'); ++ + --LEDG(0) <= not PS2_CLK; + --LEDG(1) <= not PS2_DAT; + +@@ -972,6 +977,12 @@ begin + LEDR(5), -- IS_DONE + LEDR(4) -- IS_ERROR + ); ++ AUD_ADCLRCK <= '1'; ++ ++ UART_TXD <= '0'; ++ DRAM_ADDR <= (others => '1'); ++ LEDR(9 downto 6) <= (others => '0'); ++ sys_via_pb_in(3 downto 0) <= (others => '1'); + + -- Asynchronous reset + -- PLL is reset by external reset switch +@@ -1123,6 +1134,8 @@ begin + end case; + end if; + end process; ++ ++ FL_DQ <= (others =>'Z'); + + -- CPU data bus mux and interrupts + cpu_di <= +@@ -1325,5 +1338,9 @@ begin + + GPIO_0(0) <= not (crtc_hsync xor crtc_vsync); + GPIO_0(1) <= crtc_de; ++ GPIO_0(2) <= ld_vsync; ++ GPIO_0(3) <= ld_hsync; ++ GPIO_0(35 downto 4) <= (others => '0'); ++ GPIO_1 <= (others => '0'); + + end architecture; diff --git a/de1/fpga-bbc-pq/master/other.patch b/de1/fpga-bbc-pq/master/other.patch new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/de1/fpga-bbc-pq/master/other.patch diff --git a/de1/fpga-bbc-pq/master/saa5050-fixes.patch b/de1/fpga-bbc-pq/master/saa5050-fixes.patch new file mode 100644 index 0000000..060f2f6 --- /dev/null +++ b/de1/fpga-bbc-pq/master/saa5050-fixes.patch @@ -0,0 +1,13 @@ +diff --git a/saa5050.vhd b/saa5050.vhd +index f198aa8..573aaa3 100644 +--- a/saa5050.vhd ++++ b/saa5050.vhd +@@ -274,7 +274,7 @@ begin + -- character and separated/hold graphics modes apply. + -- We don't just assume this to be the case if gfx=1 because + -- these modes don't apply to caps even in graphics mode +- if rom_data(7) = '1' then ++ if rom_data(7) = '1' and rom_data(6)='0' then + -- Apply a mask for separated graphics mode + if gfx_sep = '1' then + shift_reg(5) <= '0'; diff --git a/de1/fpga-bbc-pq/master/saa5050-rom.patch b/de1/fpga-bbc-pq/master/saa5050-rom.patch new file mode 100644 index 0000000..b676e51 --- /dev/null +++ b/de1/fpga-bbc-pq/master/saa5050-rom.patch @@ -0,0 +1,472 @@ +diff --git a/roms/saa5050/genrom.c b/roms/saa5050/genrom.c +new file mode 100644 +index 0000000..9d93bb3 +--- /dev/null ++++ b/roms/saa5050/genrom.c +@@ -0,0 +1,180 @@ ++#include <stdint.h> ++#include <stdio.h> ++#include <string.h> ++#include <stdlib.h> ++ ++// Characters on a 5x9 matrix. This is padded up to 16 rows when the ++// ROM is generated ++static uint8_t saa5050_charset[] = { ++ 0,0,0,0,0,0,0,0,0, ++ 4,4,4,4,4,0,4,0,0, ++ 10,10,10,0,0,0,0,0,0, ++ 6,9,8,28,8,8,31,0,0, ++ 14,21,20,14,5,21,14,0,0, ++ 24,25,2,4,8,19,3,0,0, ++ 8,20,20,8,21,18,13,0,0, ++ 4,4,4,0,0,0,0,0,0, ++ ++ 2,4,8,8,8,4,2,0,0, ++ 8,4,2,2,2,4,8,0,0, ++ 4,21,14,4,14,21,4,0,0, ++ 0,4,4,31,4,4,0,0,0, ++ 0,0,0,0,0,4,4,8,0, ++ 0,0,0,14,0,0,0,0,0, ++ 0,0,0,0,0,0,4,0,0, ++ 0,1,2,4,8,16,0,0,0, ++ ++ 4,10,17,17,17,10,4,0,0, ++ 4,12,4,4,4,4,14,0,0, ++ 14,17,1,6,8,16,31,0,0, ++ 31,1,2,6,1,17,14,0,0, ++ 2,6,10,18,31,2,2,0,0, ++ 31,16,30,1,1,17,14,0,0, ++ 6,8,16,30,17,17,14,0,0, ++ 31,1,2,4,8,8,8,0,0, ++ ++ 14,17,17,14,17,17,14,0,0, ++ 14,17,17,15,1,2,12,0,0, ++ 0,0,4,0,0,0,4,0,0, ++ 0,0,4,0,0,4,4,8,0, ++ 2,4,8,16,8,4,2,0,0, ++ 0,0,31,0,31,0,0,0,0, ++ 8,4,2,1,2,4,8,0,0, ++ 14,17,2,4,4,0,4,0,0, ++ ++ 14,17,23,21,23,16,14,0,0, ++ 4,10,17,17,31,17,17,0,0, ++ 30,17,17,30,17,17,30,0,0, ++ 14,17,16,16,16,17,14,0,0, ++ 30,17,17,17,17,17,30,0,0, ++ 31,16,16,30,16,16,31,0,0, ++ 31,16,16,30,16,16,16,0,0, ++ 14,17,16,16,19,17,15,0,0, ++ ++ 17,17,17,31,17,17,17,0,0, ++ 14,4,4,4,4,4,14,0,0, ++ 1,1,1,1,1,17,14,0,0, ++ 17,18,20,24,20,18,17,0,0, ++ 16,16,16,16,16,16,31,0,0, ++ 17,27,21,21,17,17,17,0,0, ++ 17,17,25,21,19,17,17,0,0, ++ 14,17,17,17,17,17,14,0,0, ++ ++ 30,17,17,30,16,16,16,0,0, ++ 14,17,17,17,21,18,13,0,0, ++ 30,17,17,30,20,18,17,0,0, ++ 14,17,16,14,1,17,14,0,0, ++ 31,4,4,4,4,4,4,0,0, ++ 17,17,17,17,17,17,14,0,0, ++ 17,17,17,10,10,4,4,0,0, ++ 17,17,17,21,21,21,10,0,0, ++ ++ 17,17,10,4,10,17,17,0,0, ++ 17,17,10,4,4,4,4,0,0, ++ 31,1,2,4,8,16,31,0,0, ++ 0,4,8,31,8,4,0,0,0, ++ 16,16,16,16,22,1,2,4,7, ++ 0,4,2,31,2,4,0,0,0, ++ 0,4,14,21,4,4,0,0,0, ++ 10,10,31,10,31,10,10,0,0, ++ ++ 0,0,0,31,0,0,0,0,0, ++ 0,0,14,1,15,17,15,0,0, ++ 16,16,30,17,17,17,30,0,0, ++ 0,0,15,16,16,16,15,0,0, ++ 1,1,15,17,17,17,15,0,0, ++ 0,0,14,17,31,16,14,0,0, ++ 2,4,4,14,4,4,4,0,0, ++ 0,0,15,17,17,17,15,1,14, ++ ++ 16,16,30,17,17,17,17,0,0, ++ 4,0,12,4,4,4,14,0,0, ++ 4,0,4,4,4,4,4,4,8, ++ 8,8,9,10,12,10,9,0,0, ++ 12,4,4,4,4,4,14,0,0, ++ 0,0,26,21,21,21,21,0,0, ++ 0,0,30,17,17,17,17,0,0, ++ 0,0,14,17,17,17,14,0,0, ++ ++ 0,0,30,17,17,17,30,16,16, ++ 0,0,15,17,17,17,15,1,1, ++ 0,0,11,12,8,8,8,0,0, ++ 0,0,15,16,14,1,30,0,0, ++ 4,4,14,4,4,4,2,0,0, ++ 0,0,17,17,17,17,15,0,0, ++ 0,0,17,17,10,10,4,0,0, ++ 0,0,17,17,21,21,10,0,0, ++ ++ 0,0,17,10,4,10,17,0,0, ++ 0,0,17,17,17,17,15,1,14, ++ 0,0,31,2,4,8,31,0,0, ++ 8,8,8,8,9,3,5,7,1, ++ 10,10,10,10,10,10,10,0,0, ++ 24,4,24,4,25,3,5,7,1, ++ 0,4,0,31,0,4,0,0,0, ++ 31,31,31,31,31,31,31,0,0, ++}; ++ ++/* Generates 6x10 teletext graphics symbol according to specified code */ ++void gen_gfx(char code,char *base) ++{ ++ char *c; ++ int r; ++ ++ for (r = 0, c = base; r < 10; r++, c++) { ++ /* Set unused bit 7 to 1 to flag these characters as graphics (the ++ * implementation uses this to determine whether hold and separated ++ * modes should be applied */ ++ *c = 128; ++ if (r < 3) { ++ // 1 2 ++ if (code & 1) *c += 56; ++ if (code & 2) *c += 7; ++ } else if (r < 7) { ++ // 4 8 ++ if (code & 4) *c += 56; ++ if (code & 8) *c += 7; ++ } else { ++ // 16 64 ++ if (code & 16) *c += 56; ++ if (code & 64) *c += 7; ++ } ++ } ++} ++ ++int main(void) { ++ char *outbuf; ++ int ch,row; ++ ++ outbuf = malloc(256 * 16); ++ if (outbuf == NULL) { ++ fprintf(stderr,"Out of memory\n"); ++ return 1; ++ } ++ ++ /* Unused locations are blank (all zero) */ ++ memset(outbuf,0,256 * 16); ++ ++ /* Copy character bitmaps to locations 32-127 and 160-255 */ ++ for (ch = 0; ch < 96; ch++) { ++ for (row = 0; row < 9; row++) { ++ outbuf[16 * (32 + ch) + row + 1] = saa5050_charset[9 * ch + row]; ++ outbuf[16 * (160 + ch) + row + 1] = saa5050_charset[9 * ch + row]; ++ } ++ } ++ ++ /* Generate graphics in locations 160-191 and 224-255 */ ++ for (ch = 160; ch < 192; ch++) { ++ gen_gfx(ch,&outbuf[16 * ch]); ++ } ++ for (ch = 224; ch < 256; ch++) { ++ gen_gfx(ch,&outbuf[16 * ch]); ++ } ++ ++ /* Write to stdout */ ++ fwrite(outbuf,256 * 16,1,stdout); ++ ++ free(outbuf); ++ return 0; ++} ++ +diff --git a/roms/saa5050/saa5050.hex b/roms/saa5050/saa5050.hex +new file mode 100644 +index 0000000..f696b00 +--- /dev/null ++++ b/roms/saa5050/saa5050.hex +@@ -0,0 +1,257 @@ ++:1000000000000000000000000000000000000000F0
++:1000100000000000000000000000000000000000E0
++:1000200000000000000000000000000000000000D0
++:1000300000000000000000000000000000000000C0
++:1000400000000000000000000000000000000000B0
++:1000500000000000000000000000000000000000A0
++:100060000000000000000000000000000000000090
++:100070000000000000000000000000000000000080
++:100080000000000000000000000000000000000070
++:100090000000000000000000000000000000000060
++:1000A0000000000000000000000000000000000050
++:1000B0000000000000000000000000000000000040
++:1000C0000000000000000000000000000000000030
++:1000D0000000000000000000000000000000000020
++:1000E0000000000000000000000000000000000010
++:1000F0000000000000000000000000000000000000
++:1001000000000000000000000000000000000000EF
++:1001100000000000000000000000000000000000DF
++:1001200000000000000000000000000000000000CF
++:1001300000000000000000000000000000000000BF
++:1001400000000000000000000000000000000000AF
++:10015000000000000000000000000000000000009F
++:10016000000000000000000000000000000000008F
++:10017000000000000000000000000000000000007F
++:10018000000000000000000000000000000000006F
++:10019000000000000000000000000000000000005F
++:1001A000000000000000000000000000000000004F
++:1001B000000000000000000000000000000000003F
++:1001C000000000000000000000000000000000002F
++:1001D000000000000000000000000000000000001F
++:1001E000000000000000000000000000000000000F
++:1001F00000000000000000000000000000000000FF
++:1002000000000000000000000000000000000000EE
++:1002100000040404040400040000000000000000C6
++:10022000000A0A0A000000000000000000000000B0
++:10023000000609081C08081F00000000000000005C
++:10024000000E15140E05150E000000000000000041
++:100250000018190204081303000000000000000049
++:10026000000814140815120D000000000000000022
++:100270000004040400000000000000000000000072
++:10028000000204080808040200000000000000004A
++:100290000008040202020408000000000000000040
++:1002A0000004150E040E15040000000000000000FC
++:1002B000000004041F04040000000000000000000F
++:1002C000000000000000040408000000000000001E
++:1002D000000000000E000000000000000000000010
++:1002E000000000000000000400000000000000000A
++:1002F00000000102040810000000000000000000DF
++:1003000000040A1111110A0400000000000000009E
++:1003100000040C040404040E0000000000000000AF
++:10032000000E11010608101F000000000000000070
++:10033000001F01020601110E000000000000000075
++:100340000002060A121F0202000000000000000066
++:10035000001F101E0101110E00000000000000002F
++:10036000000608101E11110E000000000000000021
++:10037000001F01020408080800000000000000003F
++:10038000000E11110E11110E0000000000000000FF
++:10039000000E11110F01020C00000000000000000F
++:1003A0000000000400000004000000000000000045
++:1003B0000000000400000404080000000000000029
++:1003C0000002040810080402000000000000000001
++:1003D0000000001F001F00000000000000000000DF
++:1003E00000080402010204080000000000000000F0
++:1003F000000E1102040400040000000000000000D0
++:10040000000E11171517100E00000000000000006C
++:1004100000040A11111F111100000000000000006B
++:10042000001E11111E11111E00000000000000002E
++:10043000000E11101010110E00000000000000004E
++:10044000001E11111111111E00000000000000001B
++:10045000001F10101E10101F000000000000000000
++:10046000001F10101E1010100000000000000000FF
++:10047000000E11101013110F00000000000000000A
++:10048000001111111F1111110000000000000000E7
++:10049000000E04040404040E00000000000000002C
++:1004A000000101010101110E000000000000000028
++:1004B00000111214181412110000000000000000B6
++:1004C000001010101010101F0000000000000000AD
++:1004D00000111B1515111111000000000000000093
++:1004E0000011111915131111000000000000000087
++:1004F000000E11111111110E00000000000000008B
++:10050000001E11111E10101000000000000000005D
++:10051000000E11111115120D000000000000000066
++:10052000001E11111E141211000000000000000036
++:10053000000E11100E01110E00000000000000005E
++:10054000001F040404040404000000000000000074
++:10055000001111111111110E000000000000000027
++:10056000001111110A0A040400000000000000003C
++:10057000001111111515150A0000000000000000FF
++:100580000011110A040A111100000000000000000F
++:100590000011110A0404040400000000000000001F
++:1005A000001F01020408101F0000000000000000EE
++:1005B000000004081F080400000000000000000004
++:1005C00000101010101601020407000000000000C7
++:1005D000000004021F0204000000000000000000F0
++:1005E0000000040E150404000000000000000000DC
++:1005F000000A0A1F0A1F0A0A00000000000000008B
++:10060000000000001F0000000000000000000000CB
++:100610000000000E010F110F00000000000000009C
++:100620000010101E1111111E00000000000000003B
++:100630000000000F1010100F00000000000000006C
++:100640000001010F1111110F000000000000000057
++:100650000000000E111F100E00000000000000003E
++:10066000000204040E040404000000000000000066
++:100670000000000F1111110F010E0000000000001A
++:100680000010101E111111110000000000000000E8
++:100690000004000C0404040E000000000000000030
++:1006A0000004000404040404040800000000000026
++:1006B000000808090A0C0A090000000000000000F8
++:1006C000000C04040404040E0000000000000000FC
++:1006D0000000001A151515150000000000000000AC
++:1006E0000000001E111111110000000000000000A8
++:1006F0000000000E1111110E0000000000000000AB
++:100700000000001E1111111E10100000000000005A
++:100710000000000F1111110F010100000000000086
++:100720000000000B0C08080800000000000000009A
++:100730000000000F100E011E00000000000000006D
++:100740000004040E04040402000000000000000085
++:10075000000000111111110F000000000000000046
++:1007600000000011110A0A0400000000000000004F
++:10077000000000111115150A000000000000000023
++:10078000000000110A040A1100000000000000002F
++:10079000000000111111110F010E000000000000F7
++:1007A0000000001F0204081F0000000000000000FD
++:1007B0000008080808090305070100000000000000
++:1007C000000A0A0A0A0A0A0A0000000000000000E3
++:1007D00000180418041903050701000000000000B8
++:1007E000000004001F0004000000000000000000E2
++:1007F000001F1F1F1F1F1F1F000000000000000020
++:1008000000000000000000000000000000000000E8
++:1008100000000000000000000000000000000000D8
++:1008200000000000000000000000000000000000C8
++:1008300000000000000000000000000000000000B8
++:1008400000000000000000000000000000000000A8
++:100850000000000000000000000000000000000098
++:100860000000000000000000000000000000000088
++:100870000000000000000000000000000000000078
++:100880000000000000000000000000000000000068
++:100890000000000000000000000000000000000058
++:1008A0000000000000000000000000000000000048
++:1008B0000000000000000000000000000000000038
++:1008C0000000000000000000000000000000000028
++:1008D0000000000000000000000000000000000018
++:1008E0000000000000000000000000000000000008
++:1008F00000000000000000000000000000000000F8
++:1009000000000000000000000000000000000000E7
++:1009100000000000000000000000000000000000D7
++:1009200000000000000000000000000000000000C7
++:1009300000000000000000000000000000000000B7
++:1009400000000000000000000000000000000000A7
++:100950000000000000000000000000000000000097
++:100960000000000000000000000000000000000087
++:100970000000000000000000000000000000000077
++:100980000000000000000000000000000000000067
++:100990000000000000000000000000000000000057
++:1009A0000000000000000000000000000000000047
++:1009B0000000000000000000000000000000000037
++:1009C0000000000000000000000000000000000027
++:1009D0000000000000000000000000000000000017
++:1009E0000000000000000000000000000000000007
++:1009F00000000000000000000000000000000000F7
++:100A000080808080808080808080000000000000E6
++:100A1000B8B8B8808080808080800000000000002E
++:100A200087878780808080808080000000000000B1
++:100A3000BFBFBF80808080808080000000000000F9
++:100A4000808080B8B8B8B8808080000000000000C6
++:100A5000B8B8B8B8B8B8B88080800000000000000E
++:100A6000878787B8B8B8B880808000000000000091
++:100A7000BFBFBFB8B8B8B8808080000000000000D9
++:100A8000808080878787878080800000000000004A
++:100A9000B8B8B88787878780808000000000000092
++:100AA0008787878787878780808000000000000015
++:100AB000BFBFBF878787878080800000000000005D
++:100AC000808080BFBFBFBF8080800000000000002A
++:100AD000B8B8B8BFBFBFBF80808000000000000072
++:100AE000878787BFBFBFBF808080000000000000F5
++:100AF000BFBFBFBFBFBFBF8080800000000000003D
++:100B000080808080808080B8B8B80000000000003D
++:100B1000B8B8B880808080B8B8B800000000000085
++:100B200087878780808080B8B8B800000000000008
++:100B3000BFBFBF80808080B8B8B800000000000050
++:100B4000808080B8B8B8B8B8B8B80000000000001D
++:100B5000B8B8B8B8B8B8B8B8B8B800000000000065
++:100B6000878787B8B8B8B8B8B8B8000000000000E8
++:100B7000BFBFBFB8B8B8B8B8B8B800000000000030
++:100B800080808087878787B8B8B8000000000000A1
++:100B9000B8B8B887878787B8B8B8000000000000E9
++:100BA00087878787878787B8B8B80000000000006C
++:100BB000BFBFBF87878787B8B8B8000000000000B4
++:100BC000808080BFBFBFBFB8B8B800000000000081
++:100BD000B8B8B8BFBFBFBFB8B8B8000000000000C9
++:100BE000878787BFBFBFBFB8B8B80000000000004C
++:100BF000BFBFBFBFBFBFBFB8B8B800000000000094
++:100C0000000E11171517100E000000000000000064
++:100C100000040A11111F1111000000000000000063
++:100C2000001E11111E11111E000000000000000026
++:100C3000000E11101010110E000000000000000046
++:100C4000001E11111111111E000000000000000013
++:100C5000001F10101E10101F0000000000000000F8
++:100C6000001F10101E1010100000000000000000F7
++:100C7000000E11101013110F000000000000000002
++:100C8000001111111F1111110000000000000000DF
++:100C9000000E04040404040E000000000000000024
++:100CA000000101010101110E000000000000000020
++:100CB00000111214181412110000000000000000AE
++:100CC000001010101010101F0000000000000000A5
++:100CD00000111B151511111100000000000000008B
++:100CE000001111191513111100000000000000007F
++:100CF000000E11111111110E000000000000000083
++:100D0000001E11111E101010000000000000000055
++:100D1000000E11111115120D00000000000000005E
++:100D2000001E11111E14121100000000000000002E
++:100D3000000E11100E01110E000000000000000056
++:100D4000001F04040404040400000000000000006C
++:100D5000001111111111110E00000000000000001F
++:100D6000001111110A0A0404000000000000000034
++:100D7000001111111515150A0000000000000000F7
++:100D80000011110A040A1111000000000000000007
++:100D90000011110A04040404000000000000000017
++:100DA000001F01020408101F0000000000000000E6
++:100DB000000004081F0804000000000000000000FC
++:100DC00000101010101601020407000000000000BF
++:100DD000000004021F0204000000000000000000E8
++:100DE0000000040E150404000000000000000000D4
++:100DF000000A0A1F0A1F0A0A000000000000000083
++:100E000080808080808080878787000000000000CD
++:100E1000B8B8B88080808087878700000000000015
++:100E20008787878080808087878700000000000098
++:100E3000BFBFBF80808080878787000000000000E0
++:100E4000808080B8B8B8B8878787000000000000AD
++:100E5000B8B8B8B8B8B8B8878787000000000000F5
++:100E6000878787B8B8B8B887878700000000000078
++:100E7000BFBFBFB8B8B8B8878787000000000000C0
++:100E80008080808787878787878700000000000031
++:100E9000B8B8B88787878787878700000000000079
++:100EA00087878787878787878787000000000000FC
++:100EB000BFBFBF8787878787878700000000000044
++:100EC000808080BFBFBFBF87878700000000000011
++:100ED000B8B8B8BFBFBFBF87878700000000000059
++:100EE000878787BFBFBFBF878787000000000000DC
++:100EF000BFBFBFBFBFBFBF87878700000000000024
++:100F000080808080808080BFBFBF00000000000024
++:100F1000B8B8B880808080BFBFBF0000000000006C
++:100F200087878780808080BFBFBF000000000000EF
++:100F3000BFBFBF80808080BFBFBF00000000000037
++:100F4000808080B8B8B8B8BFBFBF00000000000004
++:100F5000B8B8B8B8B8B8B8BFBFBF0000000000004C
++:100F6000878787B8B8B8B8BFBFBF000000000000CF
++:100F7000BFBFBFB8B8B8B8BFBFBF00000000000017
++:100F800080808087878787BFBFBF00000000000088
++:100F9000B8B8B887878787BFBFBF000000000000D0
++:100FA00087878787878787BFBFBF00000000000053
++:100FB000BFBFBF87878787BFBFBF0000000000009B
++:100FC000808080BFBFBFBFBFBFBF00000000000068
++:100FD000B8B8B8BFBFBFBFBFBFBF000000000000B0
++:100FE000878787BFBFBFBFBFBFBF00000000000033
++:100FF000BFBFBFBFBFBFBFBFBFBF0000000000007B
++:00000001FF
+diff --git a/roms/saa5050/saa5050.rom b/roms/saa5050/saa5050.rom +new file mode 100644 +index 0000000000000000000000000000000000000000..71565e3cf7af216396dab97af8326a10b103347b +GIT binary patch +literal 4096 +zcmeHIZI;?F40N(y)}++LfV<H4;j8XHuEamC)|oiyqgPl2@8R)iWJy*+2rqkez;qze +zLX@3pnq<wzW}E(|)MPK$Q+}^m@cA;vbbJ$>PN!54KLs<oHF&2KN7=%9#Gc?-bIjFf +zVr>6~2q79l2%3yWkyRKFeO4H!Qp%+9<Bko`5V;JSG;6(W7&k*ve%wrlHfsKDz7Cd$ +z_*#rV^sHDC$RI5buph>q@F)&z&2L$odRdL_UkD8!HE=vpHgXx={pRvnKWD9n{b;3# +zKa%HHa4z#an|eUPlyCEVoo&AstPQ9BSoRVRVjQREWwzh+f1sK3%HecA9n>G$z_jA> +zr&b%UluJF@_#kb+SsVgLKInh3^Ge>Hhy1h62g67c{Sw~hi|Lv?Uu)H8io=JN8$G;@ +z|1vM8z7SJOdR$=jzi`7J&j@jBqu~Re9)qW;;iKn6rp;So<Y8~_2iJ#^^nOFw<3zo` +z0p1wd=jr&(rI~rcwDC#}zxWT&iR<yT{uuZGK3PsX+o1!W(stTSTZy+kuEsxv-{@}@ +zK7?gL4dxAN{LW(p#G~go2>!9N&nxTCgZ87Br_X-~oB-R8WdI}^d3*oB9014j6`&d7 +zI?ekQxuose`^Pgsyq{^JKgV;t7#<C5_Vv-aiT`Wytvm1~*4uEu-`AavZ?~JnkH^Dd +z07$42y~EHu486k;!i8su-eCfm@X$L90$a>U^bW(>VFH-=V?jesqIbBTt$f!i?pl^4 +zdIDI-(090E=pBZh^@u+f4imtHhu&f6vBj8jzQb^Km;fgJcw4{z|G)A7KZhNLF_HOk +z7=*)^9ftuhOPpEJI}F0%K6~m9JzQv_?{LK{5FUERLys-)iQZul4imt{pT)qiC3=V9 +u=r9}|24H<w?=bWZ!_i^r;ldo{e1{2O!eiku^w^?_zQYxFt@0}={{H|=Yq~)I + +literal 0 +HcmV?d00001 + diff --git a/de1/fpga-bbc-pq/master/scan-rate-converter.patch b/de1/fpga-bbc-pq/master/scan-rate-converter.patch new file mode 100644 index 0000000..8ec3840 --- /dev/null +++ b/de1/fpga-bbc-pq/master/scan-rate-converter.patch @@ -0,0 +1,457 @@ +commit 5fe74b3778ec4f58f628a6f140af1e9fa9a08eac +Author: root <root@lab.panaceas.james.local> +Date: Fri Oct 18 11:08:40 2013 +0100 + + with_line_doubler + +diff --git a/bbc_micro_de1.vhd b/bbc_micro_de1.vhd +index e109c36..d78fe69 100644 +--- a/bbc_micro_de1.vhd ++++ b/bbc_micro_de1.vhd +@@ -279,6 +279,30 @@ port ( + ); + end component; + ++ ++component line_doubler is ++port ( ++ CLOCK : in std_logic; ++ -- Clock enable qualifies display cycles (interleaved with CPU cycles) ++ CLKEN : in std_logic; ++ nRESET : in std_logic; ++ ++ -- Video in (teletext mode) ++ R_IN : in std_logic; ++ G_IN : in std_logic; ++ B_IN : in std_logic; ++ HS_IN : in std_logic; ++ VS_IN : in std_logic; ++ ++ -- Video out ++ R_OUT : out std_logic; ++ G_OUT : out std_logic; ++ B_OUT : out std_logic; ++ HS_OUT : out std_logic; ++ VS_OUT : out std_logic ++ ); ++end component; ++ + -------------------------------- + -- SAA5050 Teletext Generator + -------------------------------- +@@ -610,6 +634,13 @@ signal r_out : std_logic; + signal g_out : std_logic; + signal b_out : std_logic; + ++-- line doubler signals ++signal ld_r_out : std_logic; ++signal ld_g_out : std_logic; ++signal ld_b_out : std_logic; ++signal ld_hsync : std_logic; ++signal ld_vsync : std_logic; ++ + -- SAA5050 signals + signal ttxt_glr : std_logic; + signal ttxt_dew : std_logic; +@@ -801,6 +832,16 @@ begin + r_out, g_out, b_out + ); + ++ ld : line_doubler port map ( ++ clock, ++ vid_clken, ++ reset_n, ++ r_out, g_out, b_out, ++ crtc_hsync,crtc_vsync, ++ ld_r_out,ld_g_out,ld_b_out, ++ ld_hsync, ld_vsync ++ ); ++ + teletext : saa5050 port map ( + CLOCK_24(0), -- This runs at 6 MHz, which we can't derive from the 32 MHz clock + ttxt_clken, +@@ -1182,12 +1223,16 @@ begin + ttxt_crs <= not crtc_ra(0); + ttxt_lose <= crtc_de; + ++ ++ -- line doubler ++ ++ + -- CRTC drives video out (CSYNC on HSYNC output, VSYNC high) +- VGA_HS <= not (crtc_hsync xor crtc_vsync); +- VGA_VS <= '1'; +- VGA_R <= r_out & r_out & r_out & r_out; +- VGA_G <= g_out & g_out & g_out & g_out; +- VGA_B <= b_out & b_out & b_out & b_out; ++ VGA_HS <= ld_hsync; ++ VGA_VS <= ld_vsync; ++ VGA_R <= (others => ld_r_out); ++ VGA_G <= (others => ld_g_out); ++ VGA_B <= (others => ld_b_out); + + -- Connections to System VIA + -- ADC +diff --git a/line_buffer.qip b/line_buffer.qip +new file mode 100644 +index 0000000..5a031a0 +--- /dev/null ++++ b/line_buffer.qip +@@ -0,0 +1,5 @@ ++set_global_assignment -name IP_TOOL_NAME "RAM: 2-PORT" ++set_global_assignment -name IP_TOOL_VERSION "13.0" ++set_global_assignment -name VHDL_FILE [file join $::quartus(qip_path) "line_buffer.vhd"] ++set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "line_buffer.bsf"] ++set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "line_buffer.cmp"] +diff --git a/line_buffer.vhd b/line_buffer.vhd +new file mode 100644 +index 0000000..5ca9fca +--- /dev/null ++++ b/line_buffer.vhd +@@ -0,0 +1,242 @@ ++-- megafunction wizard: %RAM: 2-PORT% ++-- GENERATION: STANDARD ++-- VERSION: WM1.0 ++-- MODULE: altsyncram ++ ++-- ============================================================ ++-- File Name: line_buffer.vhd ++-- Megafunction Name(s): ++-- altsyncram ++-- ++-- Simulation Library Files(s): ++-- altera_mf ++-- ============================================================ ++-- ************************************************************ ++-- THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! ++-- ++-- 13.0.1 Build 232 06/12/2013 SP 1 SJ Web Edition ++-- ************************************************************ ++ ++ ++--Copyright (C) 1991-2013 Altera Corporation ++--Your use of Altera Corporation's design tools, logic functions ++--and other software and tools, and its AMPP partner logic ++--functions, and any output files from any of the foregoing ++--(including device programming or simulation files), and any ++--associated documentation or information are expressly subject ++--to the terms and conditions of the Altera Program License ++--Subscription Agreement, Altera MegaCore Function License ++--Agreement, or other applicable license agreement, including, ++--without limitation, that your use is for the sole purpose of ++--programming logic devices manufactured by Altera and sold by ++--Altera or its authorized distributors. Please refer to the ++--applicable agreement for further details. ++ ++ ++LIBRARY ieee; ++USE ieee.std_logic_1164.all; ++ ++LIBRARY altera_mf; ++USE altera_mf.all; ++ ++ENTITY line_buffer IS ++ PORT ++ ( ++ data : IN STD_LOGIC_VECTOR (3 DOWNTO 0); ++ rdaddress : IN STD_LOGIC_VECTOR (9 DOWNTO 0); ++ rdclock : IN STD_LOGIC ; ++ rdclocken : IN STD_LOGIC := '1'; ++ wraddress : IN STD_LOGIC_VECTOR (9 DOWNTO 0); ++ wrclock : IN STD_LOGIC := '1'; ++ wrclocken : IN STD_LOGIC := '1'; ++ wren : IN STD_LOGIC := '0'; ++ q : OUT STD_LOGIC_VECTOR (3 DOWNTO 0) ++ ); ++END line_buffer; ++ ++ ++ARCHITECTURE SYN OF line_buffer IS ++ ++ SIGNAL sub_wire0 : STD_LOGIC_VECTOR (3 DOWNTO 0); ++ ++ ++ ++ COMPONENT altsyncram ++ GENERIC ( ++ address_reg_b : STRING; ++ clock_enable_input_a : STRING; ++ clock_enable_input_b : STRING; ++ clock_enable_output_a : STRING; ++ clock_enable_output_b : STRING; ++ intended_device_family : STRING; ++ lpm_type : STRING; ++ numwords_a : NATURAL; ++ numwords_b : NATURAL; ++ operation_mode : STRING; ++ outdata_aclr_b : STRING; ++ outdata_reg_b : STRING; ++ power_up_uninitialized : STRING; ++ widthad_a : NATURAL; ++ widthad_b : NATURAL; ++ width_a : NATURAL; ++ width_b : NATURAL; ++ width_byteena_a : NATURAL ++ ); ++ PORT ( ++ clock0 : IN STD_LOGIC ; ++ clocken1 : IN STD_LOGIC ; ++ wren_a : IN STD_LOGIC ; ++ address_b : IN STD_LOGIC_VECTOR (9 DOWNTO 0); ++ clock1 : IN STD_LOGIC ; ++ clocken0 : IN STD_LOGIC ; ++ address_a : IN STD_LOGIC_VECTOR (9 DOWNTO 0); ++ data_a : IN STD_LOGIC_VECTOR (3 DOWNTO 0); ++ q_b : OUT STD_LOGIC_VECTOR (3 DOWNTO 0) ++ ); ++ END COMPONENT; ++ ++BEGIN ++ q <= sub_wire0(3 DOWNTO 0); ++ ++ altsyncram_component : altsyncram ++ GENERIC MAP ( ++ address_reg_b => "CLOCK1", ++ clock_enable_input_a => "NORMAL", ++ clock_enable_input_b => "NORMAL", ++ clock_enable_output_a => "BYPASS", ++ clock_enable_output_b => "NORMAL", ++ intended_device_family => "Cyclone II", ++ lpm_type => "altsyncram", ++ numwords_a => 1024, ++ numwords_b => 1024, ++ operation_mode => "DUAL_PORT", ++ outdata_aclr_b => "NONE", ++ outdata_reg_b => "CLOCK1", ++ power_up_uninitialized => "TRUE", ++ widthad_a => 10, ++ widthad_b => 10, ++ width_a => 4, ++ width_b => 4, ++ width_byteena_a => 1 ++ ) ++ PORT MAP ( ++ clock0 => wrclock, ++ clocken1 => rdclocken, ++ wren_a => wren, ++ address_b => rdaddress, ++ clock1 => rdclock, ++ clocken0 => wrclocken, ++ address_a => wraddress, ++ data_a => data, ++ q_b => sub_wire0 ++ ); ++ ++ ++ ++END SYN; ++ ++-- ============================================================ ++-- CNX file retrieval info ++-- ============================================================ ++-- Retrieval info: PRIVATE: ADDRESSSTALL_A NUMERIC "0" ++-- Retrieval info: PRIVATE: ADDRESSSTALL_B NUMERIC "0" ++-- Retrieval info: PRIVATE: BYTEENA_ACLR_A NUMERIC "0" ++-- Retrieval info: PRIVATE: BYTEENA_ACLR_B NUMERIC "0" ++-- Retrieval info: PRIVATE: BYTE_ENABLE_A NUMERIC "0" ++-- Retrieval info: PRIVATE: BYTE_ENABLE_B NUMERIC "0" ++-- Retrieval info: PRIVATE: BYTE_SIZE NUMERIC "1" ++-- Retrieval info: PRIVATE: BlankMemory NUMERIC "1" ++-- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_A NUMERIC "1" ++-- Retrieval info: PRIVATE: CLOCK_ENABLE_INPUT_B NUMERIC "1" ++-- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_A NUMERIC "1" ++-- Retrieval info: PRIVATE: CLOCK_ENABLE_OUTPUT_B NUMERIC "1" ++-- Retrieval info: PRIVATE: CLRdata NUMERIC "0" ++-- Retrieval info: PRIVATE: CLRq NUMERIC "0" ++-- Retrieval info: PRIVATE: CLRrdaddress NUMERIC "0" ++-- Retrieval info: PRIVATE: CLRrren NUMERIC "0" ++-- Retrieval info: PRIVATE: CLRwraddress NUMERIC "0" ++-- Retrieval info: PRIVATE: CLRwren NUMERIC "0" ++-- Retrieval info: PRIVATE: Clock NUMERIC "1" ++-- Retrieval info: PRIVATE: Clock_A NUMERIC "0" ++-- Retrieval info: PRIVATE: Clock_B NUMERIC "0" ++-- Retrieval info: PRIVATE: IMPLEMENT_IN_LES NUMERIC "0" ++-- Retrieval info: PRIVATE: INDATA_ACLR_B NUMERIC "0" ++-- Retrieval info: PRIVATE: INDATA_REG_B NUMERIC "0" ++-- Retrieval info: PRIVATE: INIT_FILE_LAYOUT STRING "PORT_B" ++-- Retrieval info: PRIVATE: INIT_TO_SIM_X NUMERIC "1" ++-- Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II" ++-- Retrieval info: PRIVATE: JTAG_ENABLED NUMERIC "0" ++-- Retrieval info: PRIVATE: JTAG_ID STRING "NONE" ++-- Retrieval info: PRIVATE: MAXIMUM_DEPTH NUMERIC "0" ++-- Retrieval info: PRIVATE: MEMSIZE NUMERIC "4096" ++-- Retrieval info: PRIVATE: MEM_IN_BITS NUMERIC "0" ++-- Retrieval info: PRIVATE: MIFfilename STRING "" ++-- Retrieval info: PRIVATE: OPERATION_MODE NUMERIC "2" ++-- Retrieval info: PRIVATE: OUTDATA_ACLR_B NUMERIC "0" ++-- Retrieval info: PRIVATE: OUTDATA_REG_B NUMERIC "1" ++-- Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" ++-- Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_MIXED_PORTS NUMERIC "2" ++-- Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_A NUMERIC "3" ++-- Retrieval info: PRIVATE: READ_DURING_WRITE_MODE_PORT_B NUMERIC "3" ++-- Retrieval info: PRIVATE: REGdata NUMERIC "1" ++-- Retrieval info: PRIVATE: REGq NUMERIC "0" ++-- Retrieval info: PRIVATE: REGrdaddress NUMERIC "1" ++-- Retrieval info: PRIVATE: REGrren NUMERIC "1" ++-- Retrieval info: PRIVATE: REGwraddress NUMERIC "1" ++-- Retrieval info: PRIVATE: REGwren NUMERIC "1" ++-- Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" ++-- Retrieval info: PRIVATE: USE_DIFF_CLKEN NUMERIC "0" ++-- Retrieval info: PRIVATE: UseDPRAM NUMERIC "1" ++-- Retrieval info: PRIVATE: VarWidth NUMERIC "0" ++-- Retrieval info: PRIVATE: WIDTH_READ_A NUMERIC "4" ++-- Retrieval info: PRIVATE: WIDTH_READ_B NUMERIC "4" ++-- Retrieval info: PRIVATE: WIDTH_WRITE_A NUMERIC "4" ++-- Retrieval info: PRIVATE: WIDTH_WRITE_B NUMERIC "4" ++-- Retrieval info: PRIVATE: WRADDR_ACLR_B NUMERIC "0" ++-- Retrieval info: PRIVATE: WRADDR_REG_B NUMERIC "0" ++-- Retrieval info: PRIVATE: WRCTRL_ACLR_B NUMERIC "0" ++-- Retrieval info: PRIVATE: enable NUMERIC "1" ++-- Retrieval info: PRIVATE: rden NUMERIC "0" ++-- Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all ++-- Retrieval info: CONSTANT: ADDRESS_REG_B STRING "CLOCK1" ++-- Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_A STRING "NORMAL" ++-- Retrieval info: CONSTANT: CLOCK_ENABLE_INPUT_B STRING "NORMAL" ++-- Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_A STRING "BYPASS" ++-- Retrieval info: CONSTANT: CLOCK_ENABLE_OUTPUT_B STRING "NORMAL" ++-- Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II" ++-- Retrieval info: CONSTANT: LPM_TYPE STRING "altsyncram" ++-- Retrieval info: CONSTANT: NUMWORDS_A NUMERIC "1024" ++-- Retrieval info: CONSTANT: NUMWORDS_B NUMERIC "1024" ++-- Retrieval info: CONSTANT: OPERATION_MODE STRING "DUAL_PORT" ++-- Retrieval info: CONSTANT: OUTDATA_ACLR_B STRING "NONE" ++-- Retrieval info: CONSTANT: OUTDATA_REG_B STRING "CLOCK1" ++-- Retrieval info: CONSTANT: POWER_UP_UNINITIALIZED STRING "TRUE" ++-- Retrieval info: CONSTANT: WIDTHAD_A NUMERIC "10" ++-- Retrieval info: CONSTANT: WIDTHAD_B NUMERIC "10" ++-- Retrieval info: CONSTANT: WIDTH_A NUMERIC "4" ++-- Retrieval info: CONSTANT: WIDTH_B NUMERIC "4" ++-- Retrieval info: CONSTANT: WIDTH_BYTEENA_A NUMERIC "1" ++-- Retrieval info: USED_PORT: data 0 0 4 0 INPUT NODEFVAL "data[3..0]" ++-- Retrieval info: USED_PORT: q 0 0 4 0 OUTPUT NODEFVAL "q[3..0]" ++-- Retrieval info: USED_PORT: rdaddress 0 0 10 0 INPUT NODEFVAL "rdaddress[9..0]" ++-- Retrieval info: USED_PORT: rdclock 0 0 0 0 INPUT NODEFVAL "rdclock" ++-- Retrieval info: USED_PORT: rdclocken 0 0 0 0 INPUT VCC "rdclocken" ++-- Retrieval info: USED_PORT: wraddress 0 0 10 0 INPUT NODEFVAL "wraddress[9..0]" ++-- Retrieval info: USED_PORT: wrclock 0 0 0 0 INPUT VCC "wrclock" ++-- Retrieval info: USED_PORT: wrclocken 0 0 0 0 INPUT VCC "wrclocken" ++-- Retrieval info: USED_PORT: wren 0 0 0 0 INPUT GND "wren" ++-- Retrieval info: CONNECT: @address_a 0 0 10 0 wraddress 0 0 10 0 ++-- Retrieval info: CONNECT: @address_b 0 0 10 0 rdaddress 0 0 10 0 ++-- Retrieval info: CONNECT: @clock0 0 0 0 0 wrclock 0 0 0 0 ++-- Retrieval info: CONNECT: @clock1 0 0 0 0 rdclock 0 0 0 0 ++-- Retrieval info: CONNECT: @clocken0 0 0 0 0 wrclocken 0 0 0 0 ++-- Retrieval info: CONNECT: @clocken1 0 0 0 0 rdclocken 0 0 0 0 ++-- Retrieval info: CONNECT: @data_a 0 0 4 0 data 0 0 4 0 ++-- Retrieval info: CONNECT: @wren_a 0 0 0 0 wren 0 0 0 0 ++-- Retrieval info: CONNECT: q 0 0 4 0 @q_b 0 0 4 0 ++-- Retrieval info: GEN_FILE: TYPE_NORMAL line_buffer.vhd TRUE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL line_buffer.inc FALSE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL line_buffer.cmp TRUE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL line_buffer.bsf TRUE ++-- Retrieval info: GEN_FILE: TYPE_NORMAL line_buffer_inst.vhd FALSE ++-- Retrieval info: LIB_FILE: altera_mf +diff --git a/line_doubler.vhd b/line_doubler.vhd +new file mode 100644 +index 0000000..4c444c1 +--- /dev/null ++++ b/line_doubler.vhd +@@ -0,0 +1,98 @@ ++library IEEE; ++use IEEE.STD_LOGIC_1164.ALL; ++use IEEE.NUMERIC_STD.ALL; ++ ++entity line_doubler is ++port ( ++ CLOCK : in std_logic; ++ -- Clock enable qualifies display cycles (interleaved with CPU cycles) ++ CLKEN : in std_logic; ++ nRESET : in std_logic; ++ ++ -- Video in (teletext mode) ++ R_IN : in std_logic; ++ G_IN : in std_logic; ++ B_IN : in std_logic; ++ HS_IN : in std_logic; ++ VS_IN : in std_logic; ++ ++ -- Video out ++ R_OUT : out std_logic; ++ G_OUT : out std_logic; ++ B_OUT : out std_logic; ++ HS_OUT : out std_logic; ++ VS_OUT : out std_logic ++ ); ++end entity; ++ ++architecture rtl of line_doubler is ++ ++component line_buffer is ++ PORT ++ ( ++ data : IN STD_LOGIC_VECTOR (3 DOWNTO 0); ++ rdaddress : IN STD_LOGIC_VECTOR (9 DOWNTO 0); ++ rdclock : IN STD_LOGIC ; ++ rdclocken : IN STD_LOGIC := '1'; ++ wraddress : IN STD_LOGIC_VECTOR (9 DOWNTO 0); ++ wrclock : IN STD_LOGIC := '1'; ++ wrclocken : IN STD_LOGIC := '1'; ++ wren : IN STD_LOGIC := '0'; ++ q : OUT STD_LOGIC_VECTOR (3 DOWNTO 0) ++ ); ++END component; ++ ++signal out_addr : std_logic_vector(9 downto 0); ++signal in_addr : std_logic_vector(9 downto 0); ++ ++signal in_data : std_logic_vector(3 downto 0); ++signal out_data : std_logic_vector(3 downto 0); ++signal old_hs: std_logic; ++ ++begin ++ ++ in_data(3) <= HS_IN; ++ in_data(2) <= R_IN; ++ in_data(1) <= G_IN; ++ in_data(0) <= B_IN; ++ ++ line_buffer_inst : line_buffer PORT MAP ( ++ wrclock => CLOCK, ++ wrclocken => CLKEN, ++ wren => '1', ++ data => in_data, ++ wraddress => in_addr, ++ ++ rdclock => CLOCK, ++ rdclocken => '1', ++ q => out_data, ++ rdaddress => out_addr ++ ); ++ ++ HS_OUT <= out_data(3); ++ R_OUT <= out_data(2); ++ G_OUT <= out_data(1); ++ B_OUT <= out_data(0); ++ VS_OUT <= VS_IN; ++ ++ process(CLOCK,CLKEN,nRESET,HS_IN,in_addr,out_addr) ++ begin ++ if nRESET = '0' then ++ in_addr <= (others => '0'); ++ out_addr <= (others => '0'); ++ elsif rising_edge(CLOCK) then ++ old_hs <= HS_IN; ++ ++ if old_hs ='0' and HS_IN='1' then ++ in_addr <= (others => '0'); ++ out_addr <= (others => '0'); ++ else ++ out_addr <= std_logic_vector(unsigned(out_addr) +1 ); ++ if CLKEN = '1' then ++ in_addr <= std_logic_vector(unsigned(in_addr) +1 ); ++ end if; ++ end if; ++ end if; ++ end process; ++end architecture; ++ diff --git a/de1/fpga-bbc-pq/master/series b/de1/fpga-bbc-pq/master/series new file mode 100644 index 0000000..8219dc3 --- /dev/null +++ b/de1/fpga-bbc-pq/master/series @@ -0,0 +1,16 @@ +line-endings.patch +gitignore.patch +build-system.patch +saa5050-rom.patch +saa5050-fixes.patch +scan-rate-converter.patch +cpu-core-fixes.patch +sn76489-fixes.patch +audio-16bit-48k.patch +keyboard.patch +keyboard-fixes.patch +dram-floating-pins.patch +other-floating-pins.patch +missing-process-sensitivity.patch +fix-warnings.patch +endstop diff --git a/de1/fpga-bbc-pq/master/sn76489-fixes.patch b/de1/fpga-bbc-pq/master/sn76489-fixes.patch new file mode 100644 index 0000000..6566582 --- /dev/null +++ b/de1/fpga-bbc-pq/master/sn76489-fixes.patch @@ -0,0 +1,634 @@ +diff --git a/sn76489-1.0/sn76489_comp_pack-p.vhd b/sn76489-1.0/sn76489_comp_pack-p.vhd +index 06b12c8..c5fcc90 100644 +--- a/sn76489-1.0/sn76489_comp_pack-p.vhd ++++ b/sn76489-1.0/sn76489_comp_pack-p.vhd +@@ -27,9 +27,11 @@ package sn76489_comp_pack is + clock_i : in std_logic; + clk_en_i : in boolean; + res_n_i : in std_logic; +- we_i : in boolean; ++ we_i : in std_logic; + d_i : in std_logic_vector(0 to 7); +- r2_i : in std_logic; ++ addr_i : in std_logic_vector(0 to 1); ++ rst_a_i : in std_logic_vector(0 to 3); ++ rst_cnt_i: in std_logic_vector(0 to 9); + ff_o : out std_logic; + tone_o : out signed(0 to 7) + ); +@@ -40,31 +42,14 @@ package sn76489_comp_pack is + clock_i : in std_logic; + clk_en_i : in boolean; + res_n_i : in std_logic; +- we_i : in boolean; ++ we_i : in std_logic; + d_i : in std_logic_vector(0 to 7); +- r2_i : in std_logic; ++ addr_i : in std_logic_vector(0 to 1); + tone3_ff_i : in std_logic; + noise_o : out signed(0 to 7) + ); + end component; + +- component sn76489_latch_ctrl +- port ( +- clock_i : in std_logic; +- clk_en_i : in boolean; +- res_n_i : in std_logic; +- ce_n_i : in std_logic; +- we_n_i : in std_logic; +- d_i : in std_logic_vector(0 to 7); +- ready_o : out std_logic; +- tone1_we_o : out boolean; +- tone2_we_o : out boolean; +- tone3_we_o : out boolean; +- noise_we_o : out boolean; +- r2_o : out std_logic +- ); +- end component; +- + component sn76489_clock_div + generic ( + clock_div_16_g : integer := 1 +diff --git a/sn76489-1.0/sn76489_latch_ctrl-c.vhd b/sn76489-1.0/sn76489_latch_ctrl-c.vhd +deleted file mode 100644 +index abc09e0..0000000 +--- a/sn76489-1.0/sn76489_latch_ctrl-c.vhd ++++ /dev/null +@@ -1,14 +0,0 @@ +-------------------------------------------------------------------------------- +--- +--- Synthesizable model of TI's SN76489AN. +--- +--- $Id: sn76489_latch_ctrl-c.vhd,v 1.2 2005/10/10 22:12:38 arnim Exp $ +--- +-------------------------------------------------------------------------------- +- +-configuration sn76489_latch_ctrl_rtl_c0 of sn76489_latch_ctrl is +- +- for rtl +- end for; +- +-end sn76489_latch_ctrl_rtl_c0; +diff --git a/sn76489-1.0/sn76489_latch_ctrl.vhd b/sn76489-1.0/sn76489_latch_ctrl.vhd +deleted file mode 100644 +index 789720c..0000000 +--- a/sn76489-1.0/sn76489_latch_ctrl.vhd ++++ /dev/null +@@ -1,138 +0,0 @@ +-------------------------------------------------------------------------------- +--- +--- Synthesizable model of TI's SN76489AN. +--- +--- $Id: sn76489_latch_ctrl.vhd,v 1.6 2006/02/27 20:30:10 arnim Exp $ +--- +--- Latch Control Unit +--- +-------------------------------------------------------------------------------- +--- +--- Copyright (c) 2005, 2006, Arnim Laeuger (arnim.laeuger@gmx.net) +--- +--- All rights reserved +--- +--- Redistribution and use in source and synthezised forms, with or without +--- modification, are permitted provided that the following conditions are met: +--- +--- Redistributions of source code must retain the above copyright notice, +--- this list of conditions and the following disclaimer. +--- +--- Redistributions in synthesized form must reproduce the above copyright +--- notice, this list of conditions and the following disclaimer in the +--- documentation and/or other materials provided with the distribution. +--- +--- Neither the name of the author nor the names of other contributors may +--- be used to endorse or promote products derived from this software without +--- specific prior written permission. +--- +--- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +--- AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +--- THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +--- PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE +--- LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +--- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +--- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +--- INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +--- CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +--- ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +--- POSSIBILITY OF SUCH DAMAGE. +--- +--- Please report bugs to the author, but before you do so, please +--- make sure that this is not a derivative work and that +--- you have the latest version of this file. +--- +-------------------------------------------------------------------------------- +- +-library ieee; +-use ieee.std_logic_1164.all; +- +-entity sn76489_latch_ctrl is +- +- port ( +- clock_i : in std_logic; +- clk_en_i : in boolean; +- res_n_i : in std_logic; +- ce_n_i : in std_logic; +- we_n_i : in std_logic; +- d_i : in std_logic_vector(0 to 7); +- ready_o : out std_logic; +- tone1_we_o : out boolean; +- tone2_we_o : out boolean; +- tone3_we_o : out boolean; +- noise_we_o : out boolean; +- r2_o : out std_logic +- ); +- +-end sn76489_latch_ctrl; +- +- +-library ieee; +-use ieee.numeric_std.all; +- +-architecture rtl of sn76489_latch_ctrl is +- +- signal reg_q : std_logic_vector(0 to 2); +- signal we_q : boolean; +- signal ready_q : std_logic; +- +-begin +- +- ----------------------------------------------------------------------------- +- -- Process seq +- -- +- -- Purpose: +- -- Implements the sequential elements. +- -- +- seq: process (clock_i, res_n_i) +- begin +- if res_n_i = '0' then +- reg_q <= (others => '0'); +- we_q <= false; +- ready_q <= '0'; +- +- elsif clock_i'event and clock_i = '1' then +- -- READY Flag Output ---------------------------------------------------- +- if ready_q = '0' and we_q then +- if clk_en_i then +- -- assert READY when write access happened +- ready_q <= '1'; +- end if; +- elsif ce_n_i = '1' then +- -- deassert READY when access has finished +- ready_q <= '0'; +- end if; +- +- -- Register Selection --------------------------------------------------- +- if ce_n_i = '0' and we_n_i = '0' then +- if clk_en_i then +- if d_i(0) = '1' then +- reg_q <= d_i(1 to 3); +- end if; +- we_q <= true; +- end if; +- else +- we_q <= false; +- end if; +- +- end if; +- end process seq; +- -- +- ----------------------------------------------------------------------------- +- +- +- ----------------------------------------------------------------------------- +- -- Output mapping +- ----------------------------------------------------------------------------- +- tone1_we_o <= reg_q(0 to 1) = "00" and we_q; +- tone2_we_o <= reg_q(0 to 1) = "01" and we_q; +- tone3_we_o <= reg_q(0 to 1) = "10" and we_q; +- noise_we_o <= reg_q(0 to 1) = "11" and we_q; +- +- r2_o <= reg_q(2); +- +- ready_o <= ready_q +- when ce_n_i = '0' else +- '1'; +- +-end rtl; +diff --git a/sn76489-1.0/sn76489_noise.vhd b/sn76489-1.0/sn76489_noise.vhd +index 8b2ee0e..035adab 100644 +--- a/sn76489-1.0/sn76489_noise.vhd ++++ b/sn76489-1.0/sn76489_noise.vhd +@@ -54,9 +54,9 @@ entity sn76489_noise is + clock_i : in std_logic; + clk_en_i : in boolean; + res_n_i : in std_logic; +- we_i : in boolean; ++ we_i : in std_logic; + d_i : in std_logic_vector(0 to 7); +- r2_i : in std_logic; ++ addr_i : in std_logic_vector(0 to 1); + tone3_ff_i : in std_logic; + noise_o : out signed(0 to 7) + ); +@@ -68,6 +68,9 @@ use work.sn76489_comp_pack.sn76489_attenuator; + + architecture rtl of sn76489_noise is + ++ signal selected : std_logic; ++ signal write_cr : std_logic; ++ + signal nf_q : std_logic_vector(0 to 1); + signal fb_q : std_logic; + signal a_q : std_logic_vector(0 to 3); +@@ -78,12 +81,13 @@ architecture rtl of sn76489_noise is + shift_source_q : std_logic; + signal shift_rise_edge_s : boolean; + +- signal lfsr_q : std_logic_vector(0 to 15); ++ signal lfsr_q : std_logic_vector(0 to 7); + + signal freq_s : signed(0 to 1); + + begin + ++ + ----------------------------------------------------------------------------- + -- Process cpu_regs + -- +@@ -96,22 +100,25 @@ begin + nf_q <= (others => '0'); + fb_q <= '0'; + a_q <= (others => '1'); +- +- elsif clock_i'event and clock_i = '1' then +- if clk_en_i and we_i then +- if r2_i = '0' then +- -- access to control register +- -- both access types can write to the control register! +- nf_q <= d_i(6 to 7); +- fb_q <= d_i(5); +- +- else +- -- access to attenuator register +- -- both access types can write to the attenuator register! +- a_q <= d_i(4 to 7); +- ++ elsif rising_edge(clock_i) and we_i = '1' then ++ if d_i(0) = '1' then ++ if d_i(1 to 2) = addr_i then ++ if d_i(3) = '0' then ++ selected<='1'; ++ nf_q <= d_i(6 to 7); ++ fb_q <= d_i(5); ++ else ++ selected <='0'; ++ a_q <= d_i(4 to 7); ++ end if; ++ else ++ selected <='0'; ++ end if; ++ elsif selected = '1' then ++ selected<='0'; ++ nf_q <= d_i(6 to 7); ++ fb_q <= d_i(5); + end if; +- end if; + end if; + end process cpu_regs; + -- +@@ -130,8 +137,7 @@ begin + freq_cnt_q <= (others => '0'); + freq_ff_q <= '0'; + +- elsif clock_i'event and clock_i = '1' then +- if clk_en_i then ++ elsif rising_edge(clock_i) and clk_en_i then + if freq_cnt_q = 0 then + -- reload frequency counter according to NF setting + case nf_q is +@@ -152,8 +158,6 @@ begin + freq_cnt_q <= freq_cnt_q - 1; + + end if; +- +- end if; + end if; + end process freq_gen; + -- +@@ -191,6 +195,8 @@ begin + shift_rise_edge_s <= shift_source_q = '0' and shift_source_s = '1'; + + ++ write_cr <= '1' when ((we_i='1') and (((d_i(0) = '1') and (d_i(1 to 2) = addr_i) and (d_i(3) = '0')) or (selected='1'))) else '0'; ++ + ----------------------------------------------------------------------------- + -- Process lfsr + -- +@@ -219,15 +225,15 @@ begin + return parity_v; + end; + ++ + begin + if res_n_i = '0' then + -- reset LFSR to "0000000000000001" + lfsr_q <= (others => '0'); + lfsr_q(lfsr_q'right) <= '1'; + +- elsif clock_i'event and clock_i = '1' then +- if clk_en_i then +- if we_i and r2_i = '0' then ++ elsif rising_edge(clock_i) and clk_en_i then ++ if write_cr='1' then + -- write to noise register + -- -> reset LFSR + lfsr_q <= (others => '0'); +@@ -253,7 +259,6 @@ begin + + end if; + +- end if; + end if; + end process lfsr; + -- +diff --git a/sn76489-1.0/sn76489_tone.vhd b/sn76489-1.0/sn76489_tone.vhd +index b71af8b..f1b6885 100644 +--- a/sn76489-1.0/sn76489_tone.vhd ++++ b/sn76489-1.0/sn76489_tone.vhd +@@ -54,9 +54,11 @@ entity sn76489_tone is + clock_i : in std_logic; + clk_en_i : in boolean; + res_n_i : in std_logic; +- we_i : in boolean; ++ we_i : in std_logic; + d_i : in std_logic_vector(0 to 7); +- r2_i : in std_logic; ++ addr_i : in std_logic_vector(0 to 1); ++ rst_a_i : in std_logic_vector(0 to 3); ++ rst_cnt_i: in std_logic_vector(0 to 9); + ff_o : out std_logic; + tone_o : out signed(0 to 7) + ); +@@ -68,6 +70,7 @@ use work.sn76489_comp_pack.sn76489_attenuator; + + architecture rtl of sn76489_tone is + ++ signal selected : std_logic; + signal f_q : std_logic_vector(0 to 9); + signal a_q : std_logic_vector(0 to 3); + signal freq_cnt_q : unsigned(0 to 9); +@@ -75,6 +78,7 @@ architecture rtl of sn76489_tone is + + signal freq_s : signed(0 to 1); + ++ + function all_zero(a : in std_logic_vector) return boolean is + variable result_v : boolean; + begin +@@ -91,6 +95,8 @@ architecture rtl of sn76489_tone is + + begin + ++ ++ + ----------------------------------------------------------------------------- + -- Process cpu_regs + -- +@@ -99,27 +105,28 @@ begin + -- + cpu_regs: process (clock_i, res_n_i) + begin +- if res_n_i = '0' then +- f_q <= (others => '0'); +- a_q <= (others => '1'); +- +- elsif clock_i'event and clock_i = '1' then +- if clk_en_i and we_i then +- if r2_i = '0' then +- -- access to frequency register +- if d_i(0) = '0' then +- f_q(0 to 5) <= d_i(2 to 7); +- else +- f_q(6 to 9) <= d_i(4 to 7); +- end if; +- +- else +- -- access to attenuator register +- -- both access types can write to the attenuator register! +- a_q <= d_i(4 to 7); + ++ if res_n_i = '0' then ++ f_q <= (others => '1'); ++ a_q <= rst_a_i; ++ selected <='0'; ++ elsif rising_edge(clock_i) and we_i = '1' then ++ if d_i(0) = '1' then ++ if d_i(1 to 2) = addr_i then ++ if d_i(3) = '0' then ++ selected<='1'; ++ f_q(6 to 9) <= d_i(4 to 7); ++ else ++ selected <='0'; ++ a_q <= d_i(4 to 7); ++ end if; ++ else ++ selected <='0'; ++ end if; ++ elsif selected = '1' then ++ selected<='0'; ++ f_q(0 to 5) <= d_i(2 to 7); + end if; +- end if; + end if; + end process cpu_regs; + -- +@@ -135,17 +142,19 @@ begin + freq_gen: process (clock_i, res_n_i) + begin + if res_n_i = '0' then +- freq_cnt_q <= (others => '0'); ++ freq_cnt_q <= unsigned(rst_cnt_i); + freq_ff_q <= '0'; + +- elsif clock_i'event and clock_i = '1' then +- if clk_en_i then +- if freq_cnt_q = 0 then ++ elsif rising_edge(clock_i) and clk_en_i then ++ if we_i='1' and selected = '1' then ++ freq_cnt_q <= (others => '0'); ++ freq_ff_q <= '1'; ++ elsif freq_cnt_q = 0 then + -- update counter from frequency register +- freq_cnt_q <= unsigned(f_q); ++ freq_cnt_q <= unsigned(f_q)-to_unsigned(1,10); + + -- and toggle the frequency flip-flop if enabled +- if not all_zero(f_q) then ++ if unsigned(f_q) > to_unsigned(1,10) then + freq_ff_q <= not freq_ff_q; + else + -- if frequency setting is 0, then keep flip-flop at +1 +@@ -157,7 +166,6 @@ begin + freq_cnt_q <= freq_cnt_q - 1; + + end if; +- end if; + end if; + end process freq_gen; + -- +diff --git a/sn76489-1.0/sn76489_top-c.vhd b/sn76489-1.0/sn76489_top-c.vhd +index 8f709b9..55f3dfb 100644 +--- a/sn76489-1.0/sn76489_top-c.vhd ++++ b/sn76489-1.0/sn76489_top-c.vhd +@@ -14,10 +14,6 @@ configuration sn76489_top_struct_c0 of sn76489_top is + use configuration work.sn76489_clock_div_rtl_c0; + end for; + +- for latch_ctrl_b : sn76489_latch_ctrl +- use configuration work.sn76489_latch_ctrl_rtl_c0; +- end for; +- + for all : sn76489_tone + use configuration work.sn76489_tone_rtl_c0; + end for; +diff --git a/sn76489-1.0/sn76489_top.vhd b/sn76489-1.0/sn76489_top.vhd +index deb8170..2f6a01c 100644 +--- a/sn76489-1.0/sn76489_top.vhd ++++ b/sn76489-1.0/sn76489_top.vhd +@@ -86,19 +86,17 @@ architecture struct of sn76489_top is + + signal clk_en_s : boolean; + +- signal tone1_we_s, +- tone2_we_s, +- tone3_we_s, +- noise_we_s : boolean; +- signal r2_s : std_logic; +- + signal tone1_s, + tone2_s, + tone3_s, +- noise_s : signed(0 to 7); ++ noise_s : signed(0 to 15); + + signal tone3_ff_s : std_logic; + ++ signal dl : std_logic_vector(0 to 9); ++ ++ signal we : std_logic; ++ + begin + + ----------------------------------------------------------------------------- +@@ -116,26 +114,6 @@ begin + ); + + +- ----------------------------------------------------------------------------- +- -- Latch Control = CPU Interface +- ----------------------------------------------------------------------------- +- latch_ctrl_b : sn76489_latch_ctrl +- port map ( +- clock_i => clock_i, +- clk_en_i => clk_en_s, +- res_n_i => res_n_i, +- ce_n_i => ce_n_i, +- we_n_i => we_n_i, +- d_i => d_i, +- ready_o => ready_o, +- tone1_we_o => tone1_we_s, +- tone2_we_o => tone2_we_s, +- tone3_we_o => tone3_we_s, +- noise_we_o => noise_we_s, +- r2_o => r2_s +- ); +- +- + ----------------------------------------------------------------------------- + -- Tone Channel 1 + ----------------------------------------------------------------------------- +@@ -144,9 +122,11 @@ begin + clock_i => clock_i, + clk_en_i => clk_en_s, + res_n_i => res_n_i, +- we_i => tone1_we_s, ++ we_i => we, + d_i => d_i, +- r2_i => r2_s, ++ addr_i => "00", ++ rst_a_i => "0000", ++ rst_cnt_i=> "0000000000", + ff_o => open, + tone_o => tone1_s + ); +@@ -159,9 +139,11 @@ begin + clock_i => clock_i, + clk_en_i => clk_en_s, + res_n_i => res_n_i, +- we_i => tone2_we_s, ++ we_i => we, + d_i => d_i, +- r2_i => r2_s, ++ addr_i => "01", ++ rst_a_i => "1000", ++ rst_cnt_i=> "0000110100", + ff_o => open, + tone_o => tone2_s + ); +@@ -174,9 +156,11 @@ begin + clock_i => clock_i, + clk_en_i => clk_en_s, + res_n_i => res_n_i, +- we_i => tone3_we_s, ++ we_i => we, + d_i => d_i, +- r2_i => r2_s, ++ addr_i => "10", ++ rst_a_i => "1000", ++ rst_cnt_i=> "1100110100", + ff_o => tone3_ff_s, + tone_o => tone3_s + ); +@@ -189,14 +173,16 @@ begin + clock_i => clock_i, + clk_en_i => clk_en_s, + res_n_i => res_n_i, +- we_i => noise_we_s, ++ we_i => we, + d_i => d_i, +- r2_i => r2_s, ++ addr_i => "11", + tone3_ff_i => tone3_ff_s, + noise_o => noise_s + ); + + ++ we<= not(ce_n_i or we_n_i) when clk_en_s else '0'; ++ + -- Register output + process(clock_i) + begin +@@ -207,4 +193,23 @@ begin + end if; + end process; + ++ process(clock_i) ++ begin ++ if res_n_i = '0' then ++ dl<=(others => '0'); ++ elsif rising_edge(clock_i) then ++ if ce_n_i = '0' and we_n_i = '0' then ++ if d_i(0)='1' then ++ if d_i(3)='0' then ++ dl(6 to 9) <= d_i(4 to 7); ++ end if; ++ else ++ dl(0 to 5) <= d_i(2 to 7); ++ end if; ++ end if; ++ end if; ++ end process; ++ ++ ++ ready_o <= '1'; + end struct; diff --git a/de1/fpga-flash-nor/Makefile b/de1/fpga-flash-nor/Makefile new file mode 100644 index 0000000..e542f8f --- /dev/null +++ b/de1/fpga-flash-nor/Makefile @@ -0,0 +1,63 @@ +PROJ=de1flash + +SRCS=$(wildcard *.vhd *.v *.qsf *.qpf ) +SOF=${PROJ}.sof + +ROMSRC=../../roms + +default: do_flash + + +do_flash: rom_image.stamp + +rom_image.stamp:rom_image.rom load_sof.stamp + ./quartus_wrap quartus_stp -t de1flash.tcl write rom_image.rom@0x20000 + touch $@ + + +os.rom:${ROMSRC}/os12.rom + cp $< $@ +rom0.rom:${ROMSRC}/empty.rom + cp $< $@ +rom1.rom:${ROMSRC}/empty.rom + cp $< $@ +rom2.rom:${ROMSRC}/supermmc.rom + cp $< $@ +rom3.rom:${ROMSRC}/basic2.rom + cp $< $@ + +rom_image.rom:os.rom rom0.rom rom1.rom rom2.rom rom3.rom + cat rom0.rom rom1.rom rom2.rom rom3.rom ${ROMSRC}/empty.rom ${ROMSRC}/empty.rom ${ROMSRC}/empty.rom os.rom > $@ || /bin/rm -f $@ + +sta.stamp:asm.stamp + ./quartus_wrap quartus_sta ${PROJ} -c ${PROJ} + touch $@ + +asm.stamp:fit.stamp + ./quartus_wrap quartus_asm --read_settings_files=off --write_settings_files=off ${PROJ} -c ${PROJ} + touch $@ + +${SOF}:asm.stamp + +fit.stamp: ans.stamp + ./quartus_wrap quartus_fit --read_settings_files=off --write_settings_files=off ${PROJ} -c ${PROJ} + touch $@ + +ans.stamp: source.stamp + ./quartus_wrap quartus_map --read_settings_files=on --write_settings_files=off ${PROJ} -c ${PROJ} + touch $@ + +source.stamp:${SRCS} + touch source.stamp + +load_sof.stamp: ${SOF} + ./quartus_wrap quartus_pgm -m JTAG -o "p;${SOF}" -c 1 + #touch $@ + +clean: + /bin/rm -rf db incremental_db + /bin/rm -f *.stamp ${SOF} *.rpt *.html *.summary *.pin *.jdi *.qws *.pof *.done *.rom + + + + diff --git a/de1/fpga-flash-nor/crc32_d8.v b/de1/fpga-flash-nor/crc32_d8.v new file mode 100644 index 0000000..4721eb5 --- /dev/null +++ b/de1/fpga-flash-nor/crc32_d8.v @@ -0,0 +1,96 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2011 H. Peter Anvin - All Rights Reserved +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom +// the Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall +// be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// ----------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 1999-2008 Easics NV. +// This source file may be used and distributed without restriction +// provided that this copyright statement is not removed from the file +// and that any derivative work contains the original copyright notice +// and the associated disclaimer. +// +// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS +// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED +// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. +// +// Purpose : synthesizable CRC function +// * polynomial: (0 1 2 4 5 7 8 10 11 12 16 22 23 26 32) +// * data width: 8 +// +// Info : tools@easics.be +// http://www.easics.com +//////////////////////////////////////////////////////////////////////////////// + +module crc_32_d8 ( + input [ 7:0] data, + input [31:0] in, + output [31:0] out + ); + + // Note the bit ordering and the polarity of the inputs and outputs... + wire [0: 7] d = data; + wire [0:31] c = ~in; + reg [0:31] newcrc; + + assign out = ~newcrc; + + always @(d, c) + begin + newcrc[0] = d[6] ^ d[0] ^ c[24] ^ c[30]; + newcrc[1] = d[7] ^ d[6] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[30] ^ c[31]; + newcrc[2] = d[7] ^ d[6] ^ d[2] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[26] ^ c[30] ^ c[31]; + newcrc[3] = d[7] ^ d[3] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[27] ^ c[31]; + newcrc[4] = d[6] ^ d[4] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[28] ^ c[30]; + newcrc[5] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28] ^ c[29] ^ c[30] ^ c[31]; + newcrc[6] = d[7] ^ d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30] ^ c[31]; + newcrc[7] = d[7] ^ d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[24] ^ c[26] ^ c[27] ^ c[29] ^ c[31]; + newcrc[8] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[0] ^ c[24] ^ c[25] ^ c[27] ^ c[28]; + newcrc[9] = d[5] ^ d[4] ^ d[2] ^ d[1] ^ c[1] ^ c[25] ^ c[26] ^ c[28] ^ c[29]; + newcrc[10] = d[5] ^ d[3] ^ d[2] ^ d[0] ^ c[2] ^ c[24] ^ c[26] ^ c[27] ^ c[29]; + newcrc[11] = d[4] ^ d[3] ^ d[1] ^ d[0] ^ c[3] ^ c[24] ^ c[25] ^ c[27] ^ c[28]; + newcrc[12] = d[6] ^ d[5] ^ d[4] ^ d[2] ^ d[1] ^ d[0] ^ c[4] ^ c[24] ^ c[25] ^ c[26] ^ c[28] ^ c[29] ^ c[30]; + newcrc[13] = d[7] ^ d[6] ^ d[5] ^ d[3] ^ d[2] ^ d[1] ^ c[5] ^ c[25] ^ c[26] ^ c[27] ^ c[29] ^ c[30] ^ c[31]; + newcrc[14] = d[7] ^ d[6] ^ d[4] ^ d[3] ^ d[2] ^ c[6] ^ c[26] ^ c[27] ^ c[28] ^ c[30] ^ c[31]; + newcrc[15] = d[7] ^ d[5] ^ d[4] ^ d[3] ^ c[7] ^ c[27] ^ c[28] ^ c[29] ^ c[31]; + newcrc[16] = d[5] ^ d[4] ^ d[0] ^ c[8] ^ c[24] ^ c[28] ^ c[29]; + newcrc[17] = d[6] ^ d[5] ^ d[1] ^ c[9] ^ c[25] ^ c[29] ^ c[30]; + newcrc[18] = d[7] ^ d[6] ^ d[2] ^ c[10] ^ c[26] ^ c[30] ^ c[31]; + newcrc[19] = d[7] ^ d[3] ^ c[11] ^ c[27] ^ c[31]; + newcrc[20] = d[4] ^ c[12] ^ c[28]; + newcrc[21] = d[5] ^ c[13] ^ c[29]; + newcrc[22] = d[0] ^ c[14] ^ c[24]; + newcrc[23] = d[6] ^ d[1] ^ d[0] ^ c[15] ^ c[24] ^ c[25] ^ c[30]; + newcrc[24] = d[7] ^ d[2] ^ d[1] ^ c[16] ^ c[25] ^ c[26] ^ c[31]; + newcrc[25] = d[3] ^ d[2] ^ c[17] ^ c[26] ^ c[27]; + newcrc[26] = d[6] ^ d[4] ^ d[3] ^ d[0] ^ c[18] ^ c[24] ^ c[27] ^ c[28] ^ c[30]; + newcrc[27] = d[7] ^ d[5] ^ d[4] ^ d[1] ^ c[19] ^ c[25] ^ c[28] ^ c[29] ^ c[31]; + newcrc[28] = d[6] ^ d[5] ^ d[2] ^ c[20] ^ c[26] ^ c[29] ^ c[30]; + newcrc[29] = d[7] ^ d[6] ^ d[3] ^ c[21] ^ c[27] ^ c[30] ^ c[31]; + newcrc[30] = d[7] ^ d[4] ^ c[22] ^ c[28] ^ c[31]; + newcrc[31] = d[5] ^ c[23] ^ c[29]; + end // always @ (d, c) + +endmodule // crc_32_d8 diff --git a/de1/fpga-flash-nor/de1flash.fit.smsg b/de1/fpga-flash-nor/de1flash.fit.smsg new file mode 100644 index 0000000..7121cbb --- /dev/null +++ b/de1/fpga-flash-nor/de1flash.fit.smsg @@ -0,0 +1,8 @@ +Extra Info (176273): Performing register packing on registers with non-logic cell location assignments +Extra Info (176274): Completed register packing on registers with non-logic cell location assignments +Extra Info (176236): Started Fast Input/Output/OE register processing +Extra Info (176237): Finished Fast Input/Output/OE register processing +Extra Info (176238): Start inferring scan chains for DSP blocks +Extra Info (176239): Inferring scan chains for DSP blocks is complete +Extra Info (176248): Moving registers into I/O cells, Multiplier Blocks, and RAM blocks to improve timing and density +Extra Info (176249): Finished moving registers into I/O cells, Multiplier Blocks, and RAM blocks diff --git a/de1/fpga-flash-nor/de1flash.map.smsg b/de1/fpga-flash-nor/de1flash.map.smsg new file mode 100644 index 0000000..93f31b5 --- /dev/null +++ b/de1/fpga-flash-nor/de1flash.map.smsg @@ -0,0 +1,2 @@ +Warning (10273): Verilog HDL warning at de1flash.v(463): extended using "x" or "z" +Warning (10273): Verilog HDL warning at de1flash.v(466): extended using "x" or "z" diff --git a/de1/fpga-flash-nor/de1flash.qpf b/de1/fpga-flash-nor/de1flash.qpf new file mode 100644 index 0000000..6c4d9ae --- /dev/null +++ b/de1/fpga-flash-nor/de1flash.qpf @@ -0,0 +1,30 @@ +# -------------------------------------------------------------------------- # +# +# Copyright (C) 1991-2011 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. +# +# -------------------------------------------------------------------------- # +# +# Quartus II +# Version 11.0 Build 157 04/27/2011 SJ Web Edition +# Date created = 15:03:51 May 30, 2011 +# +# -------------------------------------------------------------------------- # + +QUARTUS_VERSION = "11.0" +DATE = "15:03:51 May 30, 2011" + +# Revisions + +PROJECT_REVISION = "de1flash" diff --git a/de1/fpga-flash-nor/de1flash.qsf b/de1/fpga-flash-nor/de1flash.qsf new file mode 100644 index 0000000..eb43225 --- /dev/null +++ b/de1/fpga-flash-nor/de1flash.qsf @@ -0,0 +1,348 @@ +# -------------------------------------------------------------------------- # +# +# Copyright (C) 1991-2011 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. +# +# -------------------------------------------------------------------------- # +# +# Quartus II +# Version 11.0 Build 157 04/27/2011 SJ Web Edition +# Date created = 15:03:51 May 30, 2011 +# +# -------------------------------------------------------------------------- # +# +# Notes: +# +# 1) The default values for assignments are stored in the file: +# de1flash_assignment_defaults.qdf +# If this file doesn't exist, see file: +# assignment_defaults.qdf +# +# 2) Altera recommends that you do not modify this file. This +# file is updated automatically by the Quartus II software +# and any changes you make may be lost or overwritten. +# +# -------------------------------------------------------------------------- # + + +set_global_assignment -name FAMILY "Cyclone II" +set_global_assignment -name DEVICE EP2C20F484C7 +set_global_assignment -name TOP_LEVEL_ENTITY de1flash +set_global_assignment -name ORIGINAL_QUARTUS_VERSION 11.0 +set_global_assignment -name PROJECT_CREATION_TIME_DATE "15:03:51 MAY 30, 2011" +set_global_assignment -name LAST_QUARTUS_VERSION "13.0 SP1" +set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 +set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 +set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1 +set_location_assignment PIN_A13 -to gpio_0[0] +set_location_assignment PIN_B13 -to gpio_0[1] +set_location_assignment PIN_A14 -to gpio_0[2] +set_location_assignment PIN_B14 -to gpio_0[3] +set_location_assignment PIN_A15 -to gpio_0[4] +set_location_assignment PIN_B15 -to gpio_0[5] +set_location_assignment PIN_A16 -to gpio_0[6] +set_location_assignment PIN_B16 -to gpio_0[7] +set_location_assignment PIN_A17 -to gpio_0[8] +set_location_assignment PIN_B17 -to gpio_0[9] +set_location_assignment PIN_A18 -to gpio_0[10] +set_location_assignment PIN_B18 -to gpio_0[11] +set_location_assignment PIN_A19 -to gpio_0[12] +set_location_assignment PIN_B19 -to gpio_0[13] +set_location_assignment PIN_A20 -to gpio_0[14] +set_location_assignment PIN_B20 -to gpio_0[15] +set_location_assignment PIN_C21 -to gpio_0[16] +set_location_assignment PIN_C22 -to gpio_0[17] +set_location_assignment PIN_D21 -to gpio_0[18] +set_location_assignment PIN_D22 -to gpio_0[19] +set_location_assignment PIN_E21 -to gpio_0[20] +set_location_assignment PIN_E22 -to gpio_0[21] +set_location_assignment PIN_F21 -to gpio_0[22] +set_location_assignment PIN_F22 -to gpio_0[23] +set_location_assignment PIN_G21 -to gpio_0[24] +set_location_assignment PIN_G22 -to gpio_0[25] +set_location_assignment PIN_J21 -to gpio_0[26] +set_location_assignment PIN_J22 -to gpio_0[27] +set_location_assignment PIN_K21 -to gpio_0[28] +set_location_assignment PIN_K22 -to gpio_0[29] +set_location_assignment PIN_J19 -to gpio_0[30] +set_location_assignment PIN_J20 -to gpio_0[31] +set_location_assignment PIN_J18 -to gpio_0[32] +set_location_assignment PIN_K20 -to gpio_0[33] +set_location_assignment PIN_L19 -to gpio_0[34] +set_location_assignment PIN_L18 -to gpio_0[35] +set_location_assignment PIN_H12 -to gpio_1[0] +set_location_assignment PIN_H13 -to gpio_1[1] +set_location_assignment PIN_H14 -to gpio_1[2] +set_location_assignment PIN_G15 -to gpio_1[3] +set_location_assignment PIN_E14 -to gpio_1[4] +set_location_assignment PIN_E15 -to gpio_1[5] +set_location_assignment PIN_F15 -to gpio_1[6] +set_location_assignment PIN_G16 -to gpio_1[7] +set_location_assignment PIN_F12 -to gpio_1[8] +set_location_assignment PIN_F13 -to gpio_1[9] +set_location_assignment PIN_C14 -to gpio_1[10] +set_location_assignment PIN_D14 -to gpio_1[11] +set_location_assignment PIN_D15 -to gpio_1[12] +set_location_assignment PIN_D16 -to gpio_1[13] +set_location_assignment PIN_C17 -to gpio_1[14] +set_location_assignment PIN_C18 -to gpio_1[15] +set_location_assignment PIN_C19 -to gpio_1[16] +set_location_assignment PIN_C20 -to gpio_1[17] +set_location_assignment PIN_D19 -to gpio_1[18] +set_location_assignment PIN_D20 -to gpio_1[19] +set_location_assignment PIN_E20 -to gpio_1[20] +set_location_assignment PIN_F20 -to gpio_1[21] +set_location_assignment PIN_E19 -to gpio_1[22] +set_location_assignment PIN_E18 -to gpio_1[23] +set_location_assignment PIN_G20 -to gpio_1[24] +set_location_assignment PIN_G18 -to gpio_1[25] +set_location_assignment PIN_G17 -to gpio_1[26] +set_location_assignment PIN_H17 -to gpio_1[27] +set_location_assignment PIN_J15 -to gpio_1[28] +set_location_assignment PIN_H18 -to gpio_1[29] +set_location_assignment PIN_N22 -to gpio_1[30] +set_location_assignment PIN_N21 -to gpio_1[31] +set_location_assignment PIN_P15 -to gpio_1[32] +set_location_assignment PIN_N15 -to gpio_1[33] +set_location_assignment PIN_P17 -to gpio_1[34] +set_location_assignment PIN_P18 -to gpio_1[35] +set_location_assignment PIN_L22 -to sw[0] +set_location_assignment PIN_L21 -to sw[1] +set_location_assignment PIN_M22 -to sw[2] +set_location_assignment PIN_V12 -to sw[3] +set_location_assignment PIN_W12 -to sw[4] +set_location_assignment PIN_U12 -to sw[5] +set_location_assignment PIN_U11 -to sw[6] +set_location_assignment PIN_M2 -to sw[7] +set_location_assignment PIN_M1 -to sw[8] +set_location_assignment PIN_L2 -to sw[9] +set_location_assignment PIN_J2 -to s7_0[0] +set_location_assignment PIN_J1 -to s7_0[1] +set_location_assignment PIN_H2 -to s7_0[2] +set_location_assignment PIN_H1 -to s7_0[3] +set_location_assignment PIN_F2 -to s7_0[4] +set_location_assignment PIN_F1 -to s7_0[5] +set_location_assignment PIN_E2 -to s7_0[6] +set_location_assignment PIN_E1 -to s7_1[0] +set_location_assignment PIN_H6 -to s7_1[1] +set_location_assignment PIN_H5 -to s7_1[2] +set_location_assignment PIN_H4 -to s7_1[3] +set_location_assignment PIN_G3 -to s7_1[4] +set_location_assignment PIN_D2 -to s7_1[5] +set_location_assignment PIN_D1 -to s7_1[6] +set_location_assignment PIN_G5 -to s7_2[0] +set_location_assignment PIN_G6 -to s7_2[1] +set_location_assignment PIN_C2 -to s7_2[2] +set_location_assignment PIN_C1 -to s7_2[3] +set_location_assignment PIN_E3 -to s7_2[4] +set_location_assignment PIN_E4 -to s7_2[5] +set_location_assignment PIN_D3 -to s7_2[6] +set_location_assignment PIN_F4 -to s7_3[0] +set_location_assignment PIN_D5 -to s7_3[1] +set_location_assignment PIN_D6 -to s7_3[2] +set_location_assignment PIN_J4 -to s7_3[3] +set_location_assignment PIN_L8 -to s7_3[4] +set_location_assignment PIN_F3 -to s7_3[5] +set_location_assignment PIN_D4 -to s7_3[6] +set_location_assignment PIN_R22 -to key_n[0] +set_location_assignment PIN_R21 -to key_n[1] +set_location_assignment PIN_T22 -to key_n[2] +set_location_assignment PIN_T21 -to key_n[3] +set_location_assignment PIN_R20 -to ledr[0] +set_location_assignment PIN_R19 -to ledr[1] +set_location_assignment PIN_U19 -to ledr[2] +set_location_assignment PIN_Y19 -to ledr[3] +set_location_assignment PIN_T18 -to ledr[4] +set_location_assignment PIN_V19 -to ledr[5] +set_location_assignment PIN_Y18 -to ledr[6] +set_location_assignment PIN_U18 -to ledr[7] +set_location_assignment PIN_R18 -to ledr[8] +set_location_assignment PIN_R17 -to ledr[9] +set_location_assignment PIN_U22 -to ledg[0] +set_location_assignment PIN_U21 -to ledg[1] +set_location_assignment PIN_V22 -to ledg[2] +set_location_assignment PIN_V21 -to ledg[3] +set_location_assignment PIN_W22 -to ledg[4] +set_location_assignment PIN_W21 -to ledg[5] +set_location_assignment PIN_Y22 -to ledg[6] +set_location_assignment PIN_Y21 -to ledg[7] +set_location_assignment PIN_D12 -to clock_27[0] +set_location_assignment PIN_E12 -to clock_27[1] +set_location_assignment PIN_B12 -to clock_24[0] +set_location_assignment PIN_A12 -to clock_24[1] +set_location_assignment PIN_L1 -to clock_50 +set_location_assignment PIN_M21 -to ext_clock +set_location_assignment PIN_H15 -to ps2_clk +set_location_assignment PIN_J14 -to ps2_dat +set_location_assignment PIN_F14 -to uart_rxd +set_location_assignment PIN_G12 -to uart_txd +set_location_assignment PIN_E8 -to tdi +set_location_assignment PIN_D8 -to tcs +set_location_assignment PIN_C7 -to tck +set_location_assignment PIN_D7 -to tdo +set_location_assignment PIN_D9 -to vga_r[0] +set_location_assignment PIN_C9 -to vga_r[1] +set_location_assignment PIN_A7 -to vga_r[2] +set_location_assignment PIN_B7 -to vga_r[3] +set_location_assignment PIN_B8 -to vga_g[0] +set_location_assignment PIN_C10 -to vga_g[1] +set_location_assignment PIN_B9 -to vga_g[2] +set_location_assignment PIN_A8 -to vga_g[3] +set_location_assignment PIN_A9 -to vga_b[0] +set_location_assignment PIN_D11 -to vga_b[1] +set_location_assignment PIN_A10 -to vga_b[2] +set_location_assignment PIN_B10 -to vga_b[3] +set_location_assignment PIN_A11 -to vga_hs +set_location_assignment PIN_B11 -to vga_vs +set_location_assignment PIN_A3 -to i2c_scl +set_location_assignment PIN_B3 -to i2c_sda +set_location_assignment PIN_A6 -to aud_adclrck +set_location_assignment PIN_B6 -to aud_adcdat +set_location_assignment PIN_A5 -to aud_daclrck +set_location_assignment PIN_B5 -to aud_dacdat +set_location_assignment PIN_B4 -to aud_xck +set_location_assignment PIN_A4 -to aud_bclk +set_location_assignment PIN_W4 -to dram_a[0] +set_location_assignment PIN_W5 -to dram_a[1] +set_location_assignment PIN_Y3 -to dram_a[2] +set_location_assignment PIN_Y4 -to dram_a[3] +set_location_assignment PIN_R6 -to dram_a[4] +set_location_assignment PIN_R5 -to dram_a[5] +set_location_assignment PIN_P6 -to dram_a[6] +set_location_assignment PIN_P5 -to dram_a[7] +set_location_assignment PIN_P3 -to dram_a[8] +set_location_assignment PIN_N4 -to dram_a[9] +set_location_assignment PIN_W3 -to dram_a[10] +set_location_assignment PIN_N6 -to dram_a[11] +set_location_assignment PIN_U3 -to dram_ba[0] +set_location_assignment PIN_V4 -to dram_ba[1] +set_location_assignment PIN_T3 -to dram_cas_n +set_location_assignment PIN_N3 -to dram_cke +set_location_assignment PIN_U4 -to dram_clk +set_location_assignment PIN_T6 -to dram_cs_n +set_location_assignment PIN_U1 -to dram_dq[0] +set_location_assignment PIN_U2 -to dram_dq[1] +set_location_assignment PIN_V1 -to dram_dq[2] +set_location_assignment PIN_V2 -to dram_dq[3] +set_location_assignment PIN_W1 -to dram_dq[4] +set_location_assignment PIN_W2 -to dram_dq[5] +set_location_assignment PIN_Y1 -to dram_dq[6] +set_location_assignment PIN_Y2 -to dram_dq[7] +set_location_assignment PIN_N1 -to dram_dq[8] +set_location_assignment PIN_N2 -to dram_dq[9] +set_location_assignment PIN_P1 -to dram_dq[10] +set_location_assignment PIN_P2 -to dram_dq[11] +set_location_assignment PIN_R1 -to dram_dq[12] +set_location_assignment PIN_R2 -to dram_dq[13] +set_location_assignment PIN_T1 -to dram_dq[14] +set_location_assignment PIN_T2 -to dram_dq[15] +set_location_assignment PIN_R7 -to dram_dqm[0] +set_location_assignment PIN_T5 -to dram_ras_n +set_location_assignment PIN_M5 -to dram_dqm[1] +set_location_assignment PIN_R8 -to dram_we_n +set_location_assignment PIN_AB20 -to fl_a[0] +set_location_assignment PIN_AA14 -to fl_a[1] +set_location_assignment PIN_Y16 -to fl_a[2] +set_location_assignment PIN_R15 -to fl_a[3] +set_location_assignment PIN_T15 -to fl_a[4] +set_location_assignment PIN_U15 -to fl_a[5] +set_location_assignment PIN_V15 -to fl_a[6] +set_location_assignment PIN_W15 -to fl_a[7] +set_location_assignment PIN_R14 -to fl_a[8] +set_location_assignment PIN_Y13 -to fl_a[9] +set_location_assignment PIN_R12 -to fl_a[10] +set_location_assignment PIN_T12 -to fl_a[11] +set_location_assignment PIN_AB14 -to fl_a[12] +set_location_assignment PIN_AA13 -to fl_a[13] +set_location_assignment PIN_AB13 -to fl_a[14] +set_location_assignment PIN_AA12 -to fl_a[15] +set_location_assignment PIN_AB12 -to fl_a[16] +set_location_assignment PIN_AA20 -to fl_a[17] +set_location_assignment PIN_U14 -to fl_a[18] +set_location_assignment PIN_V14 -to fl_a[19] +set_location_assignment PIN_U13 -to fl_a[20] +set_location_assignment PIN_R13 -to fl_a[21] +set_location_assignment PIN_AB16 -to fl_dq[0] +set_location_assignment PIN_AA16 -to fl_dq[1] +set_location_assignment PIN_AB17 -to fl_dq[2] +set_location_assignment PIN_AA17 -to fl_dq[3] +set_location_assignment PIN_AB18 -to fl_dq[4] +set_location_assignment PIN_AA18 -to fl_dq[5] +set_location_assignment PIN_AB19 -to fl_dq[6] +set_location_assignment PIN_AA19 -to fl_dq[7] +set_location_assignment PIN_AA15 -to fl_oe_n +set_location_assignment PIN_W14 -to fl_rst_n +set_location_assignment PIN_Y14 -to fl_we_n +set_location_assignment PIN_AB15 -to fl_ce_n +set_location_assignment PIN_AA3 -to sram_a[0] +set_location_assignment PIN_AB3 -to sram_a[1] +set_location_assignment PIN_AA4 -to sram_a[2] +set_location_assignment PIN_AB4 -to sram_a[3] +set_location_assignment PIN_AA5 -to sram_a[4] +set_location_assignment PIN_AB10 -to sram_a[5] +set_location_assignment PIN_AA11 -to sram_a[6] +set_location_assignment PIN_AB11 -to sram_a[7] +set_location_assignment PIN_V11 -to sram_a[8] +set_location_assignment PIN_W11 -to sram_a[9] +set_location_assignment PIN_R11 -to sram_a[10] +set_location_assignment PIN_T11 -to sram_a[11] +set_location_assignment PIN_Y10 -to sram_a[12] +set_location_assignment PIN_U10 -to sram_a[13] +set_location_assignment PIN_R10 -to sram_a[14] +set_location_assignment PIN_T7 -to sram_a[15] +set_location_assignment PIN_Y6 -to sram_a[16] +set_location_assignment PIN_Y5 -to sram_a[17] +set_location_assignment PIN_AB5 -to sram_ce_n +set_location_assignment PIN_AA6 -to sram_dq[0] +set_location_assignment PIN_AB6 -to sram_dq[1] +set_location_assignment PIN_AA7 -to sram_dq[2] +set_location_assignment PIN_AB7 -to sram_dq[3] +set_location_assignment PIN_AA8 -to sram_dq[4] +set_location_assignment PIN_AB8 -to sram_dq[5] +set_location_assignment PIN_AA9 -to sram_dq[6] +set_location_assignment PIN_AB9 -to sram_dq[7] +set_location_assignment PIN_Y9 -to sram_dq[8] +set_location_assignment PIN_W9 -to sram_dq[9] +set_location_assignment PIN_V9 -to sram_dq[10] +set_location_assignment PIN_U9 -to sram_dq[11] +set_location_assignment PIN_R9 -to sram_dq[12] +set_location_assignment PIN_W8 -to sram_dq[13] +set_location_assignment PIN_V8 -to sram_dq[14] +set_location_assignment PIN_U8 -to sram_dq[15] +set_location_assignment PIN_Y7 -to sram_be_n[0] +set_location_assignment PIN_T8 -to sram_oe_n +set_location_assignment PIN_W7 -to sram_be_n[1] +set_location_assignment PIN_AA10 -to sram_we_n +set_location_assignment PIN_V20 -to sd_clk +set_location_assignment PIN_Y20 -to sd_cmd +set_location_assignment PIN_W20 -to sd_dat0 +set_location_assignment PIN_U20 -to sd_dat3 + +set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top +set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top +set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top +set_global_assignment -name USE_CONFIGURATION_DEVICE ON +set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED WITH WEAK PULL-UP" +set_global_assignment -name CYCLONEII_RESERVE_NCEO_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name RESERVE_ASDO_AFTER_CONFIGURATION "USE AS REGULAR IO" +set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "NO HEAT SINK WITH STILL AIR" +set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)" +set_global_assignment -name VERILOG_FILE crc32_d8.v +set_global_assignment -name VERILOG_FILE hexled.v +set_global_assignment -name VERILOG_FILE de1flash.v +set_global_assignment -name QIP_FILE vjtag_mega.qip +set_global_assignment -name SDC_FILE de1flash.sdc +set_global_assignment -name QIP_FILE pll.qip +set_global_assignment -name QIP_FILE fl_fifo.qip +set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
\ No newline at end of file diff --git a/de1/fpga-flash-nor/de1flash.tcl b/de1/fpga-flash-nor/de1flash.tcl new file mode 100644 index 0000000..5556e3b --- /dev/null +++ b/de1/fpga-flash-nor/de1flash.tcl @@ -0,0 +1,423 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2011 H. Peter Anvin - All Rights Reserved +## +## Permission is hereby granted, free of charge, to any person +## obtaining a copy of this software and associated documentation +## files (the "Software"), to deal in the Software without +## restriction, including without limitation the rights to use, +## copy, modify, merge, publish, distribute, sublicense, and/or +## sell copies of the Software, and to permit persons to whom +## the Software is furnished to do so, subject to the following +## conditions: +## +## The above copyright notice and this permission notice shall +## be included in all copies or substantial portions of the Software. +## +## THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +## EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +## OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +## NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +## HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +## WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +## FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +## OTHER DEALINGS IN THE SOFTWARE. +## +## ----------------------------------------------------------------------- + +# Virtual JTAG instance index +set fl_instance 0 +# Current IR value +set fl_current_ir -1 +# Known space in the write FIFO +set fl_free_space 0 + +# Device parameters which really should come from reading the CFI data +set fl_device_size 0x400000 +proc fl_sector_size addr { + expr ($addr < 65536) ? 8192 : 65536 +} + +proc select_ir new_ir { + global fl_instance fl_current_ir + if { $new_ir != $fl_current_ir } { + device_virtual_ir_shift -instance_index $fl_instance \ + -ir_value $new_ir -no_captured_ir_value + set fl_current_ir $new_ir + } +} + +# Send a command (given as a 72-bit hex string) +proc fl_send cmd { + global fl_instance fl_free_space + + while { $fl_free_space < 1 } { + # Poll the free space register until nonzero + select_ir 2 + scan [device_virtual_dr_shift -instance_index $fl_instance \ + -length 8 -value_in_hex] "%x" fl_free_space + } + + select_ir 3 + device_virtual_dr_shift -instance_index $fl_instance \ + -dr_value $cmd -length 72 -value_in_hex -no_captured_dr_value + incr fl_free_space -1 +} + +# Receive a reply (returned as a 72-bit hex string) +proc fl_recv {} { + global fl_instance + + set status 0 + + select_ir 1 + while { ($status & 0x80) == 0 } { + set v [device_virtual_dr_shift -instance_index $fl_instance \ + -length 72 -value_in_hex] + scan $v "%2x" status + } + return $v +} + +# Receive bulk data (returned as a binary string) +proc fl_recv_bulk bytes { + global fl_instance + + select_ir 1 + + set qwords [expr ($bytes + 7) >> 3] + set outdata "" + + while { $qwords } { + set d [device_virtual_dr_shift -instance_index $fl_instance \ + -length [expr $qwords * 72] -value_in_hex] + + # The LSW is the first transaction, so we need to process + # the returned string backwards + for { set n [expr $qwords - 1] } { $n >= 0 } { incr n -1 } { + set ix [expr $n * 18] + set di [string range $d $ix [expr $ix + 17]] + scan $di "%2x%2x%2x%2x%2x%2x%2x%2x%2x" st d7 d6 d5 d4 d3 d2 d1 d0 + if { $st & 0x80 } { + set bd [binary format cccccccc $d0 $d1 $d2 $d3 $d4 $d5 $d6 $d7] + set nbytes 8 + if { $bytes < 8 } { + set bd [string range $bd 0 [expr $bytes - 1]] + set nbytes $bytes + } + append outdata $bd + incr qwords -1 + set bytes [expr $bytes - $nbytes] + } else { + # puts "Dropping non-data: $di" + } + } + } + return $outdata +} + +# Reset state machine +proc fl_reset {} { + global fl_instance + + puts -nonewline "Issuing reset... " + + select_ir 5 + device_virtual_dr_shift -instance_index $fl_instance \ + -dr_value 1 -length 1 -no_captured_dr_value + + select_ir 4 + set rdy 0 + while { !$rdy } { + set rdy [device_virtual_dr_shift -instance_index $fl_instance -length 1] + } + + puts "done." +} + +# Sector erase +proc fl_erase addr { + set secsize [fl_sector_size $addr] + set secaddr [expr $addr & ~($secsize - 1)] + + puts -nonewline [format "Erasing sector at 0x%x(0x%x)... " $secaddr $secsize] + + # Blank check the sector before erasing + fl_send [format "50%08X%08X" $secaddr $secsize] + set zc [fl_recv] + set ze [format "\[89ABCDEF\]5%08XFFFFFFFF" [expr $secaddr + $secsize]] + + if { ![string match $ze $zc] } { + # puts "\nNot blank, expected $ze got $zc" + + fl_send 81AAAAAAAA000000AA + fl_send 815555555500000055 + fl_send 81AAAAAAAA00000080 + fl_send 81AAAAAAAA000000AA + fl_send 815555555500000055 + fl_send [format "81%08X00000030" $secaddr] + + set read_cmd [format "D0%08X%08X" $secaddr 8] + + set done 0 + while { !$done } { + fl_send $read_cmd + set v [fl_recv] + set done [string match {[89ABCDEF]DFFFFFFFFFFFFFFFF} $v] + } + puts "done." + } else { + puts "already blank." + } +} + +# Read file +proc fl_read_file { file addr size } { + set f [open $file {WRONLY CREAT TRUNC BINARY}] + + puts -nonewline [format "Reading file %s@0x%x,0x%x... " $file $addr $size] + + # This is an arbitrary tunable, but at least for Quartus 11 is doesn't + # seem to get any better with a larger block size... + set max_block 4096 + + # Read data + set left $size + fl_send [format "D0%08X%08X" $addr $size] + while { $left > 0 } { + set blk [expr ($left < $max_block) ? $left : $max_block] + puts -nonewline $f [fl_recv_bulk $blk] + set left [expr $left - $blk] + } + + close $f + puts "done." +} + +# Write file (without erase) +proc fl_write_file { file addr size } { + set f [open $file {RDONLY BINARY}] + + puts -nonewline [format "Writing file %s@0x%x,0x%x... " $file $addr $size] + + # Write data + set left $size + fl_send [format "D0%08X%08X" $addr 0] + while { $left > 0 } { + set blk [expr ($left < 8) ? $left : 8] + set d [read $f $blk] + append d [string repeat "\xff" [expr 8 - $blk]] + binary scan $d H2H2H2H2H2H2H2H2 d0 d1 d2 d3 d4 d5 d6 d7 + fl_send [format "B%X%s%s%s%s%s%s%s%s" $blk $d7 $d6 $d5 $d4 $d3 $d2 $d1 $d0] + set left [expr $left - $blk] + } + + # Synchronize + puts -nonewline "syncing... " + fl_send 6000000000AEAEAEAE + set v [fl_recv] + if { [string match $v [format "\[89ABCDEF\]6%08XAEAEAEAE" [expr $addr + $size]]] } { + puts "error!" + } else { + puts "done." + } + + close $f +} + +# Checksum (CRC32) a region +proc fl_crc32_file { file addr size } { + fl_send [format "70%08X%08X" $addr $size] + set v [fl_recv] + scan $v "%1x%1x%8x%8x" ctr type end crc + if { $type != 7 || $end != $addr + $size } { + puts "$file: checksumming failure" + } else { + puts [format "%08x %s@0x%x,0x%x" $crc $file $addr $size] + } +} + +# Parse a list of filespecs +proc fl_parse_files { mode files } { + global fl_device_size + + set last_address 0 + set file_list {} + + foreach file $files { + regexp {^(.*?)(\@([0-9a-fA-FxX]+|)(,([0-9a-fA-FxX]+)|)|)$} $file \ + junk0 filename junk1 address junk2 len + if { [string equal $address ""] } { + set address $last_address + } + if { [string equal $len ""] } { + switch $mode { + read + { + set len [expr $fl_device_size - $address] + } + write + { + if { [string equal $filename ""] } { + set len [expr $fl_device_size - $address] + } else { + set len [file size $filename] + } + } + } + } + lappend file_list [list $filename $address $len] + } + + return $file_list +} + +# Produce a list of erase blocks from a filespec list +proc fl_get_eraseblocks flist { + set erase_list {} + + foreach fspec $flist { + set addr [lindex $fspec 1] + set len [lindex $fspec 2] + + set end [expr $addr + $len] + + while { $addr < $end } { + set secsize [fl_sector_size $addr] + set secaddr [expr $addr & ~($secsize - 1)] + + lappend erase_list $secaddr + set addr [expr $secaddr + $secsize] + } + } + + return [lsort -integer -unique $erase_list] +} + +# Erase per filespec +proc fl_erase_files flist { + foreach eb [fl_get_eraseblocks $flist] { + fl_erase $eb + } +} + +# Read per filespec +proc fl_read_files flist { + foreach fspec $flist { + set file [lindex $fspec 0] + set addr [lindex $fspec 1] + set len [lindex $fspec 2] + + if { ![string equal $file ""] } { + fl_read_file $file $addr $len + } + } +} + +# Write per filespec +proc fl_write_files flist { + foreach fspec $flist { + set file [lindex $fspec 0] + set addr [lindex $fspec 1] + set len [lindex $fspec 2] + + if { ![string equal $file ""] } { + fl_write_file $file $addr $len + } + } +} + +# Checksum per filespec +proc fl_crc32_files flist { + foreach fspec $flist { + set file [lindex $fspec 0] + set addr [lindex $fspec 1] + set len [lindex $fspec 2] + + fl_crc32_file $file $addr $len + } +} + +# --------------------------------------------------------------------------- +# Start of main program +# --------------------------------------------------------------------------- + +if {$argc < 1} { + error "Usage: quartus_stp -t de1flash.tcl command [filespec...]" +} + +set fl_cmd [lindex $argv 0] +set fl_fspec [lrange $argv 1 end] + +# List all available programming hardwares, and select the USBBlaster. +# (Note: this example assumes only one USBBlaster connected.) +#puts "Programming Hardwares:" +#foreach hardware_name [get_hardware_names] { +# puts $hardware_name +# if { [string match "USB-Blaster*" $hardware_name] } { +# set usbblaster_name $hardware_name +# } +#} + +set hardwares [get_hardware_names] +set usbblaster_name [lindex $hardwares 0] + +puts "\nUsing programming cable \{$usbblaster_name\}.\n"; + +# List all devices on the chain, and select the first device on the +# chain. +puts "\nDevices on the JTAG chain:" +foreach device_name [get_device_names -hardware_name $usbblaster_name] { + puts $device_name + if { [string match "@1*" $device_name] } { + set test_device $device_name + } +} +puts "\nSelecting device: \{$test_device\}.\n"; + +# Open device +open_device -hardware_name $usbblaster_name -device_name $test_device + +device_lock -timeout 120000 + +fl_reset + +switch $fl_cmd { + write + { + set fspec [fl_parse_files write $fl_fspec] + fl_erase_files $fspec + fl_write_files $fspec + } + writeonly + { + set fspec [fl_parse_files write $fl_fspec] + fl_write_files $fspec + } + erase + { + set fspec [fl_parse_files write $fl_fspec] + fl_erase_files $fspec + } + read + { + set fspec [fl_parse_files read $fl_fspec] + fl_read_files $fspec + } + crc32 + { + set fspec [fl_parse_files write $fl_fspec] + fl_crc32_files $fspec + } + eraseall + { + fl_erase_files [list [list "" 0 $fl_device_size]] + } + default + { + error "Unknown de1flash command" + } +} + +device_unlock +close_device diff --git a/de1/fpga-flash-nor/de1flash.v b/de1/fpga-flash-nor/de1flash.v new file mode 100644 index 0000000..57cd5ec --- /dev/null +++ b/de1/fpga-flash-nor/de1flash.v @@ -0,0 +1,893 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2003-2011 H. Peter Anvin - All Rights Reserved +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom +// the Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall +// be included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +// +// ----------------------------------------------------------------------- + +// +// de1flash.v +// +// Top-level module template for the Terasic DE1/Altera Cyclone II +// Starter Board virtual JTAG programmer module +// +module de1flash ( + input clock_50, // 50 MHz clock + input [1:0] clock_24, // 24 MHz clock (on two pins) + input [1:0] clock_27, // 27 MHz clock (on two pins) + input ext_clock, // External clock input + + inout ps2_clk, // PS/2 keyboard clock + inout ps2_dat, // PS/2 keyboard data + + output [9:0] ledr, // Red LEDs + output [7:0] ledg, // Green LEDs + output [6:0] s7_0, // 7-segment LEDs + output [6:0] s7_1, // 7-segment LEDs + output [6:0] s7_2, // 7-segment LEDs + output [6:0] s7_3, // 7-segment LEDs + + input [3:0] key_n, // Pushbutton switches + input [9:0] sw, // Slide switches + + output fl_rst_n, // Flash ROM RST# + output fl_ce_n, // Flash ROM CE# + output fl_oe_n, // Flash ROM OE# + output fl_we_n, // Flash ROM WE# + output [21:0] fl_a, // Flash ROM address bus + inout [7:0] fl_dq, // Flash ROM data bus + + output [1:0] dram_ba, // SDRAM bank selects + output dram_ras_n, // SDRAM RAS# + output dram_cas_n, // SDRAM CAS# + output dram_cke, // SDRAM clock enable + output dram_clk, // SDRAM clock + output dram_cs_n, // SDRAM CS# + output dram_we_n, // SDRAM WE# + output [1:0] dram_dqm, // SDRAM DQM (per byte) + output [11:0] dram_a, // SDRAM address bus + inout [15:0] dram_dq, // SDRAM data bus + + output sram_ce_n, // SRAM CE# + output sram_oe_n, // SRAM OE# + output sram_we_n, // SRAM WE# + output [1:0] sram_be_n, // SRAM UB#, LB# + output [17:0] sram_a, // SRAM address bus + inout [15:0] sram_dq, // SRAM data bus + + output sd_clk, // SD card clock + inout sd_cmd, // SD card DI/MOSI/CMD + inout sd_dat0, // SD card SO/MISO/DAT0 + inout sd_dat3, // SD card CS#/CD/DAT3 + + output uart_txd, // RS232 port TxD + input uart_rxd, // RS232 port RxD + + output [3:0] vga_r, // VGA red + output [3:0] vga_g, // VGA green + output [3:0] vga_b, // VGA blue + output vga_hs, // VGA horz sync + output vga_vs, // VGA vert sync + + output aud_xck, // Audio master clock + output aud_bclk, // Audio bitclock + output aud_dacdat, // Audio DAC data + output aud_daclrck, // Audio DAC framing + input aud_adcdat, // Audio ADC data + output aud_adclrck, // Audio ADC framing + + inout i2c_scl, // I2C SCK line + inout i2c_sda, // I2C SDA line + + inout [35:0] gpio_0, // GPIO headers + inout [35:0] gpio_1 // GPIO headers + ); + + wire fl_reset_n; + + reg tdo; + wire [3:0] ir_in; + wire tck, tdi, v_sdr, v_cdr, v_uir, v_udr; + + reg [71:0] jtag_wr_data; + reg [71:0] jtag_rd_data; + reg jtag_rd_valid; + reg [ 6:0] jtag_data_ctr; + wire [71:0] jtag_rd_q; + wire [ 7:0] jtag_wr_used; + reg [ 7:0] jtag_wr_free; + wire jtag_rd_empty; + reg jtag_bypass; + reg jtag_reset = 1'b0; + + assign ledg[3:0] = ir_in; + assign ledg[7:4] = { v_udr, v_sdr, v_cdr, v_uir }; + + reg jtag_wr_wrq = 1'b0; // FIFO write strobe + reg jtag_rd_rrq = 1'b0; // FIFO read strobe + + parameter cmd_read_fifo = 4'b0001; + parameter cmd_free_space = 4'b0010; + parameter cmd_write_fifo = 4'b0011; + parameter cmd_check_ready = 4'b0100; + parameter cmd_reset = 4'b0101; + + // Shift registers and TDI input + always @(posedge tck) + begin + jtag_wr_wrq <= 1'b0; + jtag_rd_rrq <= 1'b0; + jtag_reset <= 1'b0; + + if (v_udr) + begin + case (ir_in) + cmd_write_fifo: + jtag_wr_wrq <= 1'b1; + endcase // case(ir_in) + end // if (v_udr) + else if (v_cdr) + begin + case (ir_in) + cmd_read_fifo: + begin + jtag_rd_data <= { ~jtag_rd_empty, jtag_rd_q[70:0] }; + jtag_rd_valid <= ~jtag_rd_empty; + jtag_data_ctr <= 7'd71; + end + cmd_free_space: + begin + jtag_wr_free <= ~jtag_wr_used; + end + endcase // case(ir_in) + end + else if (v_sdr) + begin + jtag_bypass <= tdi; + + case (ir_in) + cmd_read_fifo: + begin + if ( jtag_data_ctr == 7'd2 ) + begin + jtag_rd_rrq <= jtag_rd_valid; + jtag_rd_valid <= 1'b0; + end + + if ( ~|jtag_data_ctr ) + begin + jtag_rd_data <= { ~jtag_rd_empty, jtag_rd_q[70:0] }; + jtag_rd_valid <= ~jtag_rd_empty; + jtag_data_ctr <= 7'd71; + end + else + begin + jtag_rd_data <= { tdi, jtag_rd_data[71:1] }; + jtag_data_ctr <= jtag_data_ctr - 1'b1; + end + end // case: cmd_read_fifo + cmd_free_space: + jtag_wr_free <= { tdi, jtag_wr_free[ 7:1] }; + cmd_write_fifo: + jtag_wr_data <= { tdi, jtag_wr_data[71:1] }; + cmd_reset: + jtag_reset <= tdi; + endcase // case(ir_in) + end // if (v_sdr) + end + + reg [2:0] jtag_ready = 3'b000; + + always @(posedge tck) + jtag_ready <= { jtag_ready[1:0], fl_reset_n }; + + // TDO output MUX + always @ (*) + begin + case (ir_in) + cmd_read_fifo: + tdo <= jtag_rd_data[0]; + cmd_free_space: + tdo <= jtag_wr_free[0]; + cmd_write_fifo: + tdo <= jtag_wr_data[0]; + cmd_reset: + tdo <= 1'b0; // Always read as zero + cmd_check_ready: + tdo <= jtag_ready[2]; + default: + tdo <= jtag_bypass; + endcase // case(ir_in) + end // always @ (*) + + vjtag_mega vjtag_mega_1 + ( + .ir_out ( ), + .tdo ( tdo ), + .ir_in ( ir_in ), + .tck ( tck ), + .tdi ( tdi ), + .virtual_state_cdr ( v_cdr ), + .virtual_state_cir ( ), + .virtual_state_e1dr ( v_udr ), + .virtual_state_e2dr ( ), + .virtual_state_pdr ( ), + .virtual_state_sdr ( v_sdr ), + .virtual_state_udr ( ), + .virtual_state_uir ( v_uir ) + ); + + // ------------------------------------------------------------------ + // Flash clock PLL and reset logic + // ------------------------------------------------------------------ + + wire pll_locked; + wire fl_clk; + + pll pll ( + .areset ( jtag_reset ), + .inclk0 ( clock_50 ), + .c0 ( fl_clk ), // 20 MHz + .locked ( pll_locked ) + ); + + assign fl_reset_n = pll_locked; + + // ------------------------------------------------------------------ + // Write FIFO (JTAG -> programmer) + // ------------------------------------------------------------------ + + wire [71: 0] prog_wr_q; + wire prog_wr_rrq; + wire prog_wr_empty; + + fl_fifo fl_wr_fifo + ( + .aclr ( ~fl_reset_n ), + + .wrclk ( tck ), + .data ( jtag_wr_data ), + .wrreq ( jtag_wr_wrq ), + .wrusedw ( jtag_wr_used ), + .wrfull ( ), + + .rdclk ( fl_clk ), + .q ( prog_wr_q ), + .rdreq ( prog_wr_rrq ), + .rdempty ( prog_wr_empty ) + ); + + // ------------------------------------------------------------------ + // Read FIFO (programmer -> JTAG) + // ------------------------------------------------------------------ + + wire [71:0] prog_rd_data; + wire prog_rd_wrq; + wire prog_rd_full; + + fl_fifo fl_rd_fifo + ( + .aclr ( ~fl_reset_n ), + + .wrclk ( fl_clk ), + .data ( prog_rd_data ), + .wrreq ( prog_rd_wrq ), + .wrusedw ( ), + .wrfull ( prog_rd_full ), + + .rdclk ( tck ), + .q ( jtag_rd_q ), + .rdreq ( jtag_rd_rrq ), + .rdempty ( jtag_rd_empty ) + ); + + // ------------------------------------------------------------------ + // Flash state machine + // This is clocked at 20 MHz (50 ns); one clock cycle for each + // rising or falling edge + // ------------------------------------------------------------------ + + reg [63:0] fl_data; // Data shift register + reg [31:0] fl_bytectr; // Byte counter + reg [ 2:0] fl_rbctr; // Read bytes in shift register + reg [ 3:0] fl_rbcmd; // Command code + reg [31:0] fl_addr; + + reg fl_ce_q; + reg fl_oe_q; + reg fl_we_q; + reg [31:0] fl_a_q; + reg [ 7:0] fl_d_q; + reg fl_d_en; + + assign fl_rst_n = fl_reset_n; + assign fl_ce_n = ~fl_ce_q; + assign fl_oe_n = ~fl_oe_q; + assign fl_we_n = ~fl_we_q; + assign fl_a = fl_a_q[21:0]; + assign fl_dq = fl_d_en ? fl_d_q : 8'hzz; + + reg [4:0] prog_state; + parameter pst_idle = 5'h00; + parameter pst_delay = 5'h01; + parameter pst_status = 5'h02; + parameter pst_read0 = 5'h04; + parameter pst_read1 = 5'h05; + parameter pst_read2 = 5'h06; + parameter pst_readpad = 5'h07; + parameter pst_write0 = 5'h08; + parameter pst_write1 = 5'h09; + parameter pst_zchk0 = 5'h0A; + parameter pst_zchk1 = 5'h0B; + parameter pst_zchk2 = 5'h0C; + parameter pst_crc0 = 5'h0D; + parameter pst_crc1 = 5'h0E; + parameter pst_crc2 = 5'h0F; + parameter pst_program0 = 5'h10; + parameter pst_program1 = 5'h11; + parameter pst_program2 = 5'h12; + parameter pst_program3 = 5'h13; + parameter pst_program4 = 5'h14; + parameter pst_program5 = 5'h15; + parameter pst_program6 = 5'h16; + parameter pst_program7 = 5'h17; + parameter pst_program8 = 5'h18; + parameter pst_program9 = 5'h19; + parameter pst_program10 = 5'h1A; + parameter pst_program11 = 5'h1B; + parameter pst_program12 = 5'h1C; + parameter pst_program13 = 5'h1D; + parameter pst_program14 = 5'h1E; + + reg rd_ack; + + reg [7:0] pgm_data; + reg [7:0] tst_data; + + // Debugging... registering these is "free" since there are + // registers in the I/O buffers, and deconstrains the design + reg [9:0] ledr_q; + assign ledr = ledr_q; + + always @(posedge fl_clk or negedge fl_reset_n) + if (~fl_reset_n) + begin + ledr_q <= ~10'b0; + end + else + begin + ledr_q[0] <= prog_rd_full; + ledr_q[1] <= fl_ce_q; + ledr_q[2] <= fl_oe_q; + ledr_q[3] <= fl_we_q; + ledr_q[4] <= fl_d_en; + ledr_q[9:5] <= prog_state; + end + + reg [6:0] s7_0_q; + reg [6:0] s7_1_q; + reg [6:0] s7_2_q; + reg [6:0] s7_3_q; + + wire [6:0] s7_0_w; + wire [6:0] s7_1_w; + wire [6:0] s7_2_w; + wire [6:0] s7_3_w; + + assign s7_0 = s7_0_q; + assign s7_1 = s7_1_q; + assign s7_2 = s7_2_q; + assign s7_3 = s7_3_q; + + hexled hexled0 ( .value (fl_addr[11: 8]), .s7 (s7_0_w) ); + hexled hexled1 ( .value (fl_addr[15:12]), .s7 (s7_1_w) ); + hexled hexled2 ( .value (fl_addr[19:16]), .s7 (s7_2_w) ); + hexled hexled3 ( .value (fl_addr[23:20]), .s7 (s7_3_w) ); + + reg [2:0] rd_cnt; + + always @(posedge fl_clk or negedge fl_reset_n) + if (~fl_reset_n) + begin + s7_0_q <= ~7'b1000000; + s7_1_q <= ~7'b1000000; + s7_2_q <= ~7'b1000000; + s7_3_q <= ~7'b1000000; + end + else + begin + s7_0_q <= s7_0_w; + s7_1_q <= s7_1_w; + s7_2_q <= s7_2_w; + s7_3_q <= s7_3_w; + end + + assign prog_wr_rrq = ~prog_wr_empty & (prog_state == pst_idle); + assign prog_rd_wrq = rd_ack; + assign prog_rd_data = { 1'b1, rd_cnt, fl_rbcmd, fl_data }; + + always @(negedge fl_reset_n or posedge fl_clk) + if (~fl_reset_n) + rd_cnt <= 3'b000; + else + rd_cnt <= rd_cnt + rd_ack; + + wire bump_addr = + (prog_state == pst_read2) | + (prog_state == pst_zchk2) | + (prog_state == pst_crc2) | + (prog_state == pst_write1) | + ((prog_state == pst_program3) & ~|(tst_data & ~fl_data[7:0])) | + ((prog_state == pst_program14) & (tst_data == pgm_data)); + + wire [31:0] tst_crc; + crc_32_d8 crcgen + ( + .data ( tst_data ), + .in ( fl_data[31:0] ), + .out ( tst_crc ) + ); + reg bump_crc; + + always @(negedge fl_reset_n or posedge fl_clk) + if (~fl_reset_n) + begin + fl_ce_q <= 1'b0; + fl_oe_q <= 1'b0; + fl_we_q <= 1'b0; + fl_addr <= 32'h0; + fl_a_q <= 32'h0; + fl_d_q <= 8'h0; + fl_d_en <= 1'b0; + + fl_data <= 64'bx; + fl_bytectr <= 32'h0; + fl_rbctr <= 3'h0; + fl_rbcmd <= 4'bx; + + prog_state <= pst_idle; + rd_ack <= 1'b0; + bump_crc <= 1'b0; + + pgm_data <= 8'hxx; + tst_data <= 8'hff; + end + else + begin + fl_ce_q <= 1'b0; + fl_oe_q <= 1'b0; + fl_we_q <= 1'b0; + fl_d_en <= 1'b0; + + rd_ack <= 1'b0; + bump_crc <= 1'b0; + + fl_addr <= fl_addr + bump_addr; + + case ( prog_state ) + pst_idle: + begin + fl_rbctr <= 3'h0; + fl_rbcmd <= prog_wr_q[71:68]; + tst_data <= 8'hff; + + if ( ~prog_wr_empty ) + casez ( prog_wr_q[71:68] ) + 4'b0010: // Delay command + begin + fl_bytectr <= prog_wr_q[31:0]; + prog_state <= pst_delay; + end + 4'b0101: // Zero check + begin + fl_addr <= prog_wr_q[63:32]; + fl_bytectr <= prog_wr_q[31:0]; + prog_state <= pst_zchk0; + end + 4'b0110: // Read back address, token + begin + fl_data <= { fl_addr, prog_wr_q[31:0] }; + prog_state <= pst_status; + end + 4'b0111: // CRC32 + begin + fl_addr <= prog_wr_q[63:32]; + fl_bytectr <= prog_wr_q[31:0]; + fl_data[63:32] <= 32'hxxxxxxxx; + fl_data[31: 0] <= 32'h00000000; + prog_state <= pst_crc0; + end + 4'b100z: // Write bytes command + begin + fl_data <= prog_wr_q[63:0]; + if ( prog_wr_q[68] ) + fl_addr <= prog_wr_q[63:32]; + prog_state <= pst_write0; + end + 4'b1011: // Program bytes command + begin + fl_bytectr <= { 28'b0, prog_wr_q[67:64] }; + fl_data <= prog_wr_q[63:0]; + prog_state <= pst_program0; + end + 4'b1101: // Set address register/read command + begin + fl_addr <= prog_wr_q[63:32]; + fl_bytectr <= prog_wr_q[31:0]; + prog_state <= pst_read0; + end + endcase // case( prog_wr_q[71:69] ) + end // case: pst_idle + + pst_delay: + begin + if ( |fl_bytectr ) + fl_bytectr <= fl_bytectr - 1'b1; + else + prog_state <= pst_idle; + end + + pst_status: + begin + if ( ~prog_rd_full ) + begin + rd_ack <= 1'b1; + prog_state <= pst_idle; + end + end + + pst_read0: // Read initial state + begin + fl_a_q <= fl_addr; + if ( |fl_bytectr ) + begin + if ( ~prog_rd_full ) + begin + fl_ce_q <= 1'b1; + fl_oe_q <= 1'b1; + prog_state <= pst_read1; + end + end + else if ( |fl_rbctr ) + begin + if ( ~prog_rd_full ) + prog_state <= pst_readpad; + end + else + prog_state <= pst_idle; + end // case: pst_read0 + + pst_read1: // Read output waveform #1 + begin + fl_ce_q <= 1'b1; + fl_oe_q <= 1'b1; + prog_state <= pst_read2; + end + + pst_read2: + begin + fl_ce_q <= 1'b1; + fl_data <= { fl_dq, fl_data[63:8] }; + rd_ack <= &fl_rbctr; + fl_bytectr <= fl_bytectr - 1'b1; + fl_rbctr <= fl_rbctr + 1'b1; + prog_state <= pst_read0; + end + + pst_readpad: + begin + fl_data <= { 8'hFF, fl_data[63:8] }; + rd_ack <= &fl_rbctr; + fl_rbctr <= fl_rbctr + 1'b1; + prog_state <= pst_read0; + end + + pst_zchk0: // Zero check + begin + fl_a_q <= fl_addr; + if ( (&tst_data) & (|fl_bytectr) ) + begin + fl_ce_q <= 1'b1; + fl_oe_q <= 1'b1; + fl_data[63:32] <= 32'hxxxxxxxx; + fl_data[31: 0] <= 32'hxxxxxxxx; + prog_state <= pst_zchk1; + end + else if ( ~prog_rd_full ) + begin + fl_data[63:32] <= fl_addr; + fl_data[31: 8] <= 24'hffffff; + fl_data[ 7: 0] <= tst_data; + rd_ack <= 1'b1; + prog_state <= pst_idle; + end // else: !if( |fl_bytectr ) + end // case: pst_zchk0 + + pst_zchk1: + begin + fl_ce_q <= 1'b1; + fl_oe_q <= 1'b1; + prog_state <= pst_zchk2; + end + + pst_zchk2: + begin + fl_ce_q <= 1'b1; + tst_data <= fl_dq; + fl_bytectr <= fl_bytectr - 1'b1; + prog_state <= pst_zchk0; + end + + pst_crc0: // CRC32 + begin + fl_a_q <= fl_addr; + if ( bump_crc ) + fl_data[31: 0] <= tst_crc; + if ( |fl_bytectr ) + begin + fl_ce_q <= 1'b1; + fl_oe_q <= 1'b1; + fl_data[63:32] <= 32'hxxxxxxxx; + prog_state <= pst_crc1; + end + else if ( ~prog_rd_full ) + begin + fl_data[63:32] <= fl_addr; + rd_ack <= 1'b1; + prog_state <= pst_idle; + end // else: !if( |fl_bytectr ) + end // case: pst_crc0 + + pst_crc1: + begin + fl_ce_q <= 1'b1; + fl_oe_q <= 1'b1; + prog_state <= pst_crc2; + end + + pst_crc2: + begin + fl_ce_q <= 1'b1; + tst_data <= fl_dq; + fl_bytectr <= fl_bytectr - 1'b1; + bump_crc <= 1'b1; + prog_state <= pst_crc0; + end + + pst_write0: + begin + fl_ce_q <= 1'b1; + fl_we_q <= 1'b1; + fl_d_en <= 1'b1; + fl_d_q <= fl_data[7:0]; + fl_a_q <= fl_data[63:32]; + prog_state <= pst_write1; + end + + pst_write1: + begin + fl_ce_q <= 1'b1; + fl_d_en <= 1'b1; + prog_state <= pst_idle; + end + + // Programming algorithm: read individual bytes to avoid + // hanging the flash chip due to zero bits + pst_program0: + begin + fl_ce_q <= 1'b1; + fl_oe_q <= 1'b1; + fl_a_q <= fl_addr; + prog_state <= pst_program1; + end + + pst_program1: + begin + fl_ce_q <= 1'b1; + fl_oe_q <= 1'b1; + prog_state <= pst_program2; + end + + pst_program2: + begin + fl_ce_q <= 1'b1; + tst_data <= fl_dq; + prog_state <= pst_program3; + fl_bytectr <= fl_bytectr - 1'b1; + end + + pst_program3: + begin + fl_ce_q <= 1'b1; + pgm_data <= tst_data & fl_data[7:0]; + fl_data <= { 8'hFF, fl_data[63:8] }; + + if ( |(tst_data & ~fl_data[7:0]) ) + begin + fl_we_q <= 1'b1; + fl_d_en <= 1'b1; + fl_d_q <= 8'hAA; + fl_a_q <= 32'hAAAA_AAAA; + prog_state <= pst_program4; + end + else + begin + if ( |fl_bytectr ) + prog_state <= pst_program0; + else + prog_state <= pst_idle; + end + end // case: pst_program3 + + pst_program4: + begin + fl_ce_q <= 1'b1; + fl_d_en <= 1'b1; + prog_state <= pst_program5; + end + + pst_program5: + begin + fl_ce_q <= 1'b1; + fl_we_q <= 1'b1; + fl_d_en <= 1'b1; + fl_d_q <= 8'h55; + fl_a_q <= 32'h5555_5555; + prog_state <= pst_program6; + end + + pst_program6: + begin + fl_ce_q <= 1'b1; + fl_d_en <= 1'b1; + prog_state <= pst_program7; + end + + pst_program7: + begin + fl_ce_q <= 1'b1; + fl_we_q <= 1'b1; + fl_d_en <= 1'b1; + fl_d_q <= 8'hA0; + fl_a_q <= 32'hAAAA_AAAA; + prog_state <= pst_program8; + end + + pst_program8: + begin + fl_ce_q <= 1'b1; + fl_d_en <= 1'b1; + prog_state <= pst_program9; + end + + pst_program9: + begin + fl_ce_q <= 1'b1; + fl_we_q <= 1'b1; + fl_d_en <= 1'b1; + fl_d_q <= pgm_data; + fl_a_q <= fl_addr; + prog_state <= pst_program10; + end + + pst_program10: + begin + fl_ce_q <= 1'b1; + fl_d_en <= 1'b1; + prog_state <= pst_program11; + end + + pst_program11: + begin + fl_ce_q <= 1'b1; + fl_oe_q <= 1'b1; + prog_state <= pst_program12; + end + + pst_program12: + begin + fl_ce_q <= 1'b1; + fl_oe_q <= 1'b1; + prog_state <= pst_program13; + end + + pst_program13: + begin + fl_ce_q <= 1'b1; + tst_data <= fl_dq; + prog_state <= pst_program14; + end + + pst_program14: + begin + fl_ce_q <= 1'b1; + if ( tst_data != pgm_data ) + prog_state <= pst_program11; + else if ( |fl_bytectr ) + prog_state <= pst_program0; + else + prog_state <= pst_idle; + end + endcase // case( prog_state ) + end + + // ------------------------------------------------------------------ + // Unused hardware ports + // ------------------------------------------------------------------ + + // PS/2 port + assign ps2_clk = 1'bz; + assign ps2_dat = 1'bz; + + // SDRAM + assign dram_ba = 2'b11; + assign dram_ras_n = 1'b1; + assign dram_cas_n = 1'b1; + assign dram_cke = 1'b1; + assign dram_clk = 1'b1; + assign dram_cs_n = 1'b1; + assign dram_we_n = 1'b1; + assign dram_dqm = 2'b11; + assign dram_a = ~12'b0; + assign dram_dq = 16'hzzzz; + + // SRAM + assign sram_ce_n = 1'b1; + assign sram_oe_n = 1'b1; + assign sram_we_n = 1'b1; + assign sram_be_n = 2'b11; + assign sram_a = ~18'b0; + assign sram_dq = 16'hzzzz; + + // SD card + assign sd_clk = 1'b1; + assign sd_cmd = 1'bz; + assign sd_dat0 = 1'bz; + assign sd_dat3 = 1'bz; + + // RS232 + assign uart_txd = 1'b1; + + // Video + assign vga_r = 4'b0; + assign vga_g = 4'b0; + assign vga_b = 4'b0; + assign vga_hs = 1'b0; + assign vga_vs = 1'b0; + + // Audio I2S + assign aud_xck = 1'b1; + assign aud_bclk = 1'b1; + assign aud_dacdat = 1'b1; + assign aud_daclrck = 1'b1; + assign aud_adclrck = 1'b1; + + // Audio I2C + assign i2c_scl = 1'bz; + assign i2c_sda = 1'bz; + + // GPIO + assign gpio_0 = 36'hz_zzzz_zzzz; + assign gpio_1 = 36'hz_zzzz_zzzz; + +endmodule // de1flash diff --git a/de1/fpga-flash-nor/fl_fifo.qip b/de1/fpga-flash-nor/fl_fifo.qip new file mode 100644 index 0000000..7981a70 --- /dev/null +++ b/de1/fpga-flash-nor/fl_fifo.qip @@ -0,0 +1,4 @@ +set_global_assignment -name IP_TOOL_NAME "FIFO" +set_global_assignment -name IP_TOOL_VERSION "11.0" +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "fl_fifo.v"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "fl_fifo_bb.v"] diff --git a/de1/fpga-flash-nor/fl_fifo.v b/de1/fpga-flash-nor/fl_fifo.v new file mode 100644 index 0000000..c16e687 --- /dev/null +++ b/de1/fpga-flash-nor/fl_fifo.v @@ -0,0 +1,185 @@ +// megafunction wizard: %FIFO% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: dcfifo + +// ============================================================ +// File Name: fl_fifo.v +// Megafunction Name(s): +// dcfifo +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 11.0 Build 157 04/27/2011 SJ Web Edition +// ************************************************************ + + +//Copyright (C) 1991-2011 Altera Corporation +//Your use of Altera Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Altera Program License +//Subscription Agreement, Altera MegaCore Function License +//Agreement, or other applicable license agreement, including, +//without limitation, that your use is for the sole purpose of +//programming logic devices manufactured by Altera and sold by +//Altera or its authorized distributors. Please refer to the +//applicable agreement for further details. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module fl_fifo ( + aclr, + data, + rdclk, + rdreq, + wrclk, + wrreq, + q, + rdempty, + wrfull, + wrusedw); + + input aclr; + input [71:0] data; + input rdclk; + input rdreq; + input wrclk; + input wrreq; + output [71:0] q; + output rdempty; + output wrfull; + output [7:0] wrusedw; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri0 aclr; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire sub_wire0; + wire [71:0] sub_wire1; + wire sub_wire2; + wire [7:0] sub_wire3; + wire wrfull = sub_wire0; + wire [71:0] q = sub_wire1[71:0]; + wire rdempty = sub_wire2; + wire [7:0] wrusedw = sub_wire3[7:0]; + + dcfifo dcfifo_component ( + .rdclk (rdclk), + .wrclk (wrclk), + .wrreq (wrreq), + .aclr (aclr), + .data (data), + .rdreq (rdreq), + .wrfull (sub_wire0), + .q (sub_wire1), + .rdempty (sub_wire2), + .wrusedw (sub_wire3), + .rdfull (), + .rdusedw (), + .wrempty ()); + defparam + dcfifo_component.intended_device_family = "Cyclone II", + dcfifo_component.lpm_hint = "MAXIMIZE_SPEED=5,", + dcfifo_component.lpm_numwords = 256, + dcfifo_component.lpm_showahead = "ON", + dcfifo_component.lpm_type = "dcfifo", + dcfifo_component.lpm_width = 72, + dcfifo_component.lpm_widthu = 8, + dcfifo_component.overflow_checking = "ON", + dcfifo_component.rdsync_delaypipe = 5, + dcfifo_component.underflow_checking = "ON", + dcfifo_component.use_eab = "ON", + dcfifo_component.write_aclr_synch = "ON", + dcfifo_component.wrsync_delaypipe = 5; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: AlmostEmpty NUMERIC "0" +// Retrieval info: PRIVATE: AlmostEmptyThr NUMERIC "-1" +// Retrieval info: PRIVATE: AlmostFull NUMERIC "0" +// Retrieval info: PRIVATE: AlmostFullThr NUMERIC "-1" +// Retrieval info: PRIVATE: CLOCKS_ARE_SYNCHRONIZED NUMERIC "0" +// Retrieval info: PRIVATE: Clock NUMERIC "4" +// Retrieval info: PRIVATE: Depth NUMERIC "256" +// Retrieval info: PRIVATE: Empty NUMERIC "1" +// Retrieval info: PRIVATE: Full NUMERIC "1" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +// Retrieval info: PRIVATE: LE_BasedFIFO NUMERIC "0" +// Retrieval info: PRIVATE: LegacyRREQ NUMERIC "0" +// Retrieval info: PRIVATE: MAX_DEPTH_BY_9 NUMERIC "0" +// Retrieval info: PRIVATE: OVERFLOW_CHECKING NUMERIC "0" +// Retrieval info: PRIVATE: Optimize NUMERIC "2" +// Retrieval info: PRIVATE: RAM_BLOCK_TYPE NUMERIC "0" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: UNDERFLOW_CHECKING NUMERIC "0" +// Retrieval info: PRIVATE: UsedW NUMERIC "1" +// Retrieval info: PRIVATE: Width NUMERIC "72" +// Retrieval info: PRIVATE: dc_aclr NUMERIC "1" +// Retrieval info: PRIVATE: diff_widths NUMERIC "0" +// Retrieval info: PRIVATE: msb_usedw NUMERIC "0" +// Retrieval info: PRIVATE: output_width NUMERIC "72" +// Retrieval info: PRIVATE: rsEmpty NUMERIC "1" +// Retrieval info: PRIVATE: rsFull NUMERIC "0" +// Retrieval info: PRIVATE: rsUsedW NUMERIC "0" +// Retrieval info: PRIVATE: sc_aclr NUMERIC "0" +// Retrieval info: PRIVATE: sc_sclr NUMERIC "0" +// Retrieval info: PRIVATE: wsEmpty NUMERIC "0" +// Retrieval info: PRIVATE: wsFull NUMERIC "1" +// Retrieval info: PRIVATE: wsUsedW NUMERIC "1" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +// Retrieval info: CONSTANT: LPM_HINT STRING "MAXIMIZE_SPEED=5," +// Retrieval info: CONSTANT: LPM_NUMWORDS NUMERIC "256" +// Retrieval info: CONSTANT: LPM_SHOWAHEAD STRING "ON" +// Retrieval info: CONSTANT: LPM_TYPE STRING "dcfifo" +// Retrieval info: CONSTANT: LPM_WIDTH NUMERIC "72" +// Retrieval info: CONSTANT: LPM_WIDTHU NUMERIC "8" +// Retrieval info: CONSTANT: OVERFLOW_CHECKING STRING "ON" +// Retrieval info: CONSTANT: RDSYNC_DELAYPIPE NUMERIC "5" +// Retrieval info: CONSTANT: UNDERFLOW_CHECKING STRING "ON" +// Retrieval info: CONSTANT: USE_EAB STRING "ON" +// Retrieval info: CONSTANT: WRITE_ACLR_SYNCH STRING "ON" +// Retrieval info: CONSTANT: WRSYNC_DELAYPIPE NUMERIC "5" +// Retrieval info: USED_PORT: aclr 0 0 0 0 INPUT GND "aclr" +// Retrieval info: USED_PORT: data 0 0 72 0 INPUT NODEFVAL "data[71..0]" +// Retrieval info: USED_PORT: q 0 0 72 0 OUTPUT NODEFVAL "q[71..0]" +// Retrieval info: USED_PORT: rdclk 0 0 0 0 INPUT NODEFVAL "rdclk" +// Retrieval info: USED_PORT: rdempty 0 0 0 0 OUTPUT NODEFVAL "rdempty" +// Retrieval info: USED_PORT: rdreq 0 0 0 0 INPUT NODEFVAL "rdreq" +// Retrieval info: USED_PORT: wrclk 0 0 0 0 INPUT NODEFVAL "wrclk" +// Retrieval info: USED_PORT: wrfull 0 0 0 0 OUTPUT NODEFVAL "wrfull" +// Retrieval info: USED_PORT: wrreq 0 0 0 0 INPUT NODEFVAL "wrreq" +// Retrieval info: USED_PORT: wrusedw 0 0 8 0 OUTPUT NODEFVAL "wrusedw[7..0]" +// Retrieval info: CONNECT: @aclr 0 0 0 0 aclr 0 0 0 0 +// Retrieval info: CONNECT: @data 0 0 72 0 data 0 0 72 0 +// Retrieval info: CONNECT: @rdclk 0 0 0 0 rdclk 0 0 0 0 +// Retrieval info: CONNECT: @rdreq 0 0 0 0 rdreq 0 0 0 0 +// Retrieval info: CONNECT: @wrclk 0 0 0 0 wrclk 0 0 0 0 +// Retrieval info: CONNECT: @wrreq 0 0 0 0 wrreq 0 0 0 0 +// Retrieval info: CONNECT: q 0 0 72 0 @q 0 0 72 0 +// Retrieval info: CONNECT: rdempty 0 0 0 0 @rdempty 0 0 0 0 +// Retrieval info: CONNECT: wrfull 0 0 0 0 @wrfull 0 0 0 0 +// Retrieval info: CONNECT: wrusedw 0 0 8 0 @wrusedw 0 0 8 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL fl_fifo.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL fl_fifo.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL fl_fifo.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL fl_fifo.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL fl_fifo_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL fl_fifo_bb.v TRUE +// Retrieval info: LIB_FILE: altera_mf diff --git a/de1/fpga-flash-nor/hexled.v b/de1/fpga-flash-nor/hexled.v new file mode 100644 index 0000000..1c25a59 --- /dev/null +++ b/de1/fpga-flash-nor/hexled.v @@ -0,0 +1,72 @@ +module hexled ( + value, + s7 + ); + + input [3:0] value; + output [6:0] s7; + reg [6:0] s7; + + always @( value ) + begin + case ( value ) + 4'h0: s7 = ~7'b0111111; + 4'h1: s7 = ~7'b0000110; + 4'h2: s7 = ~7'b1011011; + 4'h3: s7 = ~7'b1001111; + 4'h4: s7 = ~7'b1100110; + 4'h5: s7 = ~7'b1101101; + 4'h6: s7 = ~7'b1111101; + 4'h7: s7 = ~7'b0000111; + 4'h8: s7 = ~7'b1111111; + 4'h9: s7 = ~7'b1101111; + 4'hA: s7 = ~7'b1110111; + 4'hB: s7 = ~7'b1111100; + 4'hC: s7 = ~7'b0111001; + 4'hD: s7 = ~7'b1011110; + 4'hE: s7 = ~7'b1111001; + 4'hF: s7 = ~7'b1110001; + endcase + end +endmodule // hexled + +module hexledx ( + value, + blank, + minus, + s7 + ); + + input [3:0] value; + input blank; + input minus; + output [6:0] s7; + reg [6:0] s7; + + always @( value or blank or minus ) + begin + if ( blank ) + s7 = ~7'b0000000; + else if ( minus ) + s7 = ~7'b1000000; + else case ( value ) + 4'h0: s7 = ~7'b0111111; + 4'h1: s7 = ~7'b0000110; + 4'h2: s7 = ~7'b1011011; + 4'h3: s7 = ~7'b1001111; + 4'h4: s7 = ~7'b1100110; + 4'h5: s7 = ~7'b1101101; + 4'h6: s7 = ~7'b1111101; + 4'h7: s7 = ~7'b0000111; + 4'h8: s7 = ~7'b1111111; + 4'h9: s7 = ~7'b1101111; + 4'hA: s7 = ~7'b1110111; + 4'hB: s7 = ~7'b1111100; + 4'hC: s7 = ~7'b0111001; + 4'hD: s7 = ~7'b1011110; + 4'hE: s7 = ~7'b1111001; + 4'hF: s7 = ~7'b1110001; + endcase + end +endmodule // hexledx + diff --git a/de1/fpga-flash-nor/pll.qip b/de1/fpga-flash-nor/pll.qip new file mode 100644 index 0000000..39950ff --- /dev/null +++ b/de1/fpga-flash-nor/pll.qip @@ -0,0 +1,5 @@ +set_global_assignment -name IP_TOOL_NAME "ALTPLL" +set_global_assignment -name IP_TOOL_VERSION "11.0" +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "pll.v"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll_bb.v"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "pll.ppf"] diff --git a/de1/fpga-flash-nor/pll.v b/de1/fpga-flash-nor/pll.v new file mode 100644 index 0000000..93ce8a4 --- /dev/null +++ b/de1/fpga-flash-nor/pll.v @@ -0,0 +1,323 @@ +// megafunction wizard: %ALTPLL% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: altpll + +// ============================================================ +// File Name: pll.v +// Megafunction Name(s): +// altpll +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 11.0 Build 157 04/27/2011 SJ Web Edition +// ************************************************************ + + +//Copyright (C) 1991-2011 Altera Corporation +//Your use of Altera Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Altera Program License +//Subscription Agreement, Altera MegaCore Function License +//Agreement, or other applicable license agreement, including, +//without limitation, that your use is for the sole purpose of +//programming logic devices manufactured by Altera and sold by +//Altera or its authorized distributors. Please refer to the +//applicable agreement for further details. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module pll ( + areset, + inclk0, + c0, + locked); + + input areset; + input inclk0; + output c0; + output locked; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_off +`endif + tri0 areset; +`ifndef ALTERA_RESERVED_QIS +// synopsys translate_on +`endif + + wire sub_wire0; + wire [5:0] sub_wire1; + wire [0:0] sub_wire5 = 1'h0; + wire locked = sub_wire0; + wire [0:0] sub_wire2 = sub_wire1[0:0]; + wire c0 = sub_wire2; + wire sub_wire3 = inclk0; + wire [1:0] sub_wire4 = {sub_wire5, sub_wire3}; + + altpll altpll_component ( + .areset (areset), + .inclk (sub_wire4), + .locked (sub_wire0), + .clk (sub_wire1), + .activeclock (), + .clkbad (), + .clkena ({6{1'b1}}), + .clkloss (), + .clkswitch (1'b0), + .configupdate (1'b0), + .enable0 (), + .enable1 (), + .extclk (), + .extclkena ({4{1'b1}}), + .fbin (1'b1), + .fbmimicbidir (), + .fbout (), + .fref (), + .icdrclk (), + .pfdena (1'b1), + .phasecounterselect ({4{1'b1}}), + .phasedone (), + .phasestep (1'b1), + .phaseupdown (1'b1), + .pllena (1'b1), + .scanaclr (1'b0), + .scanclk (1'b0), + .scanclkena (1'b1), + .scandata (1'b0), + .scandataout (), + .scandone (), + .scanread (1'b0), + .scanwrite (1'b0), + .sclkout0 (), + .sclkout1 (), + .vcooverrange (), + .vcounderrange ()); + defparam + altpll_component.clk0_divide_by = 5, + altpll_component.clk0_duty_cycle = 50, + altpll_component.clk0_multiply_by = 2, + altpll_component.clk0_phase_shift = "0", + altpll_component.compensate_clock = "CLK0", + altpll_component.gate_lock_counter = 1048575, + altpll_component.gate_lock_signal = "YES", + altpll_component.inclk0_input_frequency = 20000, + altpll_component.intended_device_family = "Cyclone II", + altpll_component.invalid_lock_multiplier = 5, + altpll_component.lpm_hint = "CBX_MODULE_PREFIX=pll", + altpll_component.lpm_type = "altpll", + altpll_component.operation_mode = "NORMAL", + altpll_component.port_activeclock = "PORT_UNUSED", + altpll_component.port_areset = "PORT_USED", + altpll_component.port_clkbad0 = "PORT_UNUSED", + altpll_component.port_clkbad1 = "PORT_UNUSED", + altpll_component.port_clkloss = "PORT_UNUSED", + altpll_component.port_clkswitch = "PORT_UNUSED", + altpll_component.port_configupdate = "PORT_UNUSED", + altpll_component.port_fbin = "PORT_UNUSED", + altpll_component.port_inclk0 = "PORT_USED", + altpll_component.port_inclk1 = "PORT_UNUSED", + altpll_component.port_locked = "PORT_USED", + altpll_component.port_pfdena = "PORT_UNUSED", + altpll_component.port_phasecounterselect = "PORT_UNUSED", + altpll_component.port_phasedone = "PORT_UNUSED", + altpll_component.port_phasestep = "PORT_UNUSED", + altpll_component.port_phaseupdown = "PORT_UNUSED", + altpll_component.port_pllena = "PORT_UNUSED", + altpll_component.port_scanaclr = "PORT_UNUSED", + altpll_component.port_scanclk = "PORT_UNUSED", + altpll_component.port_scanclkena = "PORT_UNUSED", + altpll_component.port_scandata = "PORT_UNUSED", + altpll_component.port_scandataout = "PORT_UNUSED", + altpll_component.port_scandone = "PORT_UNUSED", + altpll_component.port_scanread = "PORT_UNUSED", + altpll_component.port_scanwrite = "PORT_UNUSED", + altpll_component.port_clk0 = "PORT_USED", + altpll_component.port_clk1 = "PORT_UNUSED", + altpll_component.port_clk2 = "PORT_UNUSED", + altpll_component.port_clk3 = "PORT_UNUSED", + altpll_component.port_clk4 = "PORT_UNUSED", + altpll_component.port_clk5 = "PORT_UNUSED", + altpll_component.port_clkena0 = "PORT_UNUSED", + altpll_component.port_clkena1 = "PORT_UNUSED", + altpll_component.port_clkena2 = "PORT_UNUSED", + altpll_component.port_clkena3 = "PORT_UNUSED", + altpll_component.port_clkena4 = "PORT_UNUSED", + altpll_component.port_clkena5 = "PORT_UNUSED", + altpll_component.port_extclk0 = "PORT_UNUSED", + altpll_component.port_extclk1 = "PORT_UNUSED", + altpll_component.port_extclk2 = "PORT_UNUSED", + altpll_component.port_extclk3 = "PORT_UNUSED", + altpll_component.valid_lock_multiplier = 1; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: ACTIVECLK_CHECK STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH STRING "1.000" +// Retrieval info: PRIVATE: BANDWIDTH_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH_FREQ_UNIT STRING "MHz" +// Retrieval info: PRIVATE: BANDWIDTH_PRESET STRING "Low" +// Retrieval info: PRIVATE: BANDWIDTH_USE_AUTO STRING "1" +// Retrieval info: PRIVATE: BANDWIDTH_USE_CUSTOM STRING "0" +// Retrieval info: PRIVATE: BANDWIDTH_USE_PRESET STRING "0" +// Retrieval info: PRIVATE: CLKBAD_SWITCHOVER_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKLOSS_CHECK STRING "0" +// Retrieval info: PRIVATE: CLKSWITCH_CHECK STRING "1" +// Retrieval info: PRIVATE: CNX_NO_COMPENSATE_RADIO STRING "0" +// Retrieval info: PRIVATE: CREATE_CLKBAD_CHECK STRING "0" +// Retrieval info: PRIVATE: CREATE_INCLK1_CHECK STRING "0" +// Retrieval info: PRIVATE: CUR_DEDICATED_CLK STRING "c0" +// Retrieval info: PRIVATE: CUR_FBIN_CLK STRING "c0" +// Retrieval info: PRIVATE: DEVICE_SPEED_GRADE STRING "7" +// Retrieval info: PRIVATE: DIV_FACTOR0 NUMERIC "1" +// Retrieval info: PRIVATE: DUTY_CYCLE0 STRING "50.00000000" +// Retrieval info: PRIVATE: EFF_OUTPUT_FREQ_VALUE0 STRING "20.000000" +// Retrieval info: PRIVATE: EXPLICIT_SWITCHOVER_COUNTER STRING "0" +// Retrieval info: PRIVATE: EXT_FEEDBACK_RADIO STRING "0" +// Retrieval info: PRIVATE: GLOCKED_COUNTER_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: GLOCKED_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: GLOCKED_MODE_CHECK STRING "1" +// Retrieval info: PRIVATE: GLOCK_COUNTER_EDIT NUMERIC "1048575" +// Retrieval info: PRIVATE: HAS_MANUAL_SWITCHOVER STRING "1" +// Retrieval info: PRIVATE: INCLK0_FREQ_EDIT STRING "50.000" +// Retrieval info: PRIVATE: INCLK0_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT STRING "100.000" +// Retrieval info: PRIVATE: INCLK1_FREQ_EDIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_CHANGED STRING "1" +// Retrieval info: PRIVATE: INCLK1_FREQ_UNIT_COMBO STRING "MHz" +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +// Retrieval info: PRIVATE: INT_FEEDBACK__MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: LOCKED_OUTPUT_CHECK STRING "1" +// Retrieval info: PRIVATE: LONG_SCAN_RADIO STRING "1" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE STRING "Not Available" +// Retrieval info: PRIVATE: LVDS_MODE_DATA_RATE_DIRTY NUMERIC "0" +// Retrieval info: PRIVATE: LVDS_PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: MIG_DEVICE_SPEED_GRADE STRING "Any" +// Retrieval info: PRIVATE: MIRROR_CLK0 STRING "0" +// Retrieval info: PRIVATE: MULT_FACTOR0 NUMERIC "1" +// Retrieval info: PRIVATE: NORMAL_MODE_RADIO STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ0 STRING "20.00000000" +// Retrieval info: PRIVATE: OUTPUT_FREQ_MODE0 STRING "1" +// Retrieval info: PRIVATE: OUTPUT_FREQ_UNIT0 STRING "MHz" +// Retrieval info: PRIVATE: PHASE_RECONFIG_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: PHASE_RECONFIG_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT0 STRING "0.00000000" +// Retrieval info: PRIVATE: PHASE_SHIFT_STEP_ENABLED_CHECK STRING "0" +// Retrieval info: PRIVATE: PHASE_SHIFT_UNIT0 STRING "deg" +// Retrieval info: PRIVATE: PLL_ADVANCED_PARAM_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_ARESET_CHECK STRING "1" +// Retrieval info: PRIVATE: PLL_AUTOPLL_CHECK NUMERIC "1" +// Retrieval info: PRIVATE: PLL_ENA_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_ENHPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FASTPLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_FBMIMIC_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_LVDS_PLL_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PLL_PFDENA_CHECK STRING "0" +// Retrieval info: PRIVATE: PLL_TARGET_HARCOPY_CHECK NUMERIC "0" +// Retrieval info: PRIVATE: PRIMARY_CLK_COMBO STRING "inclk0" +// Retrieval info: PRIVATE: RECONFIG_FILE STRING "pll.mif" +// Retrieval info: PRIVATE: SACN_INPUTS_CHECK STRING "0" +// Retrieval info: PRIVATE: SCAN_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: SELF_RESET_LOCK_LOSS STRING "0" +// Retrieval info: PRIVATE: SHORT_SCAN_RADIO STRING "0" +// Retrieval info: PRIVATE: SPREAD_FEATURE_ENABLED STRING "0" +// Retrieval info: PRIVATE: SPREAD_FREQ STRING "50.000" +// Retrieval info: PRIVATE: SPREAD_FREQ_UNIT STRING "KHz" +// Retrieval info: PRIVATE: SPREAD_PERCENT STRING "0.500" +// Retrieval info: PRIVATE: SPREAD_USE STRING "0" +// Retrieval info: PRIVATE: SRC_SYNCH_COMP_RADIO STRING "0" +// Retrieval info: PRIVATE: STICKY_CLK0 STRING "1" +// Retrieval info: PRIVATE: SWITCHOVER_COUNT_EDIT NUMERIC "1" +// Retrieval info: PRIVATE: SWITCHOVER_FEATURE_ENABLED STRING "1" +// Retrieval info: PRIVATE: SYNTH_WRAPPER_GEN_POSTFIX STRING "0" +// Retrieval info: PRIVATE: USE_CLK0 STRING "1" +// Retrieval info: PRIVATE: USE_CLKENA0 STRING "0" +// Retrieval info: PRIVATE: USE_MIL_SPEED_GRADE NUMERIC "0" +// Retrieval info: PRIVATE: ZERO_DELAY_RADIO STRING "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: CLK0_DIVIDE_BY NUMERIC "5" +// Retrieval info: CONSTANT: CLK0_DUTY_CYCLE NUMERIC "50" +// Retrieval info: CONSTANT: CLK0_MULTIPLY_BY NUMERIC "2" +// Retrieval info: CONSTANT: CLK0_PHASE_SHIFT STRING "0" +// Retrieval info: CONSTANT: COMPENSATE_CLOCK STRING "CLK0" +// Retrieval info: CONSTANT: GATE_LOCK_COUNTER NUMERIC "1048575" +// Retrieval info: CONSTANT: GATE_LOCK_SIGNAL STRING "YES" +// Retrieval info: CONSTANT: INCLK0_INPUT_FREQUENCY NUMERIC "20000" +// Retrieval info: CONSTANT: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +// Retrieval info: CONSTANT: INVALID_LOCK_MULTIPLIER NUMERIC "5" +// Retrieval info: CONSTANT: LPM_TYPE STRING "altpll" +// Retrieval info: CONSTANT: OPERATION_MODE STRING "NORMAL" +// Retrieval info: CONSTANT: PORT_ACTIVECLOCK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_ARESET STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_CLKBAD0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKBAD1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKLOSS STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CLKSWITCH STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_CONFIGUPDATE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_FBIN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_INCLK0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_INCLK1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_LOCKED STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_PFDENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASECOUNTERSELECT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASESTEP STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PHASEUPDOWN STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_PLLENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANACLR STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLK STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANCLKENA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATA STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDATAOUT STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANDONE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANREAD STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_SCANWRITE STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk0 STRING "PORT_USED" +// Retrieval info: CONSTANT: PORT_clk1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clk5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena4 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_clkena5 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk0 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk1 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk2 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: PORT_extclk3 STRING "PORT_UNUSED" +// Retrieval info: CONSTANT: VALID_LOCK_MULTIPLIER NUMERIC "1" +// Retrieval info: USED_PORT: @clk 0 0 6 0 OUTPUT_CLK_EXT VCC "@clk[5..0]" +// Retrieval info: USED_PORT: @extclk 0 0 4 0 OUTPUT_CLK_EXT VCC "@extclk[3..0]" +// Retrieval info: USED_PORT: areset 0 0 0 0 INPUT GND "areset" +// Retrieval info: USED_PORT: c0 0 0 0 0 OUTPUT_CLK_EXT VCC "c0" +// Retrieval info: USED_PORT: inclk0 0 0 0 0 INPUT_CLK_EXT GND "inclk0" +// Retrieval info: USED_PORT: locked 0 0 0 0 OUTPUT GND "locked" +// Retrieval info: CONNECT: @areset 0 0 0 0 areset 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 1 GND 0 0 0 0 +// Retrieval info: CONNECT: @inclk 0 0 1 0 inclk0 0 0 0 0 +// Retrieval info: CONNECT: c0 0 0 0 0 @clk 0 0 1 0 +// Retrieval info: CONNECT: locked 0 0 0 0 @locked 0 0 0 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.ppf TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll.bsf FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll_inst.v FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL pll_bb.v TRUE +// Retrieval info: LIB_FILE: altera_mf +// Retrieval info: CBX_MODULE_PREFIX: ON diff --git a/de1/fpga-flash-nor/protocol.txt b/de1/fpga-flash-nor/protocol.txt new file mode 100644 index 0000000..d7a1968 --- /dev/null +++ b/de1/fpga-flash-nor/protocol.txt @@ -0,0 +1,64 @@ +Virtual IR register (4 bits): + +0 - bypass +1 - read fifo +2 - write fifo space query +3 - write fifo +4 - read ready (single bit) +5 - write reset flag (single bit; write 1 then 0) +F - bypass + +Virtual DR register 1: + +READ FIFO + +72 bits: +-binary- -------hex------- +VNNNCCCC DDDDDDD DDDDDDDDD - V = valid + - N = sequence counter + - C = top 4 bits of command + +Read transactions can be streamed by shifting out a multiple of 72 bits. + +Virtual DR register 2: + +Reads the amount of space in the write FIFO as an 8-bit number. + + +Virtual DR register 3: + +WRITE FIFO + +72 bits: +-binary- -------hex------- + +000XXXXX XXXXXXXX XXXXXXXX - noop + +0010XXXX XXXXXXXX CCCCCCCC - delay for C cycles @ 20 MHz + +0101XXXX AAAAAAAA CCCCCCCC - zero check + Returns last address read in [63:32] + Returns last datum 1's extended in [31:0] - FFFFFFFF on success + +0110XXXX XXXXXXXX TTTTTTTT - read back address register, token + Returns address register in [63:32] + Returns token in [31:0] + +0111XXXX AAAAAAAA CCCCCCCC - compute CRC32 + Returns last address read in [63:32] + Returns Ethernet CRC32 of the region in [31:0] + +100SEEEE AAAAAAAA DDDDDDDD - write cycle (address, data) + address register set to A if S=1 + E is byte enables; for a byte flash + E should be set to 0001 + +1011CCCC DDDDDDDD DDDDDDDD - program bytes (C = byte count) + +1101XXXX AAAAAAAA CCCCCCCC - set address register to A + read C bytes (pad output to 64 bits) + if C=0 no read is done + +111XXXXX XXXXXXXX XXXXXXXX - noop + +For vestigial writes the data should be right-justified (LSB valid) diff --git a/de1/fpga-flash-nor/quartus_wrap b/de1/fpga-flash-nor/quartus_wrap new file mode 100755 index 0000000..e818413 --- /dev/null +++ b/de1/fpga-flash-nor/quartus_wrap @@ -0,0 +1,15 @@ +#!/bin/bash + +AD=/software/apps/altera/quartus_ii_13.0sp1 +if [ $(uname -m ) == "x86_64" ]; then + LL=linux64 +else + LL=linux +fi +QUARTUS_ROOTDIR="${AD}/quartus" +PATH="${AD}/quartus/bin:${AD}/quartus/sopc_builder/bin:${AD}/nios2eds/sdk2/bin:${AD}/nios2eds/bin:${AD}/nios2eds/bin/gnu/H-i686-pc-linux-gnu/bin:${PATH}" +LD_LIBRARY_PATH="${AD}/quartus/${LL}:/software/apps/altera/libcompat/32:/software/apps/altera/libcompat/64:${LD_LIBRARY_PATH}" + +export LD_LIBRARY_PATH PATH QUARTUS_ROOTDIR + +"$@" diff --git a/de1/fpga-flash-nor/vjtag_mega.qip b/de1/fpga-flash-nor/vjtag_mega.qip new file mode 100644 index 0000000..9bff0d2 --- /dev/null +++ b/de1/fpga-flash-nor/vjtag_mega.qip @@ -0,0 +1,6 @@ +set_global_assignment -name IP_TOOL_NAME "Virtual JTAG" +set_global_assignment -name IP_TOOL_VERSION "11.0" +set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "vjtag_mega.v"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "vjtag_mega.bsf"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "vjtag_mega_inst.v"] +set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "vjtag_mega_bb.v"] diff --git a/de1/fpga-flash-nor/vjtag_mega.v b/de1/fpga-flash-nor/vjtag_mega.v new file mode 100644 index 0000000..844c24d --- /dev/null +++ b/de1/fpga-flash-nor/vjtag_mega.v @@ -0,0 +1,181 @@ +// megafunction wizard: %Virtual JTAG% +// GENERATION: STANDARD +// VERSION: WM1.0 +// MODULE: sld_virtual_jtag + +// ============================================================ +// File Name: vjtag_mega.v +// Megafunction Name(s): +// sld_virtual_jtag +// +// Simulation Library Files(s): +// altera_mf +// ============================================================ +// ************************************************************ +// THIS IS A WIZARD-GENERATED FILE. DO NOT EDIT THIS FILE! +// +// 11.0 Build 157 04/27/2011 SJ Web Edition +// ************************************************************ + + +//Copyright (C) 1991-2011 Altera Corporation +//Your use of Altera Corporation's design tools, logic functions +//and other software and tools, and its AMPP partner logic +//functions, and any output files from any of the foregoing +//(including device programming or simulation files), and any +//associated documentation or information are expressly subject +//to the terms and conditions of the Altera Program License +//Subscription Agreement, Altera MegaCore Function License +//Agreement, or other applicable license agreement, including, +//without limitation, that your use is for the sole purpose of +//programming logic devices manufactured by Altera and sold by +//Altera or its authorized distributors. Please refer to the +//applicable agreement for further details. + + +// synopsys translate_off +`timescale 1 ps / 1 ps +// synopsys translate_on +module vjtag_mega ( + ir_out, + tdo, + ir_in, + tck, + tdi, + virtual_state_cdr, + virtual_state_cir, + virtual_state_e1dr, + virtual_state_e2dr, + virtual_state_pdr, + virtual_state_sdr, + virtual_state_udr, + virtual_state_uir); + + input [3:0] ir_out; + input tdo; + output [3:0] ir_in; + output tck; + output tdi; + output virtual_state_cdr; + output virtual_state_cir; + output virtual_state_e1dr; + output virtual_state_e2dr; + output virtual_state_pdr; + output virtual_state_sdr; + output virtual_state_udr; + output virtual_state_uir; + + wire sub_wire0; + wire sub_wire1; + wire [3:0] sub_wire2; + wire sub_wire3; + wire sub_wire4; + wire sub_wire5; + wire sub_wire6; + wire sub_wire7; + wire sub_wire8; + wire sub_wire9; + wire sub_wire10; + wire virtual_state_cir = sub_wire0; + wire virtual_state_pdr = sub_wire1; + wire [3:0] ir_in = sub_wire2[3:0]; + wire tdi = sub_wire3; + wire virtual_state_udr = sub_wire4; + wire tck = sub_wire5; + wire virtual_state_e1dr = sub_wire6; + wire virtual_state_uir = sub_wire7; + wire virtual_state_cdr = sub_wire8; + wire virtual_state_e2dr = sub_wire9; + wire virtual_state_sdr = sub_wire10; + + sld_virtual_jtag sld_virtual_jtag_component ( + .ir_out (ir_out), + .tdo (tdo), + .virtual_state_cir (sub_wire0), + .virtual_state_pdr (sub_wire1), + .ir_in (sub_wire2), + .tdi (sub_wire3), + .virtual_state_udr (sub_wire4), + .tck (sub_wire5), + .virtual_state_e1dr (sub_wire6), + .virtual_state_uir (sub_wire7), + .virtual_state_cdr (sub_wire8), + .virtual_state_e2dr (sub_wire9), + .virtual_state_sdr (sub_wire10) + // synopsys translate_off + , + .jtag_state_cdr (), + .jtag_state_cir (), + .jtag_state_e1dr (), + .jtag_state_e1ir (), + .jtag_state_e2dr (), + .jtag_state_e2ir (), + .jtag_state_pdr (), + .jtag_state_pir (), + .jtag_state_rti (), + .jtag_state_sdr (), + .jtag_state_sdrs (), + .jtag_state_sir (), + .jtag_state_sirs (), + .jtag_state_tlr (), + .jtag_state_udr (), + .jtag_state_uir (), + .tms () + // synopsys translate_on + ); + defparam + sld_virtual_jtag_component.sld_auto_instance_index = "YES", + sld_virtual_jtag_component.sld_instance_index = 0, + sld_virtual_jtag_component.sld_ir_width = 4, + sld_virtual_jtag_component.sld_sim_action = "", + sld_virtual_jtag_component.sld_sim_n_scan = 0, + sld_virtual_jtag_component.sld_sim_total_length = 0; + + +endmodule + +// ============================================================ +// CNX file retrieval info +// ============================================================ +// Retrieval info: PRIVATE: INTENDED_DEVICE_FAMILY STRING "Cyclone II" +// Retrieval info: PRIVATE: show_jtag_state STRING "0" +// Retrieval info: LIBRARY: altera_mf altera_mf.altera_mf_components.all +// Retrieval info: CONSTANT: SLD_AUTO_INSTANCE_INDEX STRING "YES" +// Retrieval info: CONSTANT: SLD_INSTANCE_INDEX NUMERIC "0" +// Retrieval info: CONSTANT: SLD_IR_WIDTH NUMERIC "4" +// Retrieval info: CONSTANT: SLD_SIM_ACTION STRING "" +// Retrieval info: CONSTANT: SLD_SIM_N_SCAN NUMERIC "0" +// Retrieval info: CONSTANT: SLD_SIM_TOTAL_LENGTH NUMERIC "0" +// Retrieval info: USED_PORT: ir_in 0 0 4 0 OUTPUT NODEFVAL "ir_in[3..0]" +// Retrieval info: USED_PORT: ir_out 0 0 4 0 INPUT NODEFVAL "ir_out[3..0]" +// Retrieval info: USED_PORT: tck 0 0 0 0 OUTPUT NODEFVAL "tck" +// Retrieval info: USED_PORT: tdi 0 0 0 0 OUTPUT NODEFVAL "tdi" +// Retrieval info: USED_PORT: tdo 0 0 0 0 INPUT NODEFVAL "tdo" +// Retrieval info: USED_PORT: virtual_state_cdr 0 0 0 0 OUTPUT NODEFVAL "virtual_state_cdr" +// Retrieval info: USED_PORT: virtual_state_cir 0 0 0 0 OUTPUT NODEFVAL "virtual_state_cir" +// Retrieval info: USED_PORT: virtual_state_e1dr 0 0 0 0 OUTPUT NODEFVAL "virtual_state_e1dr" +// Retrieval info: USED_PORT: virtual_state_e2dr 0 0 0 0 OUTPUT NODEFVAL "virtual_state_e2dr" +// Retrieval info: USED_PORT: virtual_state_pdr 0 0 0 0 OUTPUT NODEFVAL "virtual_state_pdr" +// Retrieval info: USED_PORT: virtual_state_sdr 0 0 0 0 OUTPUT NODEFVAL "virtual_state_sdr" +// Retrieval info: USED_PORT: virtual_state_udr 0 0 0 0 OUTPUT NODEFVAL "virtual_state_udr" +// Retrieval info: USED_PORT: virtual_state_uir 0 0 0 0 OUTPUT NODEFVAL "virtual_state_uir" +// Retrieval info: CONNECT: @ir_out 0 0 4 0 ir_out 0 0 4 0 +// Retrieval info: CONNECT: @tdo 0 0 0 0 tdo 0 0 0 0 +// Retrieval info: CONNECT: ir_in 0 0 4 0 @ir_in 0 0 4 0 +// Retrieval info: CONNECT: tck 0 0 0 0 @tck 0 0 0 0 +// Retrieval info: CONNECT: tdi 0 0 0 0 @tdi 0 0 0 0 +// Retrieval info: CONNECT: virtual_state_cdr 0 0 0 0 @virtual_state_cdr 0 0 0 0 +// Retrieval info: CONNECT: virtual_state_cir 0 0 0 0 @virtual_state_cir 0 0 0 0 +// Retrieval info: CONNECT: virtual_state_e1dr 0 0 0 0 @virtual_state_e1dr 0 0 0 0 +// Retrieval info: CONNECT: virtual_state_e2dr 0 0 0 0 @virtual_state_e2dr 0 0 0 0 +// Retrieval info: CONNECT: virtual_state_pdr 0 0 0 0 @virtual_state_pdr 0 0 0 0 +// Retrieval info: CONNECT: virtual_state_sdr 0 0 0 0 @virtual_state_sdr 0 0 0 0 +// Retrieval info: CONNECT: virtual_state_udr 0 0 0 0 @virtual_state_udr 0 0 0 0 +// Retrieval info: CONNECT: virtual_state_uir 0 0 0 0 @virtual_state_uir 0 0 0 0 +// Retrieval info: GEN_FILE: TYPE_NORMAL vjtag_mega.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL vjtag_mega.inc FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL vjtag_mega.cmp FALSE +// Retrieval info: GEN_FILE: TYPE_NORMAL vjtag_mega.bsf TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL vjtag_mega_inst.v TRUE +// Retrieval info: GEN_FILE: TYPE_NORMAL vjtag_mega_bb.v TRUE +// Retrieval info: LIB_FILE: altera_mf diff --git a/docs/Acorn_BBCSMOct85_Sec1.pdf b/docs/Acorn_BBCSMOct85_Sec1.pdf Binary files differnew file mode 100644 index 0000000..c0a47b5 --- /dev/null +++ b/docs/Acorn_BBCSMOct85_Sec1.pdf diff --git a/docs/README b/docs/README new file mode 100644 index 0000000..47daf92 --- /dev/null +++ b/docs/README @@ -0,0 +1,6 @@ +T65 implementation from http://www.fpgaarcade.com/resources/T65_v302.zip (bug fixes from PACE dev) +M6522 implementation from FPGA arcade VIC20 design. Various bug fixes added locally. +SN76489 implementation by Arnim Laeuger and obtained from FPGA arcade + + + diff --git a/docs/SN76489.pdf b/docs/SN76489.pdf Binary files differnew file mode 100644 index 0000000..b103f37 --- /dev/null +++ b/docs/SN76489.pdf diff --git a/docs/keyboard.odg b/docs/keyboard.odg Binary files differnew file mode 100644 index 0000000..403b1e7 --- /dev/null +++ b/docs/keyboard.odg diff --git a/docs/keyboard.png b/docs/keyboard.png Binary files differnew file mode 100644 index 0000000..12735bd --- /dev/null +++ b/docs/keyboard.png diff --git a/docs/keyboard.txt b/docs/keyboard.txt new file mode 100644 index 0000000..d63fa03 --- /dev/null +++ b/docs/keyboard.txt @@ -0,0 +1,81 @@ +Column Row Key PC key Scancode +0 0 SHIFT LEFT SHIFT, RIGHT SHIFT 12 + 59 +0 1 Q Q 15 +0 2 F0 F10 09 +0 3 1 (!) 1 16 +0 4 CAPS LOCK CAPS LOCK 58 +0 5 SHIFT LOCK LEFT ALT 11 +0 6 TAB TAB 0D +0 7 ESCAPE ESCAPE 76 +1 0 CTRL LEFT CTRL, RIGHT CTRL 14 + E0,14 +1 1 3 (#) 3 26 +1 2 W W 1D +1 3 2 (") 2 1E +1 4 A A 1C +1 5 S S 1B +1 6 Z Z 1A +1 7 F1 F1 05 +2 0 DIP 7 +2 1 4 ($) 4 25 +2 2 E E 24 +2 3 D D 23 +2 4 X X 22 +2 5 C C 21 +2 6 SPACE SPACE 29 +2 7 F2 F2 06 +3 0 DIP 6 +3 1 5 (%) 5 2E +3 2 T T 2C +3 3 R R 2D +3 4 F F 2B +3 5 G G 34 +3 6 V V 2A +3 7 F3 F3 04 +4 0 DIP 5 +4 1 F4 F4 0C +4 2 7 (') 7 3D +4 3 6 (&) 6 36 +4 4 Y Y 35 +4 5 H H 33 +4 6 B B 32 +4 7 F5 F5 03 +5 0 DIP 4 +5 1 8 (() 8 3E +5 2 I I 43 +5 3 U U 3C +5 4 J J 3B +5 5 N N 31 +5 6 M M 3A +5 7 F6 F6 0B +6 0 DIP 3 +6 1 F7 F7 83 +6 2 9 ()) 9 46 +6 3 O O 44 +6 4 K K 42 +6 5 L L 4B +6 6 , (<) , 41 +6 7 F8 F8 0A +7 0 DIP 2 +7 1 - (=) - 4E +7 2 0 0 45 +7 3 P P 4D +7 4 @ ` 0E +7 5 ; (+) ; 4C +7 6 . (>) . 49 +7 7 F9 F9 01 +8 0 DIP 1 +8 1 ^ (~) = 55 +8 2 _ (£) # 5D +8 3 [ ({) [ 54 +8 4 : (*) ' 52 +8 5 ] (}) ] 5B +8 6 / (?) / 4A +8 7 \ (|) \ 61 +9 0 DIP 0 +9 1 LEFT LEFT E0,6B +9 2 DOWN DOWN E0,72 +9 3 UP UP E0,75 +9 4 RETURN RETURN 5A +9 5 DELETE BACKSPACE 66 +9 6 COPY END E0,69 +9 7 RIGHT RIGHT E0,74 diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/C000 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/C000 new file mode 100644 index 0000000..ccfc412 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/C000 @@ -0,0 +1,876 @@ +BBC Operating System OS 1.20 +============================ +Commented disassembly by Geoff Cox, originally published on Micronet. +Additional comments by J.G.Harston. + +***************** VDU CHARACTER FONT LOOK UP TABLE **************************** + +These are the default definitions for characters 32-127. The are accessed with +OSWORD 10 (read character definition) and reprogrammed with VDU 23 (define +character). If the character set is not exploded, then a block of 32 characters +is copied to the soft character buffer at &0C00 when a character is defined. + +C000 DB 00 ;00000000 ........ &20 32 - ' ' +C001 DB 00 ;00000000 ........ +C002 DB 00 ;00000000 ........ +C003 DB 00 ;00000000 ........ +C004 DB 00 ;00000000 ........ +C005 DB 00 ;00000000 ........ +C006 DB 00 ;00000000 ........ +C007 DB 00 ;00000000 ........ + +C008 DB 18 ;00011000 ...**... &21 33 - '!' +C009 DB 18 ;00011000 ...**... +C00A DB 18 ;00011000 ...**... +C00B DB 18 ;00011000 ...**... +C00C DB 18 ;00011000 ...**... +C00D DB 00 ;00000000 ........ +C00E DB 18 ;00011000 ...**... +C00F DB 00 ;00000000 ........ + +C010 DB 6C ;01101100 .**.**.. &22 34 - '"' +C011 DB 6C ;01101100 .**.**.. +C012 DB 6C ;01101100 .**.**.. +C013 DB 00 ;00000000 ........ +C014 DB 00 ;00000000 ........ +C015 DB 00 ;00000000 ........ +C016 DB 00 ;00000000 ........ +C017 DB 00 ;00000000 ........ + +C018 DB 36 ;00110110 ..**.**. &23 35 - '#' +C019 DB 36 ;00110110 ..**.**. +C01A DB 7F ;01111111 .******* +C01B DB 36 ;00110110 ..**.**. +C01C DB 7F ;01111111 .******* +C01D DB 36 ;00110110 ..**.**. +C01E DB 36 ;00110110 ..**.**. +C01F DB 00 ;00000000 ........ + +C020 DB 0C ;00001100 ....**.. &24 36 - '$' +C021 DB 3F ;00111111 ..****** +C022 DB 68 ;01101000 .**.*... +C023 DB 3E ;00111110 ..*****. +C024 DB 0B ;00001011 ....*.** +C025 DB 7E ;01111110 .******. +C026 DB 18 ;00011000 ...**... +C027 DB 00 ;00000000 ........ + +C028 DB 60 ;01100000 .**..... &25 37 - '%' +C029 DB 66 ;01100110 .**..**. +C02A DB 0C ;00001100 ....**.. +C02B DB 18 ;00011000 ...**... +C02C DB 30 ;00110000 ..**.... +C02D DB 66 ;01100110 .**..**. +C02E DB 06 ;00000110 .....**. +C02F DB 00 ;00000000 ........ + +C030 DB 38 ;00111000 ..***... &26 38 - '&' +C031 DB 6C ;01101100 .**.**.. +C032 DB 6C ;01101100 .**.**.. +C033 DB 38 ;00111000 ..***... +C034 DB 6D ;01101101 .**.**.* +C035 DB 66 ;01100110 .**..**. +C036 DB 3B ;00111011 ..***.** +C037 DB 00 ;00000000 ........ + +C038 DB 0C ;00001100 ....**.. &27 39 - ''' +C039 DB 18 ;00011000 ...**... +C03A DB 30 ;00110000 ..**.... +C03B DB 00 ;00000000 ........ +C03C DB 00 ;00000000 ........ +C03D DB 00 ;00000000 ........ +C03E DB 00 ;00000000 ........ +C03F DB 00 ;00000000 ........ + +C040 DB 0C ;00001100 ....**.. &28 40 - '(' +C041 DB 18 ;00011000 ...**... +C042 DB 30 ;00110000 ..**.... +C043 DB 30 ;00110000 ..**.... +C044 DB 30 ;00110000 ..**.... +C045 DB 18 ;00011000 ...**... +C046 DB 0C ;00001100 ....**.. +C047 DB 00 ;00000000 ........ + +C048 DB 30 ;00110000 ..**.... &29 41 - ')' +C049 DB 18 ;00011000 ...**... +C04A DB 0C ;00001100 ....**.. +C04B DB 0C ;00001100 ....**.. +C04C DB 0C ;00001100 ....**.. +C04D DB 18 ;00011000 ...**... +C04E DB 30 ;00110000 ..**.... +C04F DB 00 ;00000000 ........ + +C050 DB 00 ;00000000 ........ &2A 42 - '*' +C051 DB 18 ;00011000 ...**... +C052 DB 7E ;01111110 .******. +C053 DB 3C ;00111100 ..****.. +C054 DB 7E ;01111110 .******. +C055 DB 18 ;00011000 ...**... +C056 DB 00 ;00000000 ........ +C057 DB 00 ;00000000 ........ + +C058 DB 00 ;00000000 ........ &2B 43 - '+' +C059 DB 18 ;00011000 ...**... +C05A DB 18 ;00011000 ...**... +C05B DB 7E ;01111110 .******. +C05C DB 18 ;00011000 ...**... +C05D DB 18 ;00011000 ...**... +C05E DB 00 ;00000000 ........ +C05F DB 00 ;00000000 ........ + +C060 DB 00 ;00000000 ........ &2C 44 - ',' +C061 DB 00 ;00000000 ........ +C062 DB 00 ;00000000 ........ +C063 DB 00 ;00000000 ........ +C064 DB 00 ;00000000 ........ +C065 DB 18 ;00011000 ...**... +C066 DB 18 ;00011000 ...**... +C067 DB 30 ;00110000 ..**.... + +C068 DB 00 ;00000000 ........ &2D 45 - '-' +C069 DB 00 ;00000000 ........ +C06A DB 00 ;00000000 ........ +C06B DB 7E ;01111110 .******. +C06C DB 00 ;00000000 ........ +C06D DB 00 ;00000000 ........ +C06E DB 00 ;00000000 ........ +C06F DB 00 ;00000000 ........ + +C070 DB 00 ;00000000 ........ &2E 46 - '.' +C071 DB 00 ;00000000 ........ +C072 DB 00 ;00000000 ........ +C073 DB 00 ;00000000 ........ +C074 DB 00 ;00000000 ........ +C075 DB 18 ;00011000 ...**... +C076 DB 18 ;00011000 ...**... +C077 DB 00 ;00000000 ........ + +C078 DB 00 ;00000000 ........ &2F 47 - '/' +C079 DB 06 ;00000110 .....**. +C07A DB 0C ;00001100 ....**.. +C07B DB 18 ;00011000 ...**... +C07C DB 30 ;00110000 ..**.... +C07D DB 60 ;01100000 .**..... +C07E DB 00 ;00000000 ........ +C07F DB 00 ;00000000 ........ + +C080 DB 3C ;00111100 ..****.. &30 48 - '0' +C081 DB 66 ;01100110 .**..**. +C082 DB 6E ;01101110 .**.***. +C083 DB 7E ;01111110 .******. +C084 DB 76 ;01110110 .***.**. +C085 DB 66 ;01100110 .**..**. +C086 DB 3C ;00111100 ..****.. +C087 DB 00 ;00000000 ........ + +C088 DB 18 ;00011000 ...**... &31 49 - '1' +C089 DB 38 ;00111000 ..***... +C08A DB 18 ;00011000 ...**... +C08B DB 18 ;00011000 ...**... +C08C DB 18 ;00011000 ...**... +C08D DB 18 ;00011000 ...**... +C08E DB 7E ;01111110 .******. +C08F DB 00 ;00000000 ........ + +C090 DB 3C ;00111100 ..****.. &32 50 - '2' +C091 DB 66 ;01100110 .**..**. +C092 DB 06 ;00000110 .....**. +C093 DB 0C ;00001100 ....**.. +C094 DB 18 ;00011000 ...**... +C095 DB 30 ;00110000 ..**.... +C096 DB 7E ;01111110 .******. +C097 DB 00 ;00000000 ........ + +C098 DB 3C ;00111100 ..****.. &33 51 - '3' +C099 DB 66 ;01100110 .**..**. +C09A DB 06 ;00000110 .....**. +C09B DB 1C ;00011100 ...***.. +C09C DB 06 ;00000110 .....**. +C09D DB 66 ;01100110 .**..**. +C09E DB 3C ;00111100 ..****.. +C09F DB 00 ;00000000 ........ + +C0A0 DB 0C ;00001100 ....**.. &34 52 - '4' +C0A1 DB 1C ;00011100 ...***.. +C0A2 DB 3C ;00111100 ..****.. +C0A3 DB 6C ;01101100 .**.**.. +C0A4 DB 7E ;01111110 .******. +C0A5 DB 0C ;00001100 ....**.. +C0A6 DB 0C ;00001100 ....**.. +C0A7 DB 00 ;00000000 ........ + +C0A8 DB 7E ;01111110 .******. &35 53 - '5' +C0A9 DB 60 ;01100000 .**..... +C0AA DB 7C ;01111100 .*****.. +C0AB DB 06 ;00000110 .....**. +C0AC DB 06 ;00000110 .....**. +C0AD DB 66 ;01100110 .**..**. +C0AE DB 3C ;00111100 ..****.. +C0AF DB 00 ;00000000 ........ + +C0B0 DB 1C ;00011100 ...***.. &36 54 - '6' +C0B1 DB 30 ;00110000 ..**.... +C0B2 DB 60 ;01100000 .**..... +C0B3 DB 7C ;01111100 .*****.. +C0B4 DB 66 ;01100110 .**..**. +C0B5 DB 66 ;01100110 .**..**. +C0B6 DB 3C ;00111100 ..****.. +C0B7 DB 00 ;00000000 ........ + +C0B8 DB 7E ;01111110 .******. &37 55 - '7' +C0B9 DB 06 ;00000110 .....**. +C0BA DB 0C ;00001100 ....**.. +C0BB DB 18 ;00011000 ...**... +C0BC DB 30 ;00110000 ..**.... +C0BD DB 30 ;00110000 ..**.... +C0BE DB 30 ;00110000 ..**.... +C0BF DB 00 ;00000000 ........ + +C0C0 DB 3C ;00111100 ..****.. &38 56 - '8' +C0C1 DB 66 ;01100110 .**..**. +C0C2 DB 66 ;01100110 .**..**. +C0C3 DB 3C ;00111100 ..****.. +C0C4 DB 66 ;01100110 .**..**. +C0C5 DB 66 ;01100110 .**..**. +C0C6 DB 3C ;00111100 ..****.. +C0C7 DB 00 ;00000000 ........ + +C0C8 DB 3C ;00111100 ..****.. &39 57 - '9' +C0C9 DB 66 ;01100110 .**..**. +C0CA DB 66 ;01100110 .**..**. +C0CB DB 3E ;00111110 ..*****. +C0CC DB 06 ;00000110 .....**. +C0CD DB 0C ;00001100 ....**.. +C0CE DB 38 ;00111000 ..***... +C0CF DB 00 ;00000000 ........ + +C0D0 DB 00 ;00000000 ........ &3A 58 - ':' +C0D1 DB 00 ;00000000 ........ +C0D2 DB 18 ;00011000 ...**... +C0D3 DB 18 ;00011000 ...**... +C0D4 DB 00 ;00000000 ........ +C0D5 DB 18 ;00011000 ...**... +C0D6 DB 18 ;00011000 ...**... +C0D7 DB 00 ;00000000 ........ + +C0D8 DB 00 ;00000000 ........ &3B 59 - ';' +C0D9 DB 00 ;00000000 ........ +C0DA DB 18 ;00011000 ...**... +C0DB DB 18 ;00011000 ...**... +C0DC DB 00 ;00000000 ........ +C0DD DB 18 ;00011000 ...**... +C0DE DB 18 ;00011000 ...**... +C0DF DB 30 ;00110000 ..**.... + +C0E0 DB 0C ;00001100 ....**.. &3C 60 - '<' +C0E1 DB 18 ;00011000 ...**... +C0E2 DB 30 ;00110000 ..**.... +C0E3 DB 60 ;01100000 .**..... +C0E4 DB 30 ;00110000 ..**.... +C0E5 DB 18 ;00011000 ...**... +C0E6 DB 0C ;00001100 ....**.. +C0E7 DB 00 ;00000000 ........ + +C0E8 DB 00 ;00000000 ........ &3D 61 - '=' +C0E9 DB 00 ;00000000 ........ +C0EA DB 7E ;01111110 .******. +C0EB DB 00 ;00000000 ........ +C0EC DB 7E ;01111110 .******. +C0ED DB 00 ;00000000 ........ +C0EE DB 00 ;00000000 ........ +C0EF DB 00 ;00000000 ........ + +C0F0 DB 30 ;00110000 ..**.... &3E 62 - '>' +C0F1 DB 18 ;00011000 ...**... +C0F2 DB 0C ;00001100 ....**.. +C0F3 DB 06 ;00000110 .....**. +C0F4 DB 0C ;00001100 ....**.. +C0F5 DB 18 ;00011000 ...**... +C0F6 DB 30 ;00110000 ..**.... +C0F7 DB 00 ;00000000 ........ + +C0F8 DB 3C ;00111100 ..****.. &3F 63 - '?' +C0F9 DB 66 ;01100110 .**..**. +C0FA DB 0C ;00001100 ....**.. +C0FB DB 18 ;00011000 ...**... +C0FC DB 18 ;00011000 ...**... +C0FD DB 00 ;00000000 ........ +C0FE DB 18 ;00011000 ...**... +C0FF DB 00 ;00000000 ........ + +C100 DB 3C ;00111100 ..****.. &40 64 - '@' +C101 DB 66 ;01100110 .**..**. +C102 DB 6E ;01101110 .**.***. +C103 DB 6A ;01101010 .**.*.*. +C104 DB 6E ;01101110 .**.***. +C105 DB 60 ;01100000 .**..... +C106 DB 3C ;00111100 ..****.. +C107 DB 00 ;00000000 ........ + +C108 DB 3C ;00111100 ..****.. &41 65 - 'A' +C109 DB 66 ;01100110 .**..**. +C10A DB 66 ;01100110 .**..**. +C10B DB 7E ;01111110 .******. +C10C DB 66 ;01100110 .**..**. +C10D DB 66 ;01100110 .**..**. +C10E DB 66 ;01100110 .**..**. +C10F DB 00 ;00000000 ........ + +C110 DB 7C ;01111100 .*****.. &42 66 - 'B' +C111 DB 66 ;01100110 .**..**. +C112 DB 66 ;01100110 .**..**. +C113 DB 7C ;01111100 .*****.. +C114 DB 66 ;01100110 .**..**. +C115 DB 66 ;01100110 .**..**. +C116 DB 7C ;01111100 .*****.. +C117 DB 00 ;00000000 ........ + +C118 DB 3C ;00111100 ..****.. &43 67 - 'C' +C119 DB 66 ;01100110 .**..**. +C11A DB 60 ;01100000 .**..... +C11B DB 60 ;01100000 .**..... +C11C DB 60 ;01100000 .**..... +C11D DB 66 ;01100110 .**..**. +C11E DB 3C ;00111100 ..****.. +C11F DB 00 ;00000000 ........ + +C120 DB 78 ;01111000 .****... &44 68 - 'D' +C121 DB 6C ;01101100 .**.**.. +C122 DB 66 ;01100110 .**..**. +C123 DB 66 ;01100110 .**..**. +C124 DB 66 ;01100110 .**..**. +C125 DB 6C ;01101100 .**.**.. +C126 DB 78 ;01111000 .****... +C127 DB 00 ;00000000 ........ + +C128 DB 7E ;01111110 .******. &45 69 - 'E' +C129 DB 60 ;01100000 .**..... +C12A DB 60 ;01100000 .**..... +C12B DB 7C ;01111100 .*****.. +C12C DB 60 ;01100000 .**..... +C12D DB 60 ;01100000 .**..... +C12E DB 7E ;01111110 .******. +C12F DB 00 ;00000000 ........ + +C130 DB 7E ;01111110 .******. &46 70 - 'F' +C131 DB 60 ;01100000 .**..... +C132 DB 60 ;01100000 .**..... +C133 DB 7C ;01111100 .*****.. +C134 DB 60 ;01100000 .**..... +C135 DB 60 ;01100000 .**..... +C136 DB 60 ;01100000 .**..... +C137 DB 00 ;00000000 ........ + +C138 DB 3C ;00111100 ..****.. &47 71 - 'G' +C139 DB 66 ;01100110 .**..**. +C13A DB 60 ;01100000 .**..... +C13B DB 6E ;01101110 .**.***. +C13C DB 66 ;01100110 .**..**. +C13D DB 66 ;01100110 .**..**. +C13E DB 3C ;00111100 ..****.. +C13F DB 00 ;00000000 ........ + +C140 DB 66 ;01100110 .**..**. &48 72 - 'H' +C141 DB 66 ;01100110 .**..**. +C142 DB 66 ;01100110 .**..**. +C143 DB 7E ;01111110 .******. +C144 DB 66 ;01100110 .**..**. +C145 DB 66 ;01100110 .**..**. +C146 DB 66 ;01100110 .**..**. +C147 DB 00 ;00000000 ........ + +C148 DB 7E ;01111110 .******. &49 73 - 'I' +C149 DB 18 ;00011000 ...**... +C14A DB 18 ;00011000 ...**... +C14B DB 18 ;00011000 ...**... +C14C DB 18 ;00011000 ...**... +C14D DB 18 ;00011000 ...**... +C14E DB 7E ;01111110 .******. +C14F DB 00 ;00000000 ........ + +C150 DB 3E ;00111110 ..*****. &4A 74 - 'J' +C151 DB 0C ;00001100 ....**.. +C152 DB 0C ;00001100 ....**.. +C153 DB 0C ;00001100 ....**.. +C154 DB 0C ;00001100 ....**.. +C155 DB 6C ;01101100 .**.**.. +C156 DB 38 ;00111000 ..***... +C157 DB 00 ;00000000 ........ + +C158 DB 66 ;01100110 .**..**. &4B 75 - 'K' +C159 DB 6C ;01101100 .**.**.. +C15A DB 78 ;01111000 .****... +C15B DB 70 ;01110000 .***.... +C15C DB 78 ;01111000 .****... +C15D DB 6C ;01101100 .**.**.. +C15E DB 66 ;01100110 .**..**. +C15F DB 00 ;00000000 ........ + +C160 DB 60 ;01100000 .**..... &4C 76 - 'L' +C161 DB 60 ;01100000 .**..... +C162 DB 60 ;01100000 .**..... +C163 DB 60 ;01100000 .**..... +C164 DB 60 ;01100000 .**..... +C165 DB 60 ;01100000 .**..... +C166 DB 7E ;01111110 .******. +C167 DB 00 ;00000000 ........ + +C168 DB 63 ;01100011 .**...** &4D 77 - 'M' +C169 DB 77 ;01110111 .***.*** +C16A DB 7F ;01111111 .******* +C16B DB 6B ;01101011 .**.*.** +C16C DB 6B ;01101011 .**.*.** +C16D DB 63 ;01100011 .**...** +C16E DB 63 ;01100011 .**...** +C16F DB 00 ;00000000 ........ + +C170 DB 66 ;01100110 .**..**. &4E 78 - 'N' +C171 DB 66 ;01100110 .**..**. +C172 DB 76 ;01110110 .***.**. +C173 DB 7E ;01111110 .******. +C174 DB 6E ;01101110 .**.***. +C175 DB 66 ;01100110 .**..**. +C176 DB 66 ;01100110 .**..**. +C177 DB 00 ;00000000 ........ + +C178 DB 3C ;00111100 ..****.. &4F 79 - 'O' +C179 DB 66 ;01100110 .**..**. +C17A DB 66 ;01100110 .**..**. +C17B DB 66 ;01100110 .**..**. +C17C DB 66 ;01100110 .**..**. +C17D DB 66 ;01100110 .**..**. +C17E DB 3C ;00111100 ..****.. +C17F DB 00 ;00000000 ........ + +C180 DB 7C ;01111100 .*****.. &50 80 - 'P' +C181 DB 66 ;01100110 .**..**. +C182 DB 66 ;01100110 .**..**. +C183 DB 7C ;01111100 .*****.. +C184 DB 60 ;01100000 .**..... +C185 DB 60 ;01100000 .**..... +C186 DB 60 ;01100000 .**..... +C187 DB 00 ;00000000 ........ + +C188 DB 3C ;00111100 ..****.. &51 81 - 'Q' +C189 DB 66 ;01100110 .**..**. +C18A DB 66 ;01100110 .**..**. +C18B DB 66 ;01100110 .**..**. +C18C DB 6A ;01101010 .**.*.*. +C18D DB 6C ;01101100 .**.**.. +C18E DB 36 ;00110110 ..**.**. +C18F DB 00 ;00000000 ........ + +C190 DB 7C ;01111100 .*****.. &52 82 - 'R' +C191 DB 66 ;01100110 .**..**. +C192 DB 66 ;01100110 .**..**. +C193 DB 7C ;01111100 .*****.. +C194 DB 6C ;01101100 .**.**.. +C195 DB 66 ;01100110 .**..**. +C196 DB 66 ;01100110 .**..**. +C197 DB 00 ;00000000 ........ + +C198 DB 3C ;00111100 ..****.. &53 83 - 'S' +C199 DB 66 ;01100110 .**..**. +C19A DB 60 ;01100000 .**..... +C19B DB 3C ;00111100 ..****.. +C19C DB 06 ;00000110 .....**. +C19D DB 66 ;01100110 .**..**. +C19E DB 3C ;00111100 ..****.. +C19F DB 00 ;00000000 ........ + +C1A0 DB 7E ;01111110 .******. &54 84 - 'T' +C1A1 DB 18 ;00011000 ...**... +C1A2 DB 18 ;00011000 ...**... +C1A3 DB 18 ;00011000 ...**... +C1A4 DB 18 ;00011000 ...**... +C1A5 DB 18 ;00011000 ...**... +C1A6 DB 18 ;00011000 ...**... +C1A7 DB 00 ;00000000 ........ + +C1A8 DB 66 ;01100110 .**..**. &55 85 - 'U' +C1A9 DB 66 ;01100110 .**..**. +C1AA DB 66 ;01100110 .**..**. +C1AB DB 66 ;01100110 .**..**. +C1AC DB 66 ;01100110 .**..**. +C1AD DB 66 ;01100110 .**..**. +C1AE DB 3C ;00111100 ..****.. +C1AF DB 00 ;00000000 ........ + +C1B0 DB 66 ;01100110 .**..**. &56 86 - 'V' +C1B1 DB 66 ;01100110 .**..**. +C1B2 DB 66 ;01100110 .**..**. +C1B3 DB 66 ;01100110 .**..**. +C1B4 DB 66 ;01100110 .**..**. +C1B5 DB 3C ;00111100 ..****.. +C1B6 DB 18 ;00011000 ...**... +C1B7 DB 00 ;00000000 ........ + +C1B8 DB 63 ;01100011 .**...** &57 87 - 'W' +C1B9 DB 63 ;01100011 .**...** +C1BA DB 6B ;01101011 .**.*.** +C1BB DB 6B ;01101011 .**.*.** +C1BC DB 7F ;01111111 .******* +C1BD DB 77 ;01110111 .***.*** +C1BE DB 63 ;01100011 .**...** +C1BF DB 00 ;00000000 ........ + +C1C0 DB 66 ;01100110 .**..**. &58 88 - 'X' +C1C1 DB 66 ;01100110 .**..**. +C1C2 DB 3C ;00111100 ..****.. +C1C3 DB 18 ;00011000 ...**... +C1C4 DB 3C ;00111100 ..****.. +C1C5 DB 66 ;01100110 .**..**. +C1C6 DB 66 ;01100110 .**..**. +C1C7 DB 00 ;00000000 ........ + +C1C8 DB 66 ;01100110 .**..**. &59 89 - 'Y' +C1C9 DB 66 ;01100110 .**..**. +C1CA DB 66 ;01100110 .**..**. +C1CB DB 3C ;00111100 ..****.. +C1CC DB 18 ;00011000 ...**... +C1CD DB 18 ;00011000 ...**... +C1CE DB 18 ;00011000 ...**... +C1CF DB 00 ;00000000 ........ + +C1D0 DB 7E ;01111110 .******. &5A 90 - 'Z' +C1D1 DB 06 ;00000110 .....**. +C1D2 DB 0C ;00001100 ....**.. +C1D3 DB 18 ;00011000 ...**... +C1D4 DB 30 ;00110000 ..**.... +C1D5 DB 60 ;01100000 .**..... +C1D6 DB 7E ;01111110 .******. +C1D7 DB 00 ;00000000 ........ + +C1D8 DB 7C ;01111100 .*****.. &5B 91 - '[' +C1D9 DB 60 ;01100000 .**..... +C1DA DB 60 ;01100000 .**..... +C1DB DB 60 ;01100000 .**..... +C1DC DB 60 ;01100000 .**..... +C1DD DB 60 ;01100000 .**..... +C1DE DB 7C ;01111100 .*****.. +C1DF DB 00 ;00000000 ........ + +C1E0 DB 00 ;00000000 ........ &5C 92 - '\' +C1E1 DB 60 ;01100000 .**..... +C1E2 DB 30 ;00110000 ..**.... +C1E3 DB 18 ;00011000 ...**... +C1E4 DB 0C ;00001100 ....**.. +C1E5 DB 06 ;00000110 .....**. +C1E6 DB 00 ;00000000 ........ +C1E7 DB 00 ;00000000 ........ + +C1E8 DB 3E ;00111110 ..*****. &5D 93 - ']' +C1E9 DB 06 ;00000110 .....**. +C1EA DB 06 ;00000110 .....**. +C1EB DB 06 ;00000110 .....**. +C1EC DB 06 ;00000110 .....**. +C1ED DB 06 ;00000110 .....**. +C1EE DB 3E ;00111110 ..*****. +C1EF DB 00 ;00000000 ........ + +C1F0 DB 18 ;00011000 ...**... &5E 94 - '^' +C1F1 DB 3C ;00111100 ..****.. +C1F2 DB 66 ;01100110 .**..**. +C1F3 DB 42 ;01000010 .*....*. +C1F4 DB 00 ;00000000 ........ +C1F5 DB 00 ;00000000 ........ +C1F6 DB 00 ;00000000 ........ +C1F7 DB 00 ;00000000 ........ + +C1F8 DB 00 ;00000000 ........ &5F 95 - '_' +C1F9 DB 00 ;00000000 ........ +C1FA DB 00 ;00000000 ........ +C1FB DB 00 ;00000000 ........ +C1FC DB 00 ;00000000 ........ +C1FD DB 00 ;00000000 ........ +C1FE DB 00 ;00000000 ........ +C1FF DB FF ;11111111 ******** + +C200 DB 1C ;00011100 ...***.. &60 96 - '`' +C201 DB 36 ;00110110 ..**.**. +C202 DB 30 ;00110000 ..**.... +C203 DB 7C ;01111100 .*****.. +C204 DB 30 ;00110000 ..**.... +C205 DB 30 ;00110000 ..**.... +C206 DB 7E ;01111110 .******. +C207 DB 00 ;00000000 ........ + +C208 DB 00 ;00000000 ........ &61 97 - 'a' +C209 DB 00 ;00000000 ........ +C20A DB 3C ;00111100 ..****.. +C20B DB 06 ;00000110 .....**. +C20C DB 3E ;00111110 ..*****. +C20D DB 66 ;01100110 .**..**. +C20E DB 3E ;00111110 ..*****. +C20F DB 00 ;00000000 ........ + +C210 DB 60 ;01100000 .**..... &62 98 - 'b' +C211 DB 60 ;01100000 .**..... +C212 DB 7C ;01111100 .*****.. +C213 DB 66 ;01100110 .**..**. +C214 DB 66 ;01100110 .**..**. +C215 DB 66 ;01100110 .**..**. +C216 DB 7C ;01111100 .*****.. +C217 DB 00 ;00000000 ........ + +C218 DB 00 ;00000000 ........ &63 99 - 'c' +C219 DB 00 ;00000000 ........ +C21A DB 3C ;00111100 ..****.. +C21B DB 66 ;01100110 .**..**. +C21C DB 60 ;01100000 .**..... +C21D DB 66 ;01100110 .**..**. +C21E DB 3C ;00111100 ..****.. +C21F DB 00 ;00000000 ........ + +C220 DB 06 ;00000110 .....**. &64 100 - 'd' +C221 DB 06 ;00000110 .....**. +C222 DB 3E ;00111110 ..*****. +C223 DB 66 ;01100110 .**..**. +C224 DB 66 ;01100110 .**..**. +C225 DB 66 ;01100110 .**..**. +C226 DB 3E ;00111110 ..*****. +C227 DB 00 ;00000000 ........ + +C228 DB 00 ;00000000 ........ &65 101 - 'e' +C229 DB 00 ;00000000 ........ +C22A DB 3C ;00111100 ..****.. +C22B DB 66 ;01100110 .**..**. +C22C DB 7E ;01111110 .******. +C22D DB 60 ;01100000 .**..... +C22E DB 3C ;00111100 ..****.. +C22F DB 00 ;00000000 ........ + +C230 DB 1C ;00011100 ...***.. &66 102 - 'f' +C231 DB 30 ;00110000 ..**.... +C232 DB 30 ;00110000 ..**.... +C233 DB 7C ;01111100 .*****.. +C234 DB 30 ;00110000 ..**.... +C235 DB 30 ;00110000 ..**.... +C236 DB 30 ;00110000 ..**.... +C237 DB 00 ;00000000 ........ + +C238 DB 00 ;00000000 ........ &67 103 - 'g' +C239 DB 00 ;00000000 ........ +C23A DB 3E ;00111110 ..*****. +C23B DB 66 ;01100110 .**..**. +C23C DB 66 ;01100110 .**..**. +C23D DB 3E ;00111110 ..*****. +C23E DB 06 ;00000110 .....**. +C23F DB 3C ;00111100 ..****.. + +C240 DB 60 ;01100000 .**..... &68 104 - 'h' +C241 DB 60 ;01100000 .**..... +C242 DB 7C ;01111100 .*****.. +C243 DB 66 ;01100110 .**..**. +C244 DB 66 ;01100110 .**..**. +C245 DB 66 ;01100110 .**..**. +C246 DB 66 ;01100110 .**..**. +C247 DB 00 ;00000000 ........ + +C248 DB 18 ;00011000 ...**... &69 105 - 'i' +C249 DB 00 ;00000000 ........ +C24A DB 38 ;00111000 ..***... +C24B DB 18 ;00011000 ...**... +C24C DB 18 ;00011000 ...**... +C24D DB 18 ;00011000 ...**... +C24E DB 3C ;00111100 ..****.. +C24F DB 00 ;00000000 ........ + +C250 DB 18 ;00011000 ...**... &6A 106 - 'j' +C251 DB 00 ;00000000 ........ +C252 DB 38 ;00111000 ..***... +C253 DB 18 ;00011000 ...**... +C254 DB 18 ;00011000 ...**... +C255 DB 18 ;00011000 ...**... +C256 DB 18 ;00011000 ...**... +C257 DB 70 ;01110000 .***.... + +C258 DB 60 ;01100000 .**..... &6B 107 - 'k' +C259 DB 60 ;01100000 .**..... +C25A DB 66 ;01100110 .**..**. +C25B DB 6C ;01101100 .**.**.. +C25C DB 78 ;01111000 .****... +C25D DB 6C ;01101100 .**.**.. +C25E DB 66 ;01100110 .**..**. +C25F DB 00 ;00000000 ........ + +C260 DB 38 ;00111000 ..***... &6C 108 - 'l' +C261 DB 18 ;00011000 ...**... +C262 DB 18 ;00011000 ...**... +C263 DB 18 ;00011000 ...**... +C264 DB 18 ;00011000 ...**... +C265 DB 18 ;00011000 ...**... +C266 DB 3C ;00111100 ..****.. +C267 DB 00 ;00000000 ........ + +C268 DB 00 ;00000000 ........ &6D 109 - 'm' +C269 DB 00 ;00000000 ........ +C26A DB 36 ;00110110 ..**.**. +C26B DB 7F ;01111111 .******* +C26C DB 6B ;01101011 .**.*.** +C26D DB 6B ;01101011 .**.*.** +C26E DB 63 ;01100011 .**...** +C26F DB 00 ;00000000 ........ + +C270 DB 00 ;00000000 ........ &6E 110 - 'n' +C271 DB 00 ;00000000 ........ +C272 DB 7C ;01111100 .*****.. +C273 DB 66 ;01100110 .**..**. +C274 DB 66 ;01100110 .**..**. +C275 DB 66 ;01100110 .**..**. +C276 DB 66 ;01100110 .**..**. +C277 DB 00 ;00000000 ........ + +C278 DB 00 ;00000000 ........ &6F 111 - 'o' +C279 DB 00 ;00000000 ........ +C27A DB 3C ;00111100 ..****.. +C27B DB 66 ;01100110 .**..**. +C27C DB 66 ;01100110 .**..**. +C27D DB 66 ;01100110 .**..**. +C27E DB 3C ;00111100 ..****.. +C27F DB 00 ;00000000 ........ + +C280 DB 00 ;00000000 ........ &70 112 - 'p' +C281 DB 00 ;00000000 ........ +C282 DB 7C ;01111100 .*****.. +C283 DB 66 ;01100110 .**..**. +C284 DB 66 ;01100110 .**..**. +C285 DB 7C ;01111100 .*****.. +C286 DB 60 ;01100000 .**..... +C287 DB 60 ;01100000 .**..... + +C288 DB 00 ;00000000 ........ &71 113 - 'q' +C289 DB 00 ;00000000 ........ +C28A DB 3E ;00111110 ..*****. +C28B DB 66 ;01100110 .**..**. +C28C DB 66 ;01100110 .**..**. +C28D DB 3E ;00111110 ..*****. +C28E DB 06 ;00000110 .....**. +C28F DB 07 ;00000111 .....*** + +C290 DB 00 ;00000000 ........ &72 114 - 'r' +C291 DB 00 ;00000000 ........ +C292 DB 6C ;01101100 .**.**.. +C293 DB 76 ;01110110 .***.**. +C294 DB 60 ;01100000 .**..... +C295 DB 60 ;01100000 .**..... +C296 DB 60 ;01100000 .**..... +C297 DB 00 ;00000000 ........ + +C298 DB 00 ;00000000 ........ &73 115 - 's' +C299 DB 00 ;00000000 ........ +C29A DB 3E ;00111110 ..*****. +C29B DB 60 ;01100000 .**..... +C29C DB 3C ;00111100 ..****.. +C29D DB 06 ;00000110 .....**. +C29E DB 7C ;01111100 .*****.. +C29F DB 00 ;00000000 ........ + +C2A0 DB 30 ;00110000 ..**.... &74 116 - 't' +C2A1 DB 30 ;00110000 ..**.... +C2A2 DB 7C ;01111100 .*****.. +C2A3 DB 30 ;00110000 ..**.... +C2A4 DB 30 ;00110000 ..**.... +C2A5 DB 30 ;00110000 ..**.... +C2A6 DB 1C ;00011100 ...***.. +C2A7 DB 00 ;00000000 ........ + +C2A8 DB 00 ;00000000 ........ &75 117 - 'u' +C2A9 DB 00 ;00000000 ........ +C2AA DB 66 ;01100110 .**..**. +C2AB DB 66 ;01100110 .**..**. +C2AC DB 66 ;01100110 .**..**. +C2AD DB 66 ;01100110 .**..**. +C2AE DB 3E ;00111110 ..*****. +C2AF DB 00 ;00000000 ........ + +C2B0 DB 00 ;00000000 ........ &76 118 - 'v' +C2B1 DB 00 ;00000000 ........ +C2B2 DB 66 ;01100110 .**..**. +C2B3 DB 66 ;01100110 .**..**. +C2B4 DB 66 ;01100110 .**..**. +C2B5 DB 3C ;00111100 ..****.. +C2B6 DB 18 ;00011000 ...**... +C2B7 DB 00 ;00000000 ........ + +C2B8 DB 00 ;00000000 ........ &77 119 - 'w' +C2B9 DB 00 ;00000000 ........ +C2BA DB 63 ;01100011 .**...** +C2BB DB 6B ;01101011 .**.*.** +C2BC DB 6B ;01101011 .**.*.** +C2BD DB 7F ;01111111 .******* +C2BE DB 36 ;00110110 ..**.**. +C2BF DB 00 ;00000000 ........ + +C2C0 DB 00 ;00000000 ........ &78 120 - 'x' +C2C1 DB 00 ;00000000 ........ +C2C2 DB 66 ;01100110 .**..**. +C2C3 DB 3C ;00111100 ..****.. +C2C4 DB 18 ;00011000 ...**... +C2C5 DB 3C ;00111100 ..****.. +C2C6 DB 66 ;01100110 .**..**. +C2C7 DB 00 ;00000000 ........ + +C2C8 DB 00 ;00000000 ........ &79 121 - 'y' +C2C9 DB 00 ;00000000 ........ +C2CA DB 66 ;01100110 .**..**. +C2CB DB 66 ;01100110 .**..**. +C2CC DB 66 ;01100110 .**..**. +C2CD DB 3E ;00111110 ..*****. +C2CE DB 06 ;00000110 .....**. +C2CF DB 3C ;00111100 ..****.. + +C2D0 DB 00 ;00000000 ........ &7A 122 - 'z' +C2D1 DB 00 ;00000000 ........ +C2D2 DB 7E ;01111110 .******. +C2D3 DB 0C ;00001100 ....**.. +C2D4 DB 18 ;00011000 ...**... +C2D5 DB 30 ;00110000 ..**.... +C2D6 DB 7E ;01111110 .******. +C2D7 DB 00 ;00000000 ........ + +C2D8 DB 0C ;00001100 ....**.. &7B 123 - '{' +C2D9 DB 18 ;00011000 ...**... +C2DA DB 18 ;00011000 ...**... +C2DB DB 70 ;01110000 .***.... +C2DC DB 18 ;00011000 ...**... +C2DD DB 18 ;00011000 ...**... +C2DE DB 0C ;00001100 ....**.. +C2DF DB 00 ;00000000 ........ + +C2E0 DB 18 ;00011000 ...**... &7C 124 - '|' +C2E1 DB 18 ;00011000 ...**... +C2E2 DB 18 ;00011000 ...**... +C2E3 DB 00 ;00000000 ........ +C2E4 DB 18 ;00011000 ...**... +C2E5 DB 18 ;00011000 ...**... +C2E6 DB 18 ;00011000 ...**... +C2E7 DB 00 ;00000000 ........ + +C2E8 DB 30 ;00110000 ..**.... &7D 125 - '}' +C2E9 DB 18 ;00011000 ...**... +C2EA DB 18 ;00011000 ...**... +C2EB DB 0E ;00001110 ....***. +C2EC DB 18 ;00011000 ...**... +C2ED DB 18 ;00011000 ...**... +C2EE DB 30 ;00110000 ..**.... +C2EF DB 00 ;00000000 ........ + +C2F0 DB 31 ;00110001 ..**...* &7E 126 - '~' +C2F1 DB 6B ;01101011 .**.*.** +C2F2 DB 46 ;01000110 .*...**. +C2F3 DB 00 ;00000000 ........ +C2F4 DB 00 ;00000000 ........ +C2F5 DB 00 ;00000000 ........ +C2F6 DB 00 ;00000000 ........ +C2F7 DB 00 ;00000000 ........ + +C2F8 DB FF ;11111111 ******** &7F 127 - DEL +C2F9 DB FF ;11111111 ******** +C2FA DB FF ;11111111 ******** +C2FB DB FF ;11111111 ******** +C2FC DB FF ;11111111 ******** +C2FD DB FF ;11111111 ******** +C2FE DB FF ;11111111 ******** +C2FF DB FF ;11111111 ******** + diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/C300 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/C300 new file mode 100644 index 0000000..83abcfd --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/C300 @@ -0,0 +1 @@ +BBC Operation System OS 1.20 Startup Strings and Tables
C300 JMP &CB1D ;Initialise screen with mode in A.
C303 DB 13,'BBC Computer ',0
C312 DB '16K',7,0
C317 DB '32K',7,0
C31C DB 08,0D,0D ;Termination byte in next table
****** 16 COLOUR MODE BYTE MASK LOOK UP TABLE******
C31F DB 00 ;00000000
C320 DB 11 ;00010001
C321 DB 22 ;00100010
C322 DB 33 ;00110011
C323 DB 44 ;01000100
C324 DB 55 ;01010101
C325 DB 66 ;01100110
C326 DB 77 ;01110111
C327 DB 88 ;10001000
C328 DB 99 ;10011001
C329 DB AA ;10101010
C32A DB BB ;10111011
C32B DB CC ;11001100
C32C DB DD ;11011101
C32D DB EE ;11101110
C32E DB FF ;11111111
****** 4 COLOUR MODE BYTE MASK LOOK UP TABLE******
C32F DB 00 ;00000000
C330 DB 55 ;01010101
C331 DB AA ;10101010
C332 DB FF ;11111111
****** VDU ENTRY POINT LO LOOK UP TABLE******
C333 DB 11 ;00010001
C334 DB 3B ;00111011
C335 DB 96 ;10010110
C336 DB A1 ;10100001
C337 DB AD ;10101101
C338 DB B9 ;10111001
C339 DB 11 ;00010001
C33A DB 6F ;01101111
C33B DB C5 ;11000101
C33C DB 64 ;01100100
C33D DB F0 ;11110000
C33E DB 5B ;01011011
C33F DB 59 ;01011001
C340 DB AF ;10101111
C341 DB 8D ;10001101
C342 DB A6 ;10100110
C343 DB C0 ;11000000
C344 DB F9 ;11111001
C345 DB FD ;11111101
C346 DB 92 ;10010010
C347 DB 39 ;00111001
C348 DB 9B ;10011011
C349 DB EB ;11101011
C34A DB F1 ;11110001
C34B DB 39 ;00111001
C34C DB 8C ;10001100
C34D DB BD ;10111101
C34E DB 11 ;00010001
C34F DB FA ;11111010
C350 DB A2 ;10100010
C351 DB 79 ;01111001
C352 DB 87 ;10000111
C353 DB AC ;10101100
****** VDU ENTRY POINT HI PARAMETER LOOK UP TABLE******
; 1xxxxxxx - no parameters, address high byte
; 0aaapppp - parameter count 16-p, address high byte &C3+a
C354 DB C5 ;11000101 VDU 0 - &C511, no parameters
C355 DB 2F ;00101111 VDU 1 - &C53B, 1 parameter
C356 DB C5 ;11000101 VDU 2 - &C596, no parameters
C357 DB C5 ;11000101 VDU 3 - &C5A1, no parameters
C358 DB C5 ;11000101 VDU 4 - &C5AD, no parameters
C359 DB C5 ;11000101 VDU 5 - &C5B9, no parameters
C35A DB C5 ;11000101 VDU 6 - &C511, no parameters
C35B DB E8 ;11101000 VDU 7 - &E86F, no parameters
C35C DB C5 ;11000101 VDU 8 - &C5C5, no parameters
C35D DB C6 ;11000110 VDU 9 - &C664, no parameters
C35E DB C6 ;11000110 VDU 10 - &C6F0, no parameters
C35F DB C6 ;11000110 VDU 11 - &C65B, no parameters
C360 DB C7 ;11000111 VDU 12 - &C759, no parameters
C361 DB C7 ;11000111 VDU 13 - &C7AF, no parameters
C362 DB C5 ;11000101 VDU 14 - &C58D, no parameters
C363 DB C5 ;11000101 VDU 15 - &C5A6, no parameters
C364 DB C7 ;11000111 VDU 16 - &C7C0, no parameters
C365 DB 4F ;01001111 VDU 17 - &C7F9, 1 parameter
C366 DB 4E ;01001110 VDU 18 - &C7FD, 2 parameters
C367 DB 5B ;01011011 VDU 19 - &C892, 5 parameters
C368 DB C8 ;11001000 VDU 20 - &C839, no parameters
C369 DB C5 ;11000101 VDU 21 - &C59B, no parameters
C36A DB 5F ;01011111 VDU 22 - &C8EB, 1 parameter
C36B DB 57 ;01010111 VDU 23 - &C8F1, 9 parameters
C36C DB 78 ;01111000 VDU 24 - &CA39, 8 parameters
C36D DB 6B ;01101011 VDU 25 - &C9AC, 5 parameters
C36E DB C9 ;11001001 VDU 26 - &C9BD, no parameters
C36F DB C5 ;11000101 VDU 27 - &C511, no parameters
C370 DB 3C ;00111100 VDU 28 - &C6FA, 4 parameters
C371 DB 7C ;01111100 VDU 29 - &CAA2, 4 parameters
C372 DB C7 ;11000111 VDU 30 - &C779, no parameters
C373 DB 4E ;01001110 VDU 31 - &C787, 2 parameters
C374 DB CA ;11001010 VDU 127 - &CAAC, no parameters
****** 640 MULTIPLICATION TABLE 40COL, 80COL MODES HIBYTE, LOBYTE ******
C375 DW 0000 ; 0*640 = &0000
C377 DW 8002 ; 1*640 = &0280
C379 DW 0005 ; 2*640 = &0500
C37B DW 8007 ; 3*640 = &0780
C37D DW 000A ; 4*
C37F DW 800C ; 5*
C381 DW 000F ; 6*
C383 DW 8011 ; 7*
C385 DW 0014 ; 8*
C387 DW 8016 ; 9*
C389 DW 0019 ; 10*
C38B DW 801B ; 11*
C38D DW 001E ; 12*
C38F DW 8020 ; 13*
C391 DW 0023 ; 14*
C393 DW 8025 ; 15*
C395 DW 0028 ; 16*
C397 DW 802A ; 17*
C399 DW 002D ; 18*
C39B DW 802F ; 19*
C39D DW 0032 ; 20*
C39F DW 8034 ; 21*
C3A1 DW 0037 ; 22*
C3A3 DW 8039 ; 23*
C3A5 DW 003C ; 24*
C3A7 DW 803E ; 25*
C3A9 DW 0041 ; 26*
C3AB DW 8043 ; 27*
C3AD DW 0046 ; 28*
C3AF DW 8048 ; 29*
C3B1 DW 004B ; 30*
C3B3 DW 804D ; 31*640 = &4D80
****** *40 MULTIPLICATION TABLE TELETEXT MODE HIBYTE, LOBYTE ******
C3B5 DW 0000 ; 0*40 = &0000
C3B7 DW 2800 ; 1*40 = &0028
C3B9 DW 5000 ; 2
C3BB DW 7800 ; 3
C3BD DW A000 ; 4
C3BF DW C800 ; 5
C3C1 DW F000 ; 6
C3C3 DW 1801 ; 7
C3C5 DW 4001 ; 8
C3C7 DW 6801 ; 9
C3C9 DW 9001 ; 10
C3CB DW B801 ; 11
C3CD DW E001 ; 12
C3CF DW 0802 ; 13
C3D1 DW 3002 ; 14
C3D3 DW 5802 ; 15
C3D5 DW 8002 ; 16
C3D7 DW A802 ; 17
C3D9 DW D002 ; 18
C3DB DW F802 ; 19
C3DD DW 2003 ; 20
C3DF DW 4803 ; 21
C3E1 DW 7003 ; 22
C3E3 DW 9803 ; 23*40 = &0398
C3E5 DW C003 ; 24*40 = &03C0
****** TEXT WINDOW -BOTTOM ROW LOOK UP TABLE ******
C3E7 DB 1F ; MODE 0 - 32 ROWS
C3E8 DB 1F ; MODE 1 - 32 ROWS
C3E9 DB 1F ; MODE 2 - 32 ROWS
C3EA DB 18 ; MODE 3 - 25 ROWS
C3EB DB 1F ; MODE 4 - 32 ROWS
C3EC DB 1F ; MODE 5 - 32 ROWS
C3ED DB 18 ; MODE 6 - 25 ROWS
C3EE DB 18 ; MODE 7 - 25 ROWS
****** TEXT WINDOW -RIGHT HAND COLUMN LOOK UP TABLE ******
C3EF DB 4F ; MODE 0 - 80 COLUMNS
C3F0 DB 27 ; MODE 1 - 40 COLUMNS
C3F1 DB 13 ; MODE 2 - 20 COLUMNS
C3F2 DB 4F ; MODE 3 - 80 COLUMNS
C3F3 DB 27 ; MODE 4 - 40 COLUMNS
C3F4 DB 13 ; MODE 5 - 20 COLUMNS
C3F5 DB 27 ; MODE 6 - 40 COLUMNS
C3F6 DB 27 ; MODE 7 - 40 COLUMNS
*************************************************************************
* *
* SEVERAL OF THE FOLLOWING TABLES OVERLAP EACH OTHER *
* SOME ARE DUAL PURPOSE *
* *
*************************************************************************
************** VIDEO ULA CONTROL REGISTER SETTINGS ***********************
C3F7 DB 9C ;10011100
C3F8 DB D8 ;11011000
C3F9 DB F4 ;11110100
C3FA DB 9C ;10011100
C3FB DB 88 ;10001000
C3FC DB C4 ;11000100
C3FD DB 88 ;10001000
C3FE DB 4B ;01001011
******** NUMBER OF BYTES PER CHARACTER FOR EACH DISPLAY MODE ************
C3FF DB 08 ;00001000
C400 DB 10 ;00010000
C401 DB 20 ;00100000
C402 DB 08 ;00001000
C403 DB 08 ;00001000
C404 DB 10 ;00010000
C405 DB 08 ;00001000
C406 DB 01 ;00000001
******************* MASK TABLE FOR 2 COLOUR MODES **********************
C407 DB AA ;10101010
C408 DB 55 ;01010101
****************** MASK TABLE FOR 4 COLOUR MODES ***********************
C409 DB 88 ;10001000
C40A DB 44 ;01000100
C40B DB 22 ;00100010
C40C DB 11 ;00010001
********** MASK TABLE FOR 4 COLOUR MODES FONT FLAG MASK TABLE **********
C40D DB 80 ;10000000
C40E DB 40 ;01000000
C40F DB 20 ;00100000
C410 DB 10 ;00010000
C411 DB 08 ;00001000
C412 DB 04 ;00000100
C413 DB 02 ;00000010 - NEXT BYTE IN FOLLOWING TABLE
********* NUMBER OF TEXT COLOURS -1 FOR EACH MODE ************************
C414 DB 01 ; MODE 0 - 2 COLOURS
C415 DB 03 ; MODE 1 - 4 COLOURS
C416 DB 0F ; MODE 2 - 16 COLOURS
C417 DB 01 ; MODE 3 - 2 COLOURS
C418 DB 01 ; MODE 4 - 2 COLOURS
C419 DB 03 ; MODE 5 - 4 COLOURS
C41A DB 01 ; MODE 6 - 2 COLOURS
C41B DB 00 ; MODE 7 - 1 'COLOUR'
************** GCOL PLOT OPTIONS PROCESSING LOOK UP TABLE ***************
C41C DB FF ;11111111
C41D DB 00 ;00000000
C41E DB 00 ;00000000
C41F DB FF ;11111111
C420 DB FF ;11111111
C421 DB FF ;11111111
C422 DB FF ;11111111
C423 DB 00 ;00000000
********** 2 COLOUR MODES PARAMETER LOOK UP TABLE WITHIN TABLE **********
C424 DB 00 ;00000000
C425 DB FF ;11111111
*************** 4 COLOUR MODES PARAMETER LOOK UP TABLE ******************
C426 DB 00 ;00000000
C427 DB 0F ;00001111
C428 DB F0 ;11110000
C429 DB FF ;11111111
***************16 COLOUR MODES PARAMETER LOOK UP TABLE ******************
C42A DB 00 ;00000000
C42B DB 03 ;00000011
C42C DB 0C ;00001100
C42D DB 0F ;00001111
C42E DB 30 ;00110000
C42F DB 33 ;00110011
C430 DB 3C ;00111100
C431 DB 3F ;00111111
C432 DB C0 ;11000000
C433 DB C3 ;11000011
C434 DB CC ;11001100
C435 DB CF ;11001111
C436 DB F0 ;11110000
C437 DB F3 ;11110011
C438 DB FC ;11111100
C439 DB FF ;11111111
********** DISPLAY MODE PIXELS/BYTE-1 LOOK UP TABLE *********************
C43A DB 07 ; MODE 0 - 8 PIXELS/BYTE
C43B DB 03 ; MODE 1 - 4 PIXELS/BYTE
C43C DB 01 ; MODE 2 - 2 PIXELS/BYTE
C43D DB 00 ; MODE 3 - 1 PIXEL/BYTE (NON-GRAPHICS)
C43E DB 07 ; MODE 4 - 8 PIXELS/BYTE
C43F DB 03 ; MODE 5 - 4 PIXELS/BYTE
********* SCREEN DISPLAY MEMORY INDEX LOOK UP TABLE OVERLAPS ************
C440 DB 00 ; MODE 6 - 1 PIXEL/BYTE // MODE 0 - TYPE 0
***** SOUND PITCH OFFSET BY CHANNEL LOOK UP TABLE WITHIN TABLE **********
C441 DB 00 ; MODE 7 - 1 PIXEL/BYTE // MODE 1 - TYPE 0 // CHANNEL 0
C442 DB 00 ; MODE 2 - TYPE 0 // CHANNEL 1
C443 DB 01 ; MODE 3 - TYPE 1 // CHANNEL 2
C444 DB 02 ; MODE 4 - TYPE 2 // CHANNEL 3
**** REST OF DISPLAY TABLE ****
C445 DB 02 ; MODE 5 - TYPE 2
C446 DB 03 ; MODE 6 - TYPE 3
C447 DB 04 ; MODE 7 - TYPE 4
***************** VDU SECTION CONTROL NUMBERS ***************************
C447 DB 04 ; MODE 7 - TYPE 4
C448 DB 00 ;00000000
C449 DB 06 ;00000110
C44A DB 02 ;00000010
*********** CRTC SET UP PARAMETERS TABLE 1 WITHIN TABLE ******************
C44B DB 0D ;00001101
C44C DB 05 ;00000101
C44D DB 0D ;00001101
C44E DB 05 ;00000101
*********** CRTC SET UP PARAMETERS TABLE 2 WITHIN TABLE *****************
C44F DB 04 ;00000100
C450 DB 04 ;00000100
C451 DB 0C ;00001100
C452 DB 0C ;00001100
C453 DB 04 ;00000100
**** REST OF VDU SECTION CONTROL NUMBERS ****
C454 DB 02 ;00000010
C455 DB 32 ;00110010
C456 DB 7A ;01111010
C457 DB 92 ;10010010
C458 DB E6 ;11100110
************** MSB OF MEMORY OCCUPIED BY SCREEN BUFFER *****************
C459 DB 50 ; Type 0: &5000 - 20k
C45A DB 40 ; Type 1: &4000 - 16k
C45B DB 28 ; Type 2: &2800 - 10k
C45C DB 20 ; Type 3: &2000 - 8k
C45D DB 04 ; Type 4: &0400 - 1k
************ MSB OF FIRST LOCATION OCCUPIED BY SCREEN BUFFER ************
C45E DB 30 ; Type 0: &3000
C45F DB 40 ; Type 1: &4000
C460 DB 58 ; Type 2: &5800
C461 DB 60 ; Type 3: &6000
C462 DB 7C ; Type 4: &7C00
***************** NUMBER OF BYTES PER ROW *******************************
C463 DB 28 ;00101000
C464 DB 40 ;01000000
C465 DB 80 ;10000000
******** ROW MULTIPLIACTION TABLE POINTER TO LOOK UP TABLE **************
C466 DB B5 ;10110101
C467 DB 75 ;01110101
C468 DB 75 ;01110101
********** CRTC CURSOR END REGISTER SETTING LOOK UP TABLE ***************
C469 DB 0B ;00001011
C46A DB 17 ;00010111
C46B DB 23 ;00100011
C46C DB 2F ;00101111
C46D DB 3B ;00111011
************* 6845 REGISTERS 0-11 FOR MODES 0-2 *************************
C46E DB 7F ;01111111
C46F DB 50 ;01010000
C470 DB 62 ;01100010
C471 DB 28 ;00101000
C472 DB 26 ;00100110
C473 DB 00 ;00000000
C474 DB 20 ;00100000
C475 DB 22 ;00100010
C476 DB 01 ;00000001
C477 DB 07 ;00000111
C478 DB 67 ;01100111
C479 DB 08 ;00001000
************* 6845 REGISTERS 0-11 FOR MODE 3 ****************************
C47A DB 7F ;01111111
C47B DB 50 ;01010000
C47C DB 62 ;01100010
C47D DB 28 ;00101000
C47E DB 1E ;00011110
C47F DB 02 ;00000010
C480 DB 19 ;00011001
C481 DB 1B ;00011011
C482 DB 01 ;00000001
C483 DB 09 ;00001001
C484 DB 67 ;01100111
C485 DB 09 ;00001001
************ 6845 REGISTERS 0-11 FOR MODES 4-5 **************************
C486 DB 3F ;00111111
C487 DB 28 ;00101000
C488 DB 31 ;00110001
C489 DB 24 ;00100100
C48A DB 26 ;00100110
C48B DB 00 ;00000000
C48C DB 20 ;00100000
C48D DB 22 ;00100010
C48E DB 01 ;00000001
C48F DB 07 ;00000111
C490 DB 67 ;01100111
C491 DB 08 ;00001000
********** 6845 REGISTERS 0-11 FOR MODE 6 *******************************
C492 DB 3F ;00111111
C493 DB 28 ;00101000
C494 DB 31 ;00110001
C495 DB 24 ;00100100
C496 DB 1E ;00011110
C497 DB 02 ;00000010
C498 DB 19 ;00011001
C499 DB 1B ;00011011
C49A DB 01 ;00000001
C49B DB 09 ;00001001
C49C DB 67 ;01100111
C49D DB 09 ;00001001
********* 6845 REGISTERS 0-11 FOR MODE 7 *****************************
C49E DB 3F ;00111111
C49F DB 28 ;00101000
C4A0 DB 33 ;00110011
C4A1 DB 24 ;00100100
C4A2 DB 1E ;00011110
C4A3 DB 02 ;00000010
C4A4 DB 19 ;00011001
C4A5 DB 1B ;00011011
C4A6 DB 93 ;10010011
C4A7 DB 12 ;00010010
C4A8 DB 72 ;01110010
C4A9 DB 13 ;00010011
************* VDU ROUTINE VECTOR ADDRESSES ******************************
C4AA DB 86 ;10000110
C4AB DB D3 ;11010011
C4AC DB 7E ;01111110
C4AD DB D3 ;11010011
************ VDU ROUTINE BRANCH VECTOR ADDRESS LO ***********************
C4AE DB 6A ;01101010
C4AF DB 74 ;01110100
C4B0 DB 42 ;01000010
C4B1 DB 4B ;01001011
************ VDU ROUTINE BRANCH VECTOR ADDRESS HI ***********************
C4B2 DB D3 ;11010011
C4B3 DB D3 ;11010011
C4B4 DB D3 ;11010011
C4B5 DB D3 ;11010011
*********** TELETEXT CHARACTER CONVERSION TABLE ************************
C4B6 DB 23 ; '#' -> '_'
C4B7 DB 5F ; '_' -> '`'
C4B8 DB 60 ; '`' -> '#'
C4B9 DB 23 ; '#'
*********** SOFT CHARACTER RAM ALLOCATION *****************************
C4BA DB 04 ; &20-&3F - OSHWM+&0400
C4BB DB 05 ; &40-&5F - OSHWM+&0500
C4BC DB 06 ; &60-&7F - OSHWM+&0600
C4BD DB 00 ; &80-&9F - OSHWM+&0000
C4BE DB 01 ; &A0-&BF - OSHWM+&0100
C4BF DB 02 ; &C0-&DF - OSHWM+&0200
*************************************************************************
* *
* VDU FUNCTIONS ADDRESSES *
* *
*************************************************************************
; VDU Address Parameters function
; 0 &C511 0 does nothing
; 1 &C53B 1 next character to printer only
; 2 &C596 0 enable printer
; 3 &C5A1 0 disable printer
; 4 &C5AD 0 select text cursor
; 5 &C5B9 0 select graphics cursor
; 6 &C511 0 enable display
; 7 &E86F 0 bell
; 8 &C5C5 0 cursor left
; 9 &C664 0 cursor right
; 10 &C6F0 0 cursor down
; 11 &C65B 0 cursor up
; 12 &C759 0 clear text window
; 13 &C7AF 0 newline
; 14 &C58D 0 select paged mode
; 15 &C5A6 0 cancel paged mode
; 16 &C7C0 0 clear graphics screen
; 17 &C7F9 1 define text colour
; 18 &C7FD 2 define graphics colour
; 19 &C892 5 define logical colour
; 20 &C839 0 restore default colours
; 21 &C59B 0 disable display
; 22 &C8EB 1 select screen MODE
; 23 &C8F1 9 define character
; 24 &CA39 8 define graphics window
; 25 &C98C 5 PLOT
; 26 &C9BD 0 set default windows
; 27 &C511 0 ESCAPE (does nothing)
; 28 &C6FA 4 define text window
; 29 &CAA2 4 define graphics origin
; 30 &C779 0 home cursor
; 31 &C787 2 position text cursor (TAB)
;127 &CAAC 0 delete
*************************************************************************
* *
* VDU Variables *
* *
*************************************************************************
;D0 VDU status
;Bit 0 printer output enabled
; 1 scrolling disabled
; 2 paged scrolling enabled
; 3 software scrolling selected
; 4 not used
; 5 printing at graphics cursor enabled
; 6 cursor editing mode enabled
; 7 screen disabled
;D1 byte mask for current graphics point
;D2/3 text colour bytes to be ORed and EORed into memory
;D4/5 graphics colour bytes to be ORed and EORed into memory
;D6/7 address of top line of current graphics cell
;D8/9 address of top scan line of current text character
;DA/F temporary workspace
;E0/1 CRTC row multiplication table pointer
;246 Character definition explosion switch
;248 current video ULA control regiter setting
;249 current pallette setting
;251 flash counter
;252 mark-space count
;253 space period count
;256 EXEC file handle
;257 SPOOL file handle
;260 Econet OSWRCH interception flag
;267 bit 7 set ignore start up message
;268 length of key string
;269 print line counter
;26A number of items in VDU queque
;26B TAB key value
;26C ESCAPE character
;27D cursor editing status
;28F start up options (Keyboard links)
bits 0-2 default screen Mode
3 reverse SHIFT/BREAK
4-5 disc timing parameters
;290 screen display vertical adjustment
;291 interlace toggle flag
;300/1 graphics window left
;302/3 graphics window bottom
;304/5 graphics window right
;306/7 graphics window top
;308 text window left
;309 text window bottom
;30A text window right
;30B text window top
;30C/D graphics origin, horizontal (external values)
;30E/F graphics origin, vertical (external values)
;310/1 current graphics cursor, horizontal (external values)
;312/3 current graphics cursor, vertical (external values)
;314/5 last graphics cursor, horizontal (external values)
;316/7 last graphics cursor, vertical (external values)
;318 text column
;319 text line
;31A graphics scan line expressed as line of character
;31B-323 VDU parameters, last parameter in &323
;324/5 current graphics cursor, horizontal (internal values)
;316/7 current graphics cursor, vertical (internal values)
;328-349 general workspace
;34A/B text cursor address to CRT controller
;34C/D width of text window in bytes
;34E hi byte of address of screen RAM start
;34F bytes per character
;350/1 address of window area start
;352/3 bytes per character row
;354 high byte of screen RAM size
;355 Mode
;356 memory map type
;357/35A current colours
;35B/C graphics plot mode
;35D/E jump vector
;35F last setting of CRT controller Cursor start register
;360 number of logical colours less 1
;361 pixels per byte (0 in text only modes)
;362/3 colour masks
;364/5 X/Y for text input cursor
;366 output cursor character for MODE 7
;367 Font flag
;368/E font location bytes
;36F-37E Colour palette
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/C4C0 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/C4C0 new file mode 100644 index 0000000..308e246 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/C4C0 @@ -0,0 +1 @@ +BBC Operation System OS 1.20 VDU Main Routines
**************************************************************************
**************************************************************************
** **
** OSWRCH MAIN ROUTINE entry from E0C5 **
** **
** output a byte via the VDU stream **
** **
**************************************************************************
**************************************************************************
;This routine takes up over 40% of the operating system ROM
;entry points are variable, as are the results achieved.
;tracing any particular path is relatively easy but generalising for
;commenting is not. For clarity comments will not be as detailed as
;for later parts of the Operating system.
C4C0 LDX &026A ;get number of items in VDU queue
C4C3 BNE &C512 ;if parameters needed then C512
C4C5 BIT &D0 ;else check status byte
C4C7 BVC &C4D8 ;if cursor editing enabled two cursors exist
C4C9 JSR &C568 ;swap values
C4CC JSR &CD6A ;then set up write cursor
C4CF BMI &C4D8 ;if display disabled C4D8
C4D1 CMP #&0D ;else if character in A=RETURN teminate edit
C4D3 BNE &C4D8 ;else C4D8
C4D5 JSR &D918 ;terminate edit
C4D8 CMP #&7F ;is character DELETE ?
C4DA BEQ &C4ED ;if so C4ED
C4DC CMP #&20 ;is it less than space? (i.e. VDU control code)
C4DE BCC &C4EF ;if so C4EF
C4E0 BIT &D0 ;else check VDU byte ahain
C4E2 BMI &C4EA ;if screen disabled C4EA
C4E4 JSR &CFB7 ;else display a character
C4E7 JSR &C664 ;and cursor right
C4EA JMP &C55E ;
********* read link addresses and number of parameters *****************
C4ED LDA #&20 ;to replace delete character
********* read link addresses and number of parameters *****************
C4EF TAY ;Y=A
C4F0 LDA &C333,Y ;get lo byte of link address
C4F3 STA &035D ;store it in jump vector
C4F6 LDA &C354,Y ;get hi byte
C4F9 BMI &C545 ;if negative (as it will be if a direct address)
;there are no parameters needed
;so C545
C4FB TAX ;else X=A
C4FC ORA #&F0 ;set up negated parameter count
C4FE STA &026A ;store it as number of items in VDU queue
C501 TXA ;get back A
C502 LSR ;A=A/16
C503 LSR ;
C504 LSR ;
C505 LSR ;
C506 CLC ;clear carry
C507 ADC #&C3 ;add &C3 to get hi byte of link address
C509 STA &035E ;
C50C BIT &D0 ;check if cursor editing enabled
C50E BVS &C52F ;if so re-exchange pointers
C510 CLC ;clear carry
C511 RTS ;and exit
;return with carry clear indicates that printer action not required.
;
********** parameters are outstanding ***********************************
X=&26A = 2 complement of number of parameters X=&FF for 1, FE for 2 etc.
C512 STA &0224,X ;store parameter in queue
C515 INX ;increment X
C516 STX &026A ;store it as VDU queue
C519 BNE &C532 ;if not 0 C532 as more parameters are needed
C51B BIT &D0 ;get VDU status byte
C51D BMI &C534 ;if screen disabled C534
C51F BVS &C526 ;else if cursor editing C526
C521 JSR &CCF5 ;execute required function
C524 CLC ;clear carry
C525 RTS ;and exit
;
C526 JSR &C568 ;swap values of cursors
C529 JSR &CD6A ;set up write cursor
C52C JSR &CCF5 ;execute required function
C52F JSR &C565 ;re-exchange pointers
C532 CLC ;carry clear
C533 RTS ;exit
*************************************************************************
* *
* VDU 1 - SEND NEXT CHARACTER TO PRINTER *
* *
* 1 parameter required *
* *
*************************************************************************
;
C534 LDY &035E ;if upper byte of link address not &C5
C537 CPY #&C5 ;printer is not interested
C539 BNE &C532 ;so C532
C53B TAX ;else X=A
C53C LDA &D0 ;A=VDU status byte
C53E LSR ;get bit 0 into carry
C53F BCC &C511 ;if printer not enabled exit
C541 TXA ;restore A
C542 JMP &E11E ;else send byte in A (next byte) to printer
*********** if explicit link address found, no parameters ***************
C545 STA &035E ;upper byte of link address
C548 TYA ;restore A
C549 CMP #&08 ;is it 7 or less?
C54B BCC &C553 ;if so C553
C54D EOR #&FF ;invert it
C54F CMP #&F2 ;c is set if A >&0D
C551 EOR #&FF ;re invert
C553 BIT &D0 ;VDU status byte
C555 BMI &C580 ;if display disabled C580
C557 PHP ;push processor flags
C558 JSR &CCF5 ;execute required function
C55B PLP ;get back flags
C55C BCC &C561 ;if carry clear (from C54B/F)
**************** main exit routine **************************************
C55E LDA &D0 ;VDU status byte
C560 LSR ;Carry is set if printer is enabled
C561 BIT &D0 ;VDU status byte
C563 BVC &C511 ;if no cursor editing C511 to exit
***************** cursor editing routines *******************************
C565 JSR &CD7A ;restore normal write cursor
C568 PHP ;save flags and
C569 PHA ;A
C56A LDX #&18 ;X=&18
C56C LDY #&64 ;Y=&64
C56E JSR &CDDE ;exchange &300/1+X with &300/1+Y
C571 JSR &CF06 ;set up display address
C574 JSR &CA02 ;set cursor position
C577 LDA &D0 ;VDU status byte
C579 EOR #&02 ;invert bit 1 to allow or bar scrolling
C57B STA &D0 ;VDU status byte
C57D PLA ;restore flags and A
C57E PLP ;
C57F RTS ;and exit
;
C580 EOR #&06 ;if A<>6
C582 BNE &C58C ;return via C58C
C584 LDA #&7F ;A=&7F
C586 BCC &C5A8 ;and goto C5A8 ALWAYS!!
******************* check text cursor in use ***************************
C588 LDA &D0 ;VDU status byte
C58A AND #&20 ;set A from bit 5 of status byte
C58C RTS ;and exit
A=0 if text cursor, &20 if graphics
*************************************************************************
* *
* VDU 14 - SET PAGED MODE *
* *
*************************************************************************
;
C58D LDY #&00 ;Y=0
C58F STY &0269 ;paged mode counter
C592 LDA #&04 ;A=04
C594 BNE &C59D ;jump to C59D
*************************************************************************
* *
* VDU 2 - PRINTER ON (START PRINT JOB) *
* *
*************************************************************************
C596 JSR &E1A2 ;select printer buffer and output character
C599 LDA #&94 ;A=&94
;when inverted at C59B this becomes =&01
*************************************************************************
* *
* VDU 21 - DISABLE DISPLAY *
* *
*************************************************************************
C59B EOR #&95 ;if A=&15 A now =&80: if A=&94 A now =1
C59D ORA &D0 ;VDU status byte set bit 0 or bit 7
C59F BNE &C5AA ;branch forward to store
*************************************************************************
* *
* VDU 3 - PRINTER OFF (END PRINT JOB) *
* *
*************************************************************************
C5A1 JSR &E1A2 ;select printer buffer and output character
C5A4 LDA #&0A ;A=10 to clear status bits below...
*************************************************************************
* *
* VDU 15 - PAGED MODE OFF *
* *
*************************************************************************
; A=&F or &A
C5A6 EOR #&F4 ;convert to &FB or &FE
C5A8 AND &D0 ;VDU status byte clear bit 0 or bit 2 of status
C5AA STA &D0 ;VDU status byte
C5AC RTS ;exit
*************************************************************************
* *
* VDU 4 - OUTPUT AT TEXT CURSOR *
* *
*************************************************************************
;
C5AD LDA &0361 ;pixels per byte
C5B0 BEQ &C5AC ;if no graphics in current mode C5AC
C5B2 JSR &C951 ;set CRT controller for text cursor
C5B5 LDA #&DF ;this to clear bit 5 of status byte
C5B7 BNE &C5A8 ;via C5A8 exit
*************************************************************************
* *
* VDU 5 - OUTPUT AT GRAPHICS CURSOR *
* *
*************************************************************************
C5B9 LDA &0361 ;pixels per byte
C5BC BEQ &C5AC ;if none this is text mode so exit
C5BE LDA #&20 ;set up graphics cursor
C5C0 JSR &C954 ;via C954
C5C3 BNE &C59D ;set bit 5 via exit C59D
*************************************************************************
* *
* VDU 8 - CURSOR LEFT *
* *
*************************************************************************
C5C5 JSR &C588 ;A=0 if text cursor A=&20 if graphics cursor
C5C8 BNE &C61F ;move cursor left 8 pixels if graphics
C5CA DEC &0318 ;else decrement text column
C5CD LDX &0318 ;store new text column
C5D0 CPX &0308 ;if it is less than text window left
C5D3 BMI &C5EE ;do wraparound cursor to rt of screen 1 line up
C5D5 LDA &034A ;text cursor 6845 address
C5D8 SEC ;subtract
C5D9 SBC &034F ;bytes per character
C5DC TAX ;put in X
C5DD LDA &034B ;get text cursor 6845 address
C5E0 SBC #&00 ;subtract 0
C5E2 CMP &034E ;compare with hi byte of screen RAM address
C5E5 BCS &C5EA ;if = or greater
C5E7 ADC &0354 ;add screen RAM size hi byte to wrap around
C5EA TAY ;Y=A
C5EB JMP &C9F6 ;Y hi and X lo byte of cursor position
***************** execute wraparound left-up*****************************
C5EE LDA &030A ;text window right
C5F1 STA &0318 ;text column
*************** cursor up ***********************************************
C5F4 DEC &0269 ;paged mode counter
C5F7 BPL &C5FC ;if still greater than 0 skip next instruction
C5F9 INC &0269 ;paged mode counter to restore X=0
C5FC LDX &0319 ;current text line
C5FF CPX &030B ;top of text window
C602 BEQ &C60A ;if its at top of window C60A
C604 DEC &0319 ;else decrement current text line
C607 JMP &C6AF ;and carry on moving cursor
******** cursor at top of window ****************************************
C60A CLC ;clear carry
C60B JSR &CD3F ;check for window violatations
C60E LDA #&08 ;A=8 to check for software scrolling
C610 BIT &D0 ;compare against VDU status byte
C612 BNE &C619 ;if not enabled C619
C614 JSR &C994 ;set screen start register and adjust RAM
C617 BNE &C61C ;jump C61C
C619 JSR &CDA4 ;soft scroll 1 line
C61C JMP &C6AC ;and exit
**********cursor left and down with graphics cursor in use **************
C61F LDX #&00 ;X=0 to select horizontal parameters
********** cursor down with graphics in use *****************************
;X=2 for vertical or 0 for horizontal
C621 STX &DB ;store X
C623 JSR &D10D ;check for window violations
C626 LDX &DB ;restore X
C628 SEC ;set carry
C629 LDA &0324,X ;current graphics cursor X>1=vertical
C62C SBC #&08 ;subtract 8 to move back 1 character
C62E STA &0324,X ;store in current graphics cursor X>1=verticaal
C631 BCS &C636 ;if carry set skip next
C633 DEC &0325,X ;current graphics cursor hi -1
C636 LDA &DA ;&DA=0 if no violation else 1 if vert violation
;2 if horizontal violation
C638 BNE &C658 ;if violation C658
C63A JSR &D10D ;check for window violations
C63D BEQ &C658 ;if none C658
C63F LDX &DB ;else get back X
C641 LDA &0304,X ;graphics window rt X=0 top X=2
C644 CPX #&01 ;is X=0
C646 BCS &C64A ;if not C64A
C648 SBC #&06 ;else subtract 7
C64A STA &0324,X ;current graphics cursor X>1=vertical
C64D LDA &0305,X ;graphics window hi rt X=0 top X=2
C650 SBC #&00 ;subtract carry
C652 STA &0325,X ;current graphics cursor X<2=horizontal else vertical
C655 TXA ;A=X
C656 BEQ &C660 ;cursor up
C658 JMP &D1B8 ;set up external coordinates for graphics
*************************************************************************
* *
* VDU 11 - CURSOR UP *
* *
*************************************************************************
C65B JSR &C588 ;A=0 if text cursor A=&20 if graphics cursor
C65E BEQ &C5F4 ;if text cursor then C5F4
C660 LDX #&02 ;else X=2
C662 BNE &C6B6 ;goto C6B6
*************************************************************************
* *
* VDU 9 - CURSOR RIGHT *
* *
*************************************************************************
C664 LDA &D0 ;VDU status byte
C666 AND #&20 ;check bit 5
C668 BNE &C6B4 ;if set then graphics cursor in use so C6B4
C66A LDX &0318 ;text column
C66D CPX &030A ;text window right
C670 BCS &C684 ;if X exceeds window right then C684
C672 INC &0318 ;text column
C675 LDA &034A ;text cursor 6845 address
C678 ADC &034F ;add bytes per character
C67B TAX ;X=A
C67C LDA &034B ;text cursor 6845 address
C67F ADC #&00 ;add carry if set
C681 JMP &C9F6 ;use X and Y to set new cursor address
********: text cursor down and right *************************************
C684 LDA &0308 ;text window left
C687 STA &0318 ;text column
********: text cursor down *************************************
C68A CLC ;clear carry
C68B JSR &CAE3 ;check bottom margin, X=line count
C68E LDX &0319 ;current text line
C691 CPX &0309 ;bottom margin
C694 BCS &C69B ;if X=>current bottom margin C69B
C696 INC &0319 ;else increment current text line
C699 BCC &C6AF ;
C69B JSR &CD3F ;check for window violations
C69E LDA #&08 ;check bit 3
C6A0 BIT &D0 ;VDU status byte
C6A2 BNE &C6A9 ;if software scrolling enabled C6A9
C6A4 JSR &C9A4 ;perform hardware scroll
C6A7 BNE &C6AC ;
C6A9 JSR &CDFF ;execute upward scroll
C6AC JSR &CEAC ;clear a line
C6AF JSR &CF06 ;set up display address
C6B2 BCC &C732 ;
*********** graphic cursor right ****************************************
C6B4 LDX #&00 ;
************** graphic cursor up (X=2) **********************************
C6B6 STX &DB ;store X
C6B8 JSR &D10D ;check for window violations
C6BB LDX &DB ;get back X
C6BD CLC ;clear carry
C6BE LDA &0324,X ;current graphics cursor X>1=vertical
C6C1 ADC #&08 ;Add 8 pixels
C6C3 STA &0324,X ;current graphics cursor X>1=vertical
C6C6 BCC &C6CB ;
C6C8 INC &0325,X ;current graphics cursor X<2=horizontal else vertical
C6CB LDA &DA ;A=0 no window violations 1 or 2 indicates violation
C6CD BNE &C658 ;if outside window C658
C6CF JSR &D10D ;check for window violations
C6D2 BEQ &C658 ;if no violations C658
C6D4 LDX &DB ;get back X
C6D6 LDA &0300,X ;graphics window X<2 =left else bottom
C6D9 CPX #&01 ;If X=0
C6DB BCC &C6DF ;C6DF
C6DD ADC #&06 ;else add 7
C6DF STA &0324,X ;current graphics cursor X>1=vertical
C6E2 LDA &0301,X ;graphics window hi X<2 =left else bottom
C6E5 ADC #&00 ;add anny carry
C6E7 STA &0325,X ;current graphics cursor X<2=horizontal else vertical
C6EA TXA ;A=X
C6EB BEQ &C6F5 ;if X=0 C6F5 cursor down
C6ED JMP &D1B8 ;set up external coordinates for graphics
*************************************************************************
* *
* VDU 10 - CURSOR DOWN *
* *
*************************************************************************
C6F0 JSR &C588 ;A=0 if text cursor A=&20 if graphics cursor
C6F3 BEQ &C68A ;if text cursor back to C68A
C6F5 LDX #&02 ;else X=2 to indicate vertical movement
C6F7 JMP &C621 ;move graphics cursor down
*************************************************************************
* *
* VDU 28 - DEFINE TEXT WINDOW *
* *
* 4 parameters *
* *
*************************************************************************
;parameters are set up thus
;0320 P1 left margin
;0321 P2 bottom margin
;0322 P3 right margin
;0323 P4 top margin
;Note that last parameter is always in 0323
C6FA LDX &0355 ;screen mode
C6FD LDA &0321 ;get bottom margin
C700 CMP &0323 ;compare with top margin
C703 BCC &C758 ;if bottom margin exceeds top return
C705 CMP &C3E7,X ;text window bottom margin maximum
C708 BEQ &C70C ;if equal then its OK
C70A BCS &C758 ;else exit
C70C LDA &0322 ;get right margin
C70F TAY ;put it in Y
C710 CMP C3EF,X ;text window right hand margin maximum
C713 BEQ &C717 ;if equal then OK
C715 BCS &C758 ;if greater than maximum exit
C717 SEC ;set carry to subtract
C718 SBC &0320 ;left margin
C71B BMI &C758 ;if left greater than right exit
C71D TAY ;else A=Y (window width)
C71E JSR &CA88 ;calculate number of bytes in a line
C721 LDA #&08 ;A=8 to set bit of &D0
C723 JSR &C59D ;indicating that text window is defined
C726 LDX #&20 ;point to parameters
C728 LDY #&08 ;point to text window margins
C72A JSR &D48A ;(&300/3+Y)=(&300/3+X)
C72D JSR &CEE8 ;set up screen address
C730 BCS &C779 ;home cursor within window
C732 JMP &CA02 ;set cursor position
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/C735 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/C735 new file mode 100644 index 0000000..badc60f --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/C735 @@ -0,0 +1 @@ +*************************************************************************
* *
* OSWORD 9 - READ A PIXEL *
* =POINT(X,Y) *
* *
*************************************************************************
;on entry &EF=A=9
; &F0=X=low byte of parameter block address
; &F1=Y=high byte of parameter block address
; PARAMETER BLOCK
; 0,1=X coordinate
; 2,3=Y coordinate
;on exit, result in BLOCK+4
; =&FF if point was of screen or logical colour of point if on screen
;
C735 LDY #&03 ;Y=3 to point to hi byte of Y coordinate
C737 LDA (&F0),Y ;get it
C739 STA &0328,Y ;store it
C73C DEY ;point to next byte
C73D BPL &C737 ;transfer till Y=&FF lo byte of X coordinate in &328
C73F LDA #&28 ;
C741 JSR &D839 ;check window boundaries
C744 LDY #&04 ;Y=4
C746 BNE &C750 ;jump to C750
*************************************************************************
* *
* OSWORD 11 - READ PALLETTE *
* *
*************************************************************************
;on entry &EF=A=11
; &F0=X=low byte of parameter block address
; &F1=Y=high byte of parameter block address
; PARAMETER BLOCK
; 0=logical colour to read
;on exit, result in BLOCK
; 0=logical colour
; 1=physical colour
; 2=red colour component \
; 3=green colour component } when set using analogue colours
; 4=blue colour component /
C748 AND &0360 ;number of logical colours less 1
C74B TAX ;put it in X
C74C LDA &036F,X ;colour pallette
C74F INY ;increment Y to point to byte 1
C750 STA (&F0),Y ;store data
C752 LDA #&00 ;issue 0s
C754 CPY #&04 ;to next bytes until Y=4
C756 BNE &C74F ;
C758 RTS ;and exit
*************************************************************************
* *
* VDU 12 - CLEAR TEXT SCREEN *
* CLS *
* *
*************************************************************************
;
C759 JSR &C588 ;A=0 if text cursor A=&20 if graphics cursor
C75C BNE &C7BD ;if graphics cursor &C7BD
C75E LDA &D0 ;VDU status byte
C760 AND #&08 ;check if software scrolling (text window set)
C762 BNE &C767 ;if so C767
C764 JMP &CBC1 ;initialise screen display and home cursor
C767 LDX &030B ;top of text window
C76A STX &0319 ;current text line
C76D JSR &CEAC ;clear a line
C770 LDX &0319 ;current text line
C773 CPX &0309 ;bottom margin
C776 INX ;X=X+1
C777 BCC &C76A ;if X at compare is less than bottom margin clear next
*************************************************************************
* *
* VDU 30 - HOME CURSOR *
* *
*************************************************************************
C779 JSR &C588 ;A=0 if text cursor A=&20 if graphics cursor
C77C BEQ &C781 ;if text cursor C781
C77E JMP &CFA6 ;home graphic cursor if graphic
C781 STA &0323 ;store 0 in last two parameters
C784 STA &0322 ;
*************************************************************************
* *
* VDU 31 - POSITION TEXT CURSOR *
* TAB(X,Y) *
* *
* 2 parameters *
* *
*************************************************************************
;0322 = supplied X coordinate
;0323 = supplied Y coordinate
C787 JSR &C588 ;A=0 if text cursor A=&20 if graphics cursor
C78A BNE &C758 ;exit
C78C JSR &C7A8 ;exchange text column/line with workspace 0328/9
C78F CLC ;clear carry
C790 LDA &0322 ;get X coordinate
C793 ADC &0308 ;add to text window left
C796 STA &0318 ;store as text column
C799 LDA &0323 ;get Y coordinate
C79C CLC ;
C79D ADC &030B ;add top of text window
C7A0 STA &0319 ;current text line
C7A3 JSR &CEE8 ;set up screen address
C7A6 BCC &C732 ;set cursor position if C=0 (point on screen)
C7A8 LDX #&18 ;else point to workspace
C7AA LDY #&28 ;and line/column to restore old values
C7AC JMP &CDDE ;exchange &300/1+X with &300/1+Y
*************************************************************************
* *
* VDU 13 - CARRIAGE RETURN *
* *
*************************************************************************
C7AF JSR &C588 ;A=0 if text cursor A=&20 if graphics cursor
C7B2 BEQ &C7B7 ;if text C7B7
C7B4 JMP &CFAD ;else set graphics cursor to left hand columm
C7B7 JSR &CE6E ;set text column to left hand column
C7BA JMP &C6AF ;set up cursor and display address
C7BD JSR &CFA6 ;home graphic cursor
*************************************************************************
* *
* VDU 16 - CLEAR GRAPHICS SCREEN *
* CLG *
* *
*************************************************************************
C7C0 LDA &0361 ;pixels per byte
C7C3 BEQ &C7F8 ;if 0 current mode has no graphics so exit
C7C5 LDX &035A ;Background graphics colour
C7C8 LDY &035C ;background graphics plot mode (GCOL n)
C7CB JSR &D0B3 ;set graphics byte mask in &D4/5
C7CE LDX #&00 ;graphics window
C7D0 LDY #&28 ;workspace
C7D2 JSR &D47C ;set(300/7+Y) from (300/7+X)
C7D5 SEC ;set carry
C7D6 LDA &0306 ;graphics window top lo.
C7D9 SBC &0302 ;graphics window bottom lo
C7DC TAY ;Y=difference
C7DD INY ;increment
C7DE STY &0330 ;and store in workspace (this is line count)
C7E1 LDX #&2C ;
C7E3 LDY #&28 ;
C7E5 JSR &D6A6 ;clear line
C7E8 LDA &032E ;decrement window height in pixels
C7EB BNE &C7F0 ;
C7ED DEC &032F ;
C7F0 DEC &032E ;
C7F3 DEC &0330 ;decrement line count
C7F6 BNE &C7E1 ;if <>0 then do it again
C7F8 RTS ;exit
*************************************************************************
* *
* VDU 17 - DEFINE TEXT COLOUR *
* COLOUR n *
* *
* 1 parameter *
* *
*************************************************************************
;parameter in &0323
C7F9 LDY #&00 ;Y=0
C7FB BEQ &C7FF ;jump to C7FF
*************************************************************************
* *
* VDU 18 - DEFINE GRAPHICS COLOUR *
* GCOL k,c *
* *
* 2 parameters *
* *
*************************************************************************
;parameters in 323,322
C7FD LDY #&02 ;Y=2
C7FF LDA &0323 ;get last parameter
C802 BPL &C805 ;if +ve it's foreground colour so C805
C804 INY ;else Y=Y+1
C805 AND &0360 ;number of logical colours less 1
C808 STA &DA ;store it
C80A LDA &0360 ;number of logical colours less 1
C80D BEQ &C82B ;if none exit
C80F AND #&07 ;else limit to an available colour and clear M
C811 CLC ;clear carry
C812 ADC &DA ;Add last parameter to get pointer to table
C814 TAX ;pointer into X
C815 LDA &C423,X ;get plot options from table
C818 STA &0357,Y ; colour Y=0=text fgnd 1= text bkgnd 2=graphics fg etc
C81B CPY #&02 ;If Y>1
C81D BCS &C82C ;then its graphics so C82C else
C81F LDA &0357 ;foreground text colour
C822 EOR #&FF ;invert
C824 STA &D3 ;text colour byte to be orred or EORed into memory
C826 EOR &0358 ;background text colour
C829 STA &D2 ;text colour byte to be orred or EORed into memory
C82B RTS ;and exit
;
C82C LDA &0322 ;get first parameter
C82F STA &0359,Y ;text colour Y=0=foreground 1=background etc.
C832 RTS ;exit
;
C833 LDA #&20 ;
C835 STA &0358 ;background text colour
C838 RTS ;
*************************************************************************
* *
* VDU 20 - RESTORE DEFAULT COLOURS *
* *
*************************************************************************
;
C839 LDX #&05 ;X=5
C83B LDA #&00 ;A=0
C83D STA &0357,X ;zero all colours
C840 DEX ;
C841 BPL &C83D ;until X=&FF
C843 LDX &0360 ;number of logical colours less 1
C846 BEQ &C833 ;if none its MODE 7 so C833
C848 LDA #&FF ;A=&FF
C84A CPX #&0F ;if not mode 2 (16 colours)
C84C BNE &C850 ;goto C850
C84E LDA #&3F ;else A=&3F
C850 STA &0357 ;foreground text colour
C853 STA &0359 ;foreground graphics colour
C856 EOR #&FF ;invert A
C858 STA &D2 ;text colour byte to be orred or EORed into memory
C85A STA &D3 ;text colour byte to be orred or EORed into memory
C85C STX &031F ;set first parameter of 5
C85F CPX #&03 ;if there are 4 colours
C861 BEQ &C874 ;goto C874
C863 BCC &C885 ;if less there are 2 colours goto C885
;else there are 16 colours
C865 STX &0320 ;set second parameter
C868 JSR &C892 ;do VDU 19 etc
C86B DEC &0320 ;decrement first parameter
C86E DEC &031F ;and last parameter
C871 BPL &C868 ;
C873 RTS ;
;
********* 4 colour mode *************************************************
C874 LDX #&07 ;X=7
C876 STX &0320 ;set first parameter
C879 JSR &C892 ;and do VDU 19
C87C LSR &0320 ;
C87F DEC &031F ;
C882 BPL &C879 ;
C884 RTS ;exit
;********* 2 colour mode ************************************************
C885 LDX #&07 ;X=7
C887 JSR &C88F ;execute VDU 19
C88A LDX #&00 ;X=0
C88C STX &031F ;store it as
C88F STX &0320 ;both parameters
*************************************************************************
* *
* VDU 19 - DEFINE COLOURS *
* [COLOUR l,p] *
* [COLOUR l,r,g,b] *
* *
* 5 parameters *
* *
*************************************************************************
;&31F=first parameter logical colour
;&320=second physical colour
C892 PHP ;push processor flags
C893 SEI ;disable interrupts
C894 LDA &031F ;get first parameter and
C897 AND &0360 ;number of logical colours less 1
C89A TAX ;toi make legal X=A
C89B LDA &0320 ;A=second parameter
C89E AND #&0F ;make legal
C8A0 STA &036F,X ;colour pallette
C8A3 TAY ;Y=A
C8A4 LDA &0360 ;number of logical colours less 1
C8A7 STA &FA ;store it
C8A9 CMP #&03 ;is it 4 colour mode??
C8AB PHP ;save flags
C8AC TXA ;A=X
C8AD ROR ;rotate A into &FA
C8AE ROR &FA ;
C8B0 BCS &C8AD ;
C8B2 ASL &FA ;
C8B4 TYA ;A=Y
C8B5 ORA &FA ;
C8B7 TAX ;
C8B8 LDY #&00 ;Y=0
C8BA PLP ;check flags
C8BB PHP ;
C8BC BNE &C8CC ;if A<>3 earlier C8CC
C8BE AND #&60 ;else A=&60 to test bits 5 and 6
C8C0 BEQ &C8CB ;if not set C8CB
C8C2 CMP #&60 ;else if both set
C8C4 BEQ &C8CB ;C8CB
C8C6 TXA ;A=X
C8C7 EOR #&60 ;invert
C8C9 BNE &C8CC ;and if not 0 C8CC
C8CB TXA ;X=A
C8CC JSR &EA11 ;call Osbyte 155 pass data to pallette register
C8CF TYA ;
C8D0 SEC ;
C8D1 ADC &0360 ;number of logical colours less 1
C8D4 TAY ;
C8D5 TXA ;
C8D6 ADC #&10 ;
C8D8 TAX ;
C8D9 CPY #&10 ;if Y<16 do it again
C8DB BCC &C8BA ;
C8DD PLP ;pull flags twice
C8DE PLP ;
C8DF RTS ;and exit
*************************************************************************
* *
* OSWORD 12 - WRITE PALLETTE *
* *
*************************************************************************
;on entry X=&F0:Y=&F1:YX points to parameter block
;byte 0 = logical colour; byte 1 physical colour; bytes 2-4=0
C8E0 PHP ;push flags
C8E1 AND &0360 ;and with number of logical colours less 1
C8E4 TAX ;X=A
C8E5 INY ;Y=Y+1
C8E6 LDA (&F0),Y ;get phsical colour
C8E8 JMP &C89E ;do VDU19 with parameters in X and A
*************************************************************************
* *
* VDU 22 - SELECT MODE *
* MODE n *
* *
* 1 parameter *
* *
*************************************************************************
;parameter in &323
C8EB LDA &0323 ;get parameter
C8EE JMP &CB33 ;goto CB33
*************************************************************************
* *
* VDU 23 - DEFINE CHARACTERS *
* *
* 9 parameters *
* *
*************************************************************************
;parameters are:-
;31B character to define
;31C to 323 definition
C8F1 LDA &031B ;get character to define
C8F4 CMP #&20 ;is it ' '
C8F6 BCC &C93F ;if less then it is a control instruction, goto C93F
C8F8 PHA ;else save parameter
C8F9 LSR ;A=A/32
C8FA LSR ;
C8FB LSR ;
C8FC LSR ;
C8FD LSR ;
C8FE TAX ;X=A
C8FF LDA &C40D,X ;get font flag mask from table (A=&80/2^X)
C902 BIT &0367 ;font flag
C905 BNE &C927 ;and if A<>0 C927 storage area is established already
C907 ORA &0367 ;or with font flag to set bit found to be 0
C90A STA &0367 ;font flag
C90D TXA ;get back A
C90E AND #&03 ;And 3 to clear all but bits 0 and 1
C910 CLC ;clear carry
C911 ADC #&BF ;add &BF (A=&C0,&C1,&C2) to select a character page
C913 STA &DF ;store it
C915 LDA &0367,X ;get font location byte (normally &0C)
C918 STA &DD ;store it
C91A LDY #&00 ;Y=0 so (&DE) holds (&C000 -&C2FF)
C91C STY &DC ;
C91E STY &DE ;
C920 LDA (&DE),Y ;transfer page to storage area
C922 STA (&DC),Y ;
C924 DEY ;
C925 BNE &C920 ;
C927 PLA ;get back A
C928 JSR &D03E ;set up character definition pointers
C92B LDY #&07 ;Y=7
C92D LDA &031C,Y ;transfer definition parameters
C930 STA (&DE),Y ;to RAM definition
C932 DEY ;
C933 BPL &C92D ;
C935 RTS ;and exit
;
C936 PLA ;Pull A
C937 RTS ;and exit
;
************ VDU EXTENSION **********************************************
C938 LDA &031F ;A=fifth VDU parameter
C93B CLC ;clear carry
C93C JMP (&0226) ;jump via VDUV vector
********** VDU control commands *****************************************
C93F CMP #&01 ;is A=1
C941 BCC &C958 ;if less (0) then set CRT register directly
C943 BNE &C93C ;if not 1 jump to VDUV for VDU extension
********** turn cursor on/off *******************************************
C945 JSR &C588 ;A=0 if text cursor, A=&20 if graphics cursor
C948 BNE &C937 ;if graphics exit
C94A LDA #&20 ;A=&20 - preload to turn cursor off
C94C LDY &031C ;Y=second VDU parameter
C94F BEQ &C954 ;if 0, jump to C954 to turn cursor off
C951 LDA &035F ;get last setting of CRT controller register
;for cursor on
C954 LDY #&0A ;Y=10 - cursor control register number
C956 BNE &C985 ;jump to C985, Y=register, Y=value
********** set CRT controller *******************************************
C958 LDA &031D ;get third
C95B LDY &031C ;and second parameter
C95E CPY #&07 ;is Y=7
C960 BCC &C985 ;if less C985
C962 BNE &C967 ;else if >7 C967
C964 ADC &0290 ;else ADD screen vertical display adjustment
C967 CPY #&08 ;If Y<>8
C969 BNE &C972 ;C972
C96B ORA #&00 ;if bit 7 set
C96D BMI &C972 ;C972
C96F EOR &0291 ;else EOR with interlace toggle
C972 CPY #&0A ;Y=10??
C974 BNE &C985 ;if not C985
C976 STA &035F ;last setting of CRT controller register
C979 TAY ;Y=A
C97A LDA &D0 ;VDU status byte
C97C AND #&20 ;check bit 5 printing at graphics cursor??
C97E PHP ;push flags
C97F TYA ;Y=A
C980 LDY #&0A ;Y=10
C982 PLP ;pull flags
C983 BNE &C98B ;if graphics in use then C98B
C985 STY &FE00 ;else set CRTC address register
C988 STA &FE01 ;and poke new value to register Y
C98B RTS ;exit
*************************************************************************
* *
* VDU 25 - PLOT *
* PLOT k,x,y *
* *
* 5 parameters *
* *
*************************************************************************
;
C98C LDX &0361 ;pixels per byte
C98F BEQ &C938 ;if no graphics available go to VDU Extension
C991 JMP &D060 ;else enter Plot routine at D060
********** adjust screen RAM addresses **********************************
C994 LDX &0350 ;window area start address lo
C997 LDA &0351 ;window area start address hi
C99A JSR &CCF8 ;subtract bytes per character row from this
C99D BCS &C9B3 ;if no wraparound needed C9B3
C99F ADC &0354 ;screen RAM size hi byte to wrap around
C9A2 BCC &C9B3 ;
C9A4 LDX &0350 ;window area start address lo
C9A7 LDA &0351 ;window area start address hi
C9AA JSR &CAD4 ;add bytes per char. row
C9AD BPL &C9B3 ;
C9AF SEC ;wrap around i other direction
C9B0 SBC &0354 ;screen RAM size hi byte
C9B3 STA &0351 ;window area start address hi
C9B6 STX &0350 ;window area start address lo
C9B9 LDY #&0C ;Y=12
C9BB BNE &CA0E ;jump to CA0E
*************************************************************************
* *
* VDU 26 - SET DEFAULT WINDOWS *
* *
*************************************************************************
C9BD LDA #&00 ;A=0
C9BF LDX #&2C ;X=&2C
C9C1 STA &0300,X ;clear all windows
C9C4 DEX ;
C9C5 BPL &C9C1 ;until X=&FF
C9C7 LDX &0355 ;screen mode
C9CA LDY C3EF,X ;text window right hand margin maximum
C9CD STY &030A ;text window right
C9D0 JSR &CA88 ;calculate number of bytes in a line
C9D3 LDY &C3E7,X ;text window bottom margin maximum
C9D6 STY &0309 ;bottom margin
C9D9 LDY #&03 ;Y=3
C9DB STY &0323 ;set as last parameter
C9DE INY ;increment Y
C9DF STY &0321 ;set parameters
C9E2 DEC &0322 ;
C9E5 DEC &0320 ;
C9E8 JSR &CA39 ;and do VDU 24
C9EB LDA #&F7 ;
C9ED JSR &C5A8 ;clear bit 3 of &D0
C9F0 LDX &0350 ;window area start address lo
C9F3 LDA &0351 ;window area start address hi
C9F6 STX &034A ;text cursor 6845 address
C9F9 STA &034B ;text cursor 6845 address
C9FC BPL &CA02 ;set cursor position
C9FE SEC ;
C9FF SBC &0354 ;screen RAM size hi byte
**************** set cursor position ************************************
CA02 STX &D8 ;set &D8/9 from X/A
CA04 STA &D9 ;
CA06 LDX &034A ;text cursor 6845 address
CA09 LDA &034B ;text cursor 6845 address
CA0C LDY #&0E ;Y=15
CA0E PHA ;Push A
CA0F LDA &0355 ;screen mode
CA12 CMP #&07 ;is it mode 7?
CA14 PLA ;get back A
CA15 BCS &CA27 ;if mode 7 selected CA27
CA17 STX &DA ;else store X
CA19 LSR ;divide X/A by 8
CA1A ROR &DA ;
CA1C LSR ;
CA1D ROR &DA ;
CA1F LSR ;
CA20 ROR &DA ;
CA22 LDX &DA ;
CA24 JMP &CA2B ;goto CA2B
CA27 SBC #&74 ;mode 7 subtract &74
CA29 EOR #&20 ;EOR with &20
CA2B STY &FE00 ;write to CRTC address file register
CA2E STA &FE01 ;and to relevant address (register 14)
CA31 INY ;Increment Y
CA32 STY &FE00 ;write to CRTC address file register
CA35 STX &FE01 ;and to relevant address (register 15)
CA38 RTS ;and RETURN
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/CA39 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/CA39 new file mode 100644 index 0000000..576492f --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/CA39 @@ -0,0 +1 @@ +*************************************************************************
* *
* VDU 24 - DEFINE GRAPHICS WINDOW *
* *
* 8 parameters *
* *
*************************************************************************
;&31C/D Left margin
;&31E/F Bottom margin
;&320/1 Right margin
;&322/3 Top margin
CA39 JSR &CA81 ;exchange 310/3 with 328/3
CA3C LDX #&1C ;
CA3E LDY #&2C ;
CA40 JSR &D411 ;calculate width=right - left
; height = top-bottom
CA43 ORA &032D ;
CA46 BMI &CA81 ;exchange 310/3 with 328/3 and exit
CA48 LDX #&20 ;X=&20
CA4A JSR &D149 ;scale pointers to mode
CA4D LDX #&1C ;X=&1C
CA4F JSR &D149 ;scale pointers to mode
CA52 LDA &031F ;check for negative margins
CA55 ORA &031D ;
CA58 BMI &CA81 ;if found exchange 310/3 with 328/3 and exit
CA5A LDA &0323 ;
CA5D BNE &CA81 ;exchange 310/3 with 328/3 and exit
CA5F LDX &0355 ;screen mode
CA62 LDA &0321 ;right margin hi
CA65 STA &DA ;store it
CA67 LDA &0320 ;right margin lo
CA6A LSR &DA ;/2
CA6C ROR ;A=A/2
CA6D LSR &DA ;/2
CA6F BNE &CA81 ;exchange 310/3 with 328/3
CA71 ROR ;A=A/2
CA72 LSR ;A=A/2
CA73 CMP C3EF,X ;text window right hand margin maximum
CA76 BEQ &CA7A ;if equal CA7A
CA78 BPL &CA81 ;exchange 310/3 with 328/3
CA7A LDY #&00 ;Y=0
CA7C LDX #&1C ;X=&1C
CA7E JSR &D47C ;set(300/7+Y) from (300/7+X)
***************** exchange 310/3 with 328/3 *****************************
CA81 LDX #&10 ;X=10
CA83 LDY #&28 ;Y=&28
CA85 JMP &CDE6 ;exchange 300/3+Y and 300/3+X
CA88 INY ;Y=Y+1
CA89 TYA ;A=Y
CA8A LDY #&00 ;Y=0
CA8C STY &034D ;text window width hi (bytes)
CA8F STA &034C ;text window width lo (bytes)
CA92 LDA &034F ;bytes per character
CA95 LSR ;/2
CA96 BEQ &CAA1 ;if 0 exit
CA98 ASL &034C ;text window width lo (bytes)
CA9B ROL &034D ;text window width hi (bytes)
CA9E LSR ;/2
CA9F BCC &CA98 ;
CAA1 RTS ;
*************************************************************************
* *
* VDU 29 - SET GRAPHICS ORIGIN *
* *
* 4 parameters *
* *
*************************************************************************
;
CAA2 LDX #&20 ;
CAA4 LDY #&0C ;
CAA6 JSR &D48A ;(&300/3+Y)=(&300/3+X)
CAA9 JMP &D1B8 ;set up external coordinates for graphics
*************************************************************************
* *
* VDU 127 (&7F) - DELETE (entry 32) *
* *
*************************************************************************
CAAC JSR &C5C5 ;cursor left
CAAF JSR &C588 ;A=0 if text cursor A=&20 if graphics cursor
CAB2 BNE &CAC7 ;if graphics then CAC7
CAB4 LDX &0360 ;number of logical colours less 1
CAB7 BEQ &CAC2 ;if mode 7 CAC2
CAB9 STA &DE ;else store A (always 0)
CABB LDA #&C0 ;A=&C0
CABD STA &DF ;store in &DF (&DE) now points to C300 SPACE pattern
CABF JMP &CFBF ;display a space
CAC2 LDA #&20 ;A=&20
CAC4 JMP &CFDC ;and return to display a space
CAC7 LDA #&7F ;for graphics cursor
CAC9 JSR &D03E ;set up character definition pointers
CACC LDX &035A ;Background graphics colour
CACF LDY #&00 ;Y=0
CAD1 JMP &CF63 ;invert pattern data (to background colour)
***** Add number of bytes in a line to X/A ******************************
CAD4 PHA ;store A
CAD5 TXA ;A=X
CAD6 CLC ;clear carry
CAD7 ADC &0352 ;bytes per character row
CADA TAX ;X=A
CADB PLA ;get back A
CADC ADC &0353 ;bytes per character row
CADF RTS ;and return
;
********* control scrolling in paged mode *******************************
CAE0 JSR &CB14 ;zero paged mode line counter
CAE3 JSR &E9D9 ;osbyte 118 check keyboard status; set LEDs
CAE6 BCC &CAEA ;if carry clear CAEA
CAE8 BMI &CAE0 ;if M set CAE0 do it again
CAEA LDA &D0 ;VDU status byte
CAEC EOR #&04 ;invert bit 2 paged scrolling
CAEE AND #&46 ;and if 2 cursors, paged mode off, or scrolling
CAF0 BNE &CB1C ;barred then CB1C to exit
CAF2 LDA &0269 ;paged mode counter
CAF5 BMI &CB19 ;if negative then exit via CB19
CAF7 LDA &0319 ;current text line
CAFA CMP &0309 ;bottom margin
CAFD BCC &CB19 ;increment line counter and exit
CAFF LSR ;A=A/4
CB00 LSR ;
CB01 SEC ;set carry
CB02 ADC &0269 ;paged mode counter
CB05 ADC &030B ;top of text window
CB08 CMP &0309 ;bottom margin
CB0B BCC &CB19 ;increment line counter and exit
CB0D CLC ;clear carry
CB0E JSR &E9D9 ;osbyte 118 check keyboard status; set LEDs
CB11 SEC ;set carry
CB12 BPL &CB0E ;if +ve result then loop till shift pressed
**************** zero paged mode counter *******************************
CB14 LDA #&FF ;
CB16 STA &0269 ;paged mode counter
CB19 INC &0269 ;paged mode counter
CB1C RTS ;
;
*********part of intitialisation routines ******************************
CB1D PHA ;save A
CB1E LDX #&7F ;X=&7F
CB20 LDA #&00 ;A=0
CB22 STA &D0 ;VDU status byte to set default conditions
CB24 STA &02FF,X ;zero 300,37E
CB27 DEX ;with this loop
CB28 BNE &CB24 ;
CB2A JSR &CD07 ;implode character definitions
CB2D PLA ;get back A
CB2E LDX #&7F ;X=&7F
CB30 STX &0366 ;mode 7 write cursor character
CB33 BIT &028E ;available RAM pages
CB36 BMI &CB3A ;if 32k CB3A
CB38 ORA #&04 ;ensure only modes 4-7 are available
CB3A AND #&07 ;X=A and 7 ensure legal mode
CB3C TAX ;X=mode
CB3D STX &0355 ;set screen mode flag
CB40 LDA &C414,X ;no. of colours -1 in mode table
CB43 STA &0360 ;number of logical colours less 1
CB46 LDA &C3FF,X ;number of bytes /character for each mode
CB49 STA &034F ;bytes per character
CB4C LDA &C43A,X ;display mode pixels/byte table
CB4F STA &0361 ;pixels per byte
CB52 BNE &CB56 ;if <> 0 CB56
CB54 LDA #&07 ;else A=7
CB56 ASL ;A=A*2
CB57 TAY ;Y=A
CB58 LDA &C406,Y ;mask table
CB5B STA &0363 ;colour mask left
CB5E ASL ;A=A*2
CB5F BPL &CB5E ;If still +ve CB5E
CB61 STA &0362 ;colour mask right
CB64 LDY &C440,X ;screen display memory index table
CB67 STY &0356 ;memory map type
CB6A LDA &C44F,Y ;VDU section control
CB6D JSR &E9F8 ;set hardware scrolling to VIA
CB70 LDA &C44B,Y ;VDU section control
CB73 JSR &E9F8 ;set hardware scrolling to VIA
CB76 LDA &C459,Y ;Screen RAM size hi byte table
CB79 STA &0354 ;screen RAM size hi byte
CB7C LDA &C45E,Y ;screen ram address hi byte
CB7F STA &034E ;hi byte of screen RAM address
CB82 TYA ;Y=A
CB83 ADC #&02 ;Add 2
CB85 EOR #&07 ;
CB87 LSR ;/2
CB88 TAX ;X=A
CB89 LDA &C466,X ;row multiplication table pointer
CB8C STA &E0 ;store it
CB8E LDA #&C3 ;A=&C3
CB90 STA &E1 ;store it (&E0) now points to C3B5 or C375
CB92 LDA &C463,X ;get nuber of bytes per row from table
CB95 STA &0352 ;store as bytes per character row
CB98 STX &0353 ;bytes per character row
CB9B LDA #&43 ;A=&43
CB9D JSR &C5A8 ;A=A and &D0:&D0=A
CBA0 LDX &0355 ;screen mode
CBA3 LDA &C3F7,X ;get video ULA control setting
CBA6 JSR &EA00 ;set video ULA using osbyte 154
CBA9 PHP ;push flags
CBAA SEI ;set interrupts
CBAB LDX &C469,Y ;get cursor end register data from table
CBAE LDY #&0B ;Y=11
CBB0 LDA &C46E,X ;get end of 6845 registers 0-11 table
CBB3 JSR &C95E ;set register Y
CBB6 DEX ;reduce pointers
CBB7 DEY ;
CBB8 BPL &CBB0 ;and if still >0 do it again
CBBA PLP ;pull flags
CBBB JSR &C839 ;set default colours
CBBE JSR &C9BD ;set default windows
CBC1 LDX #&00 ;X=0
CBC3 LDA &034E ;hi byte of screen RAM address
CBC6 STX &0350 ;window area start address lo
CBC9 STA &0351 ;window area start address hi
CBCC JSR &C9F6 ;use X and Y to set new cursor address
CBCF LDY #&0C ;Y=12
CBD1 JSR &CA2B ;set registers 12 and 13 in CRTC
CBD4 LDA &0358 ;background text colour
CBD7 LDX &0356 ;memory map type
CBDA LDY &C454,X ;get section control number
CBDD STY &035D ;set it in jump vector lo
CBE0 LDY #&CC ;Y=&CC
CBE2 STY &035E ;upper byte of link address
CBE5 LDX #&00 ;X=0
CBE7 STX &0269 ;paged mode counter
CBEA STX &0318 ;text column
CBED STX &0319 ;current text line
CBF0 JMP (&035D) ;jump vector set up previously
*************************************************************************
* *
* OSWORD 10 - READ CHARACTER DEFINITION *
* *
*************************************************************************
;&EF=A:&F0=X:&F1=Y, on entry YX contains number of byte to be read
;(&DE) points to address
;on exit byte YX+1 to YX+8 contain definition
CBF3 JSR &D03E ;set up character definition pointers
CBF6 LDY #&00 ;Y=0
CBF8 LDA (&DE),Y ;get first byte
CBFA INY ;Y=Y+1
CBFB STA (&F0),Y ;store it in YX
CBFD CPY #&08 ;until Y=8
CBFF BNE &CBF8 ;
CC01 RTS ;then exit
;
*************************************************************************
* *
* MAIN SCREEN CLEARANCE ROUTINE *
* *
*************************************************************************
;on entry A contains background colour which is set in every byte
;of the screen
************************ Mode 0,1,2 entry point *************************
CC02 STA &3000,X ;
CC05 STA &3100,X ;
CC08 STA &3200,X ;
CC0B STA &3300,X ;
CC0E STA &3400,X ;
CC11 STA &3500,X ;
CC14 STA &3600,X ;
CC17 STA &3700,X ;
CC1A STA &3800,X ;
CC1D STA &3900,X ;
CC20 STA &3A00,X ;
CC23 STA &3B00,X ;
CC26 STA &3C00,X ;
CC29 STA &3D00,X ;
CC2C STA &3E00,X ;
CC2F STA &3F00,X ;
************************ Mode 3 entry point *****************************
CC32 STA &4000,X ;
CC35 STA &4100,X ;
CC38 STA &4200,X ;
CC3B STA &4300,X ;
CC3E STA &4400,X ;
CC41 STA &4500,X ;
CC44 STA &4600,X ;
CC47 STA &4700,X ;
CC4A STA &4800,X ;
CC4D STA &4900,X ;
CC50 STA &4A00,X ;
CC53 STA &4B00,X ;
CC56 STA &4C00,X ;
CC59 STA &4D00,X ;
CC5C STA &4E00,X ;
CC5F STA &4F00,X ;
CC62 STA &5000,X ;
CC65 STA &5100,X ;
CC68 STA &5200,X ;
CC6B STA &5300,X ;
CC6E STA &5400,X ;
CC71 STA &5500,X ;
CC74 STA &5600,X ;
CC77 STA &5700,X ;
************************ Mode 4,5 entry point ***************************
CC7A STA &5800,X ;
CC7D STA &5900,X ;
CC80 STA &5A00,X ;
CC83 STA &5B00,X ;
CC86 STA &5C00,X ;
CC89 STA &5D00,X ;
CC8C STA &5E00,X ;
CC8F STA &5F00,X ;
************************ Mode 6 entry point *****************************
CC92 STA &6000,X ;
CC95 STA &6100,X ;
CC98 STA &6200,X ;
CC9B STA &6300,X ;
CC9E STA &6400,X ;
CCA1 STA &6500,X ;
CCA4 STA &6600,X ;
CCA7 STA &6700,X ;
CCAA STA &6800,X ;
CCAD STA &6900,X ;
CCB0 STA &6A00,X ;
CCB3 STA &6B00,X ;
CCB6 STA &6C00,X ;
CCB9 STA &6D00,X ;
CCBC STA &6E00,X ;
CCBF STA &6F00,X ;
CCC2 STA &7000,X ;
CCC5 STA &7100,X ;
CCC8 STA &7200,X ;
CCCB STA &7300,X ;
CCCE STA &7400,X ;
CCD1 STA &7500,X ;
CCD4 STA &7600,X ;
CCD7 STA &7700,X ;
CCDA STA &7800,X ;
CCDD STA &7900,X ;
CCE0 STA &7A00,X ;
CCE3 STA &7B00,X ;
************************ Mode 7 entry point *****************************
CCE6 STA &7C00,X ;
CCE9 STA &7D00,X ;
CCEC STA &7E00,X ;
CCEF STA &7F00,X ;
CCF2 INX ;
CCF3 BEQ &CD65 ;exit
****************** execute required function ****************************
CCF5 JMP (&035D) ;jump vector set up previously
********* subtract bytes per line from X/A ******************************
CCF8 PHA ;Push A
CCF9 TXA ;A=X
CCFA SEC ;set carry for subtraction
CCFB SBC &0352 ;bytes per character row
CCFE TAX ;restore X
CCFF PLA ;and A
CD00 SBC &0353 ;bytes per character row
CD03 CMP &034E ;hi byte of screen RAM address
CD06 RTS ;return
*************************************************************************
* *
* OSBYTE 20 - EXPLODE CHARACTERS *
* *
*************************************************************************
;
CD07 LDA #&0F ;A=15
CD09 STA &0367 ;font flag indicating that page &0C,&C0-&C2 are
;used for user defined characters
CD0C LDA #&0C ;A=&0C
CD0E LDY #&06 ;set loop counter
CD10 STA &0368,Y ;set all font location bytes
CD13 DEY ;to page &0C to indicate only page available
CD14 BPL &CD10 ;for user character definitions
CD16 CPX #&07 ;is X= 7 or greater
CD18 BCC &CD1C ;if not CD1C
CD1A LDX #&06 ;else X=6
CD1C STX &0246 ;character definition explosion switch
CD1F LDA &0243 ;A=primary OSHWM
CD22 LDX #&00 ;X=0
CD24 CPX &0246 ;character definition explosion switch
CD27 BCS &CD34 ;
CD29 LDY &C4BA,X ;get soft character RAM allocation
CD2C STA &0368,Y ;font location bytes
CD2F ADC #&01 ;Add 1
CD31 INX ;X=X+1
CD32 BNE &CD24 ;if X<>0 then CD24
CD34 STA &0244 ;current value of page (OSHWM)
CD37 TAY ;Y=A
CD38 BEQ &CD06 ;return via CD06 (ERROR?)
CD3A LDX #&11 ;X=&11
CD3C JMP &F168 ;issue paged ROM service call &11
;font implosion/explosion warning
******** move text cursor to next line **********************************
CD3F LDA #&02 ;A=2 to check if scrolling disabled
CD41 BIT &D0 ;VDU status byte
CD43 BNE &CD47 ;if scrolling is barred CD47
CD45 BVC &CD79 ;if cursor editing mode disabled RETURN
CD47 LDA &0309 ;bottom margin
CD4A BCC &CD4F ;if carry clear on entry CD4F
CD4C LDA &030B ;else if carry set get top of text window
CD4F BVS &CD59 ;and if cursor editing enabled CD59
CD51 STA &0319 ;get current text line
CD54 PLA ;pull return link from stack
CD55 PLA ;
CD56 JMP &C6AF ;set up cursor and display address
CD59 PHP ;push flags
CD5A CMP &0365 ;Y coordinate of text input cursor
CD5D BEQ &CD78 ;if A=line count of text input cursor CD78 to exit
CD5F PLP ;get back flags
CD60 BCC &CD66 ;
CD62 DEC &0365 ;Y coordinate of text input cursor
CD65 RTS ;exit
;
CD66 INC &0365 ;Y coordinate of text input cursor
CD69 RTS ;exit
*********************** set up write cursor ********************************
CD6A PHP ;save flags
CD6B PHA ;save A
CD6C LDY &034F ;bytes per character
CD6F DEY ;Y=Y-1
CD70 BNE &CD8F ;if Y=0 Mode 7 is in use
CD72 LDA &0338 ;so get mode 7 write character cursor character &7F
CD75 STA (&D8),Y ;store it at top scan line of current character
CD77 PLA ;pull A
CD78 PLP ;pull flags
CD79 RTS ;and exit
;
CD7A PHP ;push flags
CD7B PHA ;push A
CD7C LDY &034F ;bytes per character
CD7F DEY ;
CD80 BNE &CD8F ;if not mode 7
CD82 LDA (&D8),Y ;get cursor from top scan line
CD84 STA &0338 ;store it
CD87 LDA &0366 ;mode 7 write cursor character
CD8A STA (&D8),Y ;store it at scan line
CD8C JMP &CD77 ;and exit
CD8F LDA #&FF ;A=&FF =cursor
CD91 CPY #&1F ;except in mode 2 (Y=&1F)
CD93 BNE &CD97 ;if not CD97
CD95 LDA #&3F ;load cursor byte mask
********** produce white block write cursor *****************************
CD97 STA &DA ;store it
CD99 LDA (&D8),Y ;get scan line byte
CD9B EOR &DA ;invert it
CD9D STA (&D8),Y ;store it on scan line
CD9F DEY ;decrement scan line counter
CDA0 BPL &CD99 ;do it again
CDA2 BMI &CD77 ;then jump to &CD77
CDA4 JSR &CE5B ;exchange line and column cursors with workspace copies
CDA7 LDA &0309 ;bottom margin
CDAA STA &0319 ;current text line
CDAD JSR &CF06 ;set up display address
CDB0 JSR &CCF8 ;subtract bytes per character row from this
CDB3 BCS &CDB8 ;wraparound if necessary
CDB5 ADC &0354 ;screen RAM size hi byte
CDB8 STA &DB ;store A
CDBA STX &DA ;X
CDBC STA &DC ;A again
CDBE BCS &CDC6 ;if C set there was no wraparound so CDC6
CDC0 JSR &CE73 ;copy line to new position
;using (&DA) for read
;and (&D8) for write
CDC3 JMP &CDCE ;
CDC6 JSR &CCF8 ;subtract bytes per character row from X/A
CDC9 BCC &CDC0 ;if a result is outside screen RAM CDC0
CDCB JSR &CE38 ;perform a copy
CDCE LDA &DC ;set write pointer from read pointer
CDD0 LDX &DA ;
CDD2 STA &D9 ;
CDD4 STX &D8 ;
CDD6 DEC &DE ;decrement window height
CDD8 BNE &CDB0 ;and if not zero CDB0
CDDA LDX #&28 ;point to workspace
CDDC LDY #&18 ;point to text column/line
CDDE LDA #&02 ;number of bytes to swap
CDE0 BNE &CDE8 ;exchange (328/9)+Y with (318/9)+X
CDE2 LDX #&24 ;point to graphics cursor
CDE4 LDY #&14 ;point to last graphics cursor
;A=4 to swap X and Y coordinates
*************** exchange 300/3+Y with 300/3+X ***************************
CDE6 LDA #&04 ;A =4
************** exchange (300/300+A)+Y with (300/300+A)+X *****************
CDE8 STA &DA ;store it as loop counter
CDEA LDA &0300,X ;get byte
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/CDED b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/CDED new file mode 100644 index 0000000..ef1ac9b --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/CDED @@ -0,0 +1 @@ +CDED PHA ;store it
CDEE LDA &0300,Y ;get byte pointed to by Y
CDF1 STA &0300,X ;put it in 300+X
CDF4 PLA ;get back A
CDF5 STA &0300,Y ;put it in 300+Y
CDF8 INX ;increment pointers
CDF9 INY ;
CDFA DEC &DA ;decrement loop counter
CDFC BNE &CDEA ;and if not 0 do it again
CDFE RTS ;and exit
******** execute upward scroll ******************************************
;
CDFF JSR &CE5B ;exchange line and column cursors with workspace copies
CE02 LDY &030B ;top of text window
CE05 STY &0319 ;current text line
CE08 JSR &CF06 ;set up display address
CE0B JSR &CAD4 ;add bytes per char. row
CE0E BPL &CE14 ;
CE10 SEC ;
CE11 SBC &0354 ;screen RAM size hi byte
CE14 STA &DB ;(&DA)=X/A
CE16 STX &DA ;
CE18 STA &DC ;&DC=A
CE1A BCC &CE22 ;
CE1C JSR &CE73 ;copy line to new position
;using (&DA) for read
;and (&D8) for write
CE1F JMP &CE2A ;exit
CE22 JSR &CAD4 ;add bytes per char. row
CE25 BMI &CE1C ;if outside screen RAM CE1C
CE27 JSR &CE38 ;perform a copy
CE2A LDA &DC ;
CE2C LDX &DA ;
CE2E STA &D9 ;
CE30 STX &D8 ;
CE32 DEC &DE ;decrement window height
CE34 BNE &CE0B ;CE0B if not 0
CE36 BEQ &CDDA ;exchange text column/linelse CDDA
*********** copy routines ***********************************************
CE38 LDX &034D ;text window width hi (bytes)
CE3B BEQ &CE4D ;if no more than 256 bytes to copy X=0 so CE4D
CE3D LDY #&00 ;Y=0 to set loop counter
CE3F LDA (&DA),Y ;copy 256 bytes
CE41 STA (&D8),Y ;
CE43 INY ;
CE44 BNE &CE3F ;Till Y=0 again
CE46 INC &D9 ;increment hi bytes
CE48 INC &DB ;
CE4A DEX ;decrement window width
CE4B BNE &CE3F ;if not 0 go back and do loop again
CE4D LDY &034C ;text window width lo (bytes)
CE50 BEQ &CE5A ;if Y=0 CE5A
CE52 DEY ;else Y=Y-1
CE53 LDA (&DA),Y ;copy Y bytes
CE55 STA (&D8),Y ;
CE57 TYA ;A=Y
CE58 BNE &CE52 ;if not 0 CE52
CE5A RTS ;and exit
;
CE5B JSR &CDDA ;exchange text column/line with workspace
CE5E SEC ;set carry
CE5F LDA &0309 ;bottom margin
CE62 SBC &030B ;top of text window
CE65 STA &DE ;store it
CE67 BNE &CE6E ;set text column to left hand column
CE69 PLA ;get back return address
CE6A PLA ;
CE6B JMP &CDDA ;exchange text column/line with workspace
CE6E LDA &0308 ;text window left
CE71 BPL &CEE3 ;Jump CEE3 always!
CE73 LDA &DA ;get back A
CE75 PHA ;push A
CE76 SEC ;set carry
CE77 LDA &030A ;text window right
CE7A SBC &0308 ;text window left
CE7D STA &DF ;
CE7F LDY &034F ;bytes per character to set loop counter
CE82 DEY ;copy loop
CE83 LDA (&DA),Y ;
CE85 STA (&D8),Y ;
CE87 DEY ;
CE88 BPL &CE83 ;
CE8A LDX #&02 ;X=2
CE8C CLC ;clear carry
CE8D LDA &D8,X ;
CE8F ADC &034F ;bytes per character
CE92 STA &D8,X ;
CE94 LDA &D9,X ;
CE96 ADC #&00 ;
CE98 BPL &CE9E ;if this remains in screen RAM OK
CE9A SEC ;else wrap around screen
CE9B SBC &0354 ;screen RAM size hi byte
CE9E STA &D9,X ;
CEA0 DEX ;X=X-2
CEA1 DEX ;
CEA2 BEQ &CE8C ;if X=0 adjust second set of pointers
CEA4 DEC &DF ;decrement window width
CEA6 BPL &CE7F ;and if still +ve do it all again
CEA8 PLA ;get back A
CEA9 STA &DA ;and store it
CEAB RTS ;then exit
;
*********** clear a line ************************************************
CEAC LDA &0318 ;text column
CEAF PHA ;save it
CEB0 JSR &CE6E ;set text column to left hand column
CEB3 JSR &CF06 ;set up display address
CEB6 SEC ;set carry
CEB7 LDA &030A ;text window right
CEBA SBC &0308 ;text window left
CEBD STA &DC ;as window width
CEBF LDA &0358 ;background text colour
CEC2 LDY &034F ;bytes per character
CEC5 DEY ;Y=Y-1 decrementing loop counter
CEC6 STA (&D8),Y ;store background colour at this point on screen
CEC8 BNE &CEC5 ;if Y<>0 do it again
CECA TXA ;else A=X
CECB CLC ;clear carry to add
CECC ADC &034F ;bytes per character
CECF TAX ;X=A restoring it
CED0 LDA &D9 ;get hi byte
CED2 ADC #&00 ;Add carry if any
CED4 BPL &CEDA ;if +ve CeDA
CED6 SEC ;else wrap around
CED7 SBC &0354 ;screen RAM size hi byte
CEDA STX &D8 ;restore D8/9
CEDC STA &D9 ;
CEDE DEC &DC ;decrement window width
CEE0 BPL &CEBF ;ind if not 0 do it all again
CEE2 PLA ;get back A
CEE3 STA &0318 ;restore text column
CEE6 SEC ;set carry
CEE7 RTS ;and exit
;
CEE8 LDX &0318 ;text column
CEEB CPX &0308 ;text window left
CEEE BMI &CEE6 ;if less than left margin return with carry set
CEF0 CPX &030A ;text window right
CEF3 BEQ &CEF7 ;if equal to right margin thats OK
CEF5 BPL &CEE6 ;if greater than right margin return with carry set
CEF7 LDX &0319 ;current text line
CEFA CPX &030B ;top of text window
CEFD BMI &CEE6 ;if less than top margin
CEFF CPX &0309 ;bottom margin
CF02 BEQ &CF06 ;set up display address
CF04 BPL &CEE6 ;or greater than bottom margin return with carry set
************:set up display address *************************************
;Mode 0: (0319)*640+(0318)* 8
;Mode 1: (0319)*640+(0318)*16
;Mode 2: (0319)*640+(0318)*32
;Mode 3: (0319)*640+(0318)* 8
;Mode 4: (0319)*320+(0318)* 8
;Mode 5: (0319)*320+(0318)*16
;Mode 6: (0319)*320+(0318)* 8
;Mode 7: (0319)* 40+(0318)
;this gives a displacement relative to the screen RAM start address
;which is added to the calculated number and stored in in 34A/B
;if the result is less than &8000, the top of screen RAM it is copied into X/A
;and D8/9.
;if the result is greater than &7FFF the hi byte of screen RAM size is
;subtracted to wraparound the screen. X/A, D8/9 are then set from this
CF06 LDA &0319 ;current text line
CF09 ASL ;A=A*2
CF0A TAY ;Y=A
CF0B LDA (&E0),Y ;get CRTC multiplication table pointer
CF0D STA &D9 ;&D9=A
CF0F INY ;Y=Y+1
CF10 LDA #&02 ;A=2
CF12 AND &0356 ;memory map type
CF15 PHP ;save flags
CF16 LDA (&E0),Y ;get CRTC multiplication table pointer
CF18 PLP ;pull flags
CF19 BEQ &CF1E ;
CF1B LSR &D9 ;&D9=&D9/2
CF1D ROR ;A=A/2 +(128*carry)
CF1E ADC &0350 ;window area start address lo
CF21 STA &D8 ;store it
CF23 LDA &D9 ;
CF25 ADC &0351 ;window area start address hi
CF28 TAY ;
CF29 LDA &0318 ;text column
CF2C LDX &034F ;bytes per character
CF2F DEX ;X=X-1
CF30 BEQ &CF44 ;if X=0 mode 7 CF44
CF32 CPX #&0F ;is it mode 1 or mode 5?
CF34 BEQ &CF39 ;yes CF39 with carry set
CF36 BCC &CF3A ;if its less (mode 0,3,4,6) CF3A
CF38 ASL ;A=A*16 if entered here (mode 2)
CF39 ASL ;A=A*8 if entered here
CF3A ASL ;A=A*4 if entered here
CF3B ASL ;
CF3C BCC &CF40 ;if carry clear
CF3E INY ;Y=Y+2
CF3F INY ;
CF40 ASL ;A=A*2
CF41 BCC &CF45 ;if carry clear add to &D8
CF43 INY ;if not Y=Y+1
CF44 CLC ;clear carry
CF45 ADC &D8 ;add to &D8
CF47 STA &D8 ;and store it
CF49 STA &034A ;text cursor 6845 address
CF4C TAX ;X=A
CF4D TYA ;A=Y
CF4E ADC #&00 ;Add carry if set
CF50 STA &034B ;text cursor 6845 address
CF53 BPL &CF59 ;if less than &800 goto &CF59
CF55 SEC ;else wrap around
CF56 SBC &0354 ;screen RAM size hi byte
CF59 STA &D9 ;store in high byte
CF5B CLC ;clear carry
CF5C RTS ;and exit
******** Graphics cursor display routine ********************************
CF5D LDX &0359 ;foreground graphics colour
CF60 LDY &035B ;foreground graphics plot mode (GCOL n)
CF63 JSR &D0B3 ;set graphics byte mask in &D4/5
CF66 JSR &D486 ;copy (324/7) graphics cursor to workspace (328/B)
CF69 LDY #&00 ;Y=0
CF6B STY &DC ;&DC=Y
CF6D LDY &DC ;Y=&DC
CF6F LDA (&DE),Y ;get pattern byte
CF71 BEQ &CF86 ;if A=0 CF86
CF73 STA &DD ;else &DD=A
CF75 BPL &CF7A ;and if >0 CF7A
CF77 JSR &D0E3 ;else display a pixel
CF7A INC &0324 ;current horizontal graphics cursor
CF7D BNE &CF82 ;
CF7F INC &0325 ;current horizontal graphics cursor
CF82 ASL &DD ;&DD=&DD*2
CF84 BNE &CF75 ;and if<>0 CF75
CF86 LDX #&28 ;point to workspace
CF88 LDY #&24 ;point to horizontal graphics cursor
CF8A JSR &D482 ;0300/1+Y=0300/1+X
CF8D LDY &0326 ;current vertical graphics cursor
CF90 BNE &CF95 ;
CF92 DEC &0327 ;current vertical graphics cursor
CF95 DEC &0326 ;current vertical graphics cursor
CF98 LDY &DC ;
CF9A INY ;
CF9B CPY #&08 ;if Y<8 then do loop again
CF9D BNE &CF6B ;else
CF9F LDX #&28 ;point to workspace
CFA1 LDY #&24 ;point to graphics cursor
CFA3 JMP &D48A ;(&300/3+Y)=(&300/3+X)
*********** home graphics cursor ***************************************
CFA6 LDX #&06 ;point to graphics window TOP
CFA8 LDY #&26 ;point to workspace
CFAA JSR &D482 ;0300/1+Y=0300/1+X
************* set graphics cursor to left hand column *******************
CFAD LDX #&00 ;X=0 point to graphics window left
CFAF LDY #&24 ;Y=&24
CFB1 JSR &D482 ;0300/1+Y=0300/1+X
CFB4 JMP &D1B8 ;set up external coordinates for graphics
CFB7 LDX &0360 ;number of logical colours less 1
CFBA BEQ &CFDC ;if MODE 7 CFDC
CFBC JSR &D03E ;set up character definition pointers
CFBF LDX &0360 ;number of logical colours less 1
CFC2 LDA &D0 ;VDU status byte
CFC4 AND #&20 ;and out bit 5 printing at graphics cursor
CFC6 BNE &CF5D ;if set CF5D
CFC8 LDY #&07 ;else Y=7
CFCA CPX #&03 ;if X=3
CFCC BEQ &CFEE ;goto CFEE to handle 4 colour modes
CFCE BCS &D01E ;else if X>3 D01E to deal with 16 colours
CFD0 LDA (&DE),Y ;get pattern byte
CFD2 ORA &D2 ;text colour byte to be orred or EORed into memory
CFD4 EOR &D3 ;text colour byte to be orred or EORed into memory
CFD6 STA (&D8),Y ; write to screen
CFD8 DEY ;Y=Y-1
CFD9 BPL &CFD0 ;if still +ve do loop again
CFDB RTS ;and exit
******* convert teletext characters *************************************
;mode 7
CFDC LDY #&02 ;Y=2
CFDE CMP &C4B6,Y ;compare with teletext conversion table
CFE1 BEQ &CFE9 ;if equal then CFE9
CFE3 DEY ;else Y=Y-1
CFE4 BPL &CFDE ;and if +ve CFDE
CFE6 STA (&D8,X) ;if not write byte to screen
CFE8 RTS ;and exit
CFE9 LDA &C4B7,Y ;convert with teletext conversion table
CFEC BNE &CFE6 ;and write it
***********four colour modes ********************************************
CFEE LDA (&DE),Y ;get pattern byte
CFF0 PHA ;save it
CFF1 LSR ;move hi nybble to lo
CFF2 LSR ;
CFF3 LSR ;
CFF4 LSR ;
CFF5 TAX ;X=A
CFF6 LDA &C31F,X ;4 colour mode byte mask look up table
CFF9 ORA &D2 ;text colour byte to be orred or EORed into memory
CFFB EOR &D3 ;text colour byte to be orred or EORed into memory
CFFD STA (&D8),Y ; write to screen
CFFF TYA ;A=Y
D000 CLC ;clear carry
D001 ADC #&08 ;add 8 to move screen RAM pointer 8 bytes
D003 TAY ;Y=A
D004 PLA ;get back A
D005 AND #&0F ;clear high nybble
D007 TAX ;X=A
D008 LDA &C31F,X ;4 colour mode byte mask look up table
D00B ORA &D2 ;text colour byte to be orred or EORed into memory
D00D EOR &D3 ;text colour byte to be orred or EORed into memory
D00F STA (&D8),Y ; write to screen
D011 TYA ;A=Y
D012 SBC #&08 ;A=A-9
D014 TAY ;Y=A
D015 BPL &CFEE ;if +ve do loop again
D017 RTS ;exit
D018 TYA ;Y=Y-&21
D019 SBC #&21 ;
D01B BMI &D017 ;IF Y IS negative then RETURN
D01D TAY ;else A=Y
******* 16 COLOUR MODES *************************************************
D01E LDA (&DE),Y ;get pattern byte
D020 STA &DC ;store it
D022 SEC ;set carry
D023 LDA #&00 ;A=0
D025 ROL &DC ;carry now occupies bit 0 of DC
D027 BEQ &D018 ;when DC=0 again D018 to deal with next pattern byte
D029 ROL ;get bit 7 from &DC into A bit 0
D02A ASL &DC ;rotate again to get second
D02C ROL ;bit into A
D02D TAX ;and store result in X
D02E LDA &C32F,X ;multiply by &55 using look up table
D031 ORA &D2 ;and set colour factors
D033 EOR &D3 ;
D035 STA (&D8),Y ;and store result
D037 CLC ;clear carry
D038 TYA ;Y=Y+8 moving screen RAM pointer on 8 bytes
D039 ADC #&08 ;
D03B TAY ;
D03C BCC &D023 ;iloop to D023 to deal with next bit pair
************* calculate pattern address for given code ******************
;A contains code on entry = 12345678
D03E ASL ;23456780 C holds 1
D03F ROL ;34567801 C holds 2
D040 ROL ;45678012 C holds 3
D041 STA &DE ;save this pattern
D043 AND #&03 ;00000012
D045 ROL ;00000123 C=0
D046 TAX ;X=A=0 - 7
D047 AND #&03 ;A=00000023
D049 ADC #&BF ;A=&BF,C0 or C1
D04B TAY ;this is used as a pointer
D04C LDA &C40D,X ;A=&80/2^X i.e.1,2,4,8,&10,&20,&40, or &80
D04F BIT &0367 ;with font flag
D052 BEQ &D057 ;if 0 D057
D054 LDY &0367,X ;else get hi byte from table
D057 STY &DF ;store Y
D059 LDA &DE ;get back pattern
D05B AND #&F8 ;convert to 45678000
D05D STA &DE ;and re store it
D05F RTS ;exit
;
*************************************************************************
*************************************************************************
** **
** **
** PLOT ROUTINES ENTER HERE **
** **
** **
*************************************************************************
*************************************************************************
;on entry ADDRESS PARAMETER DESCRIPTION
; 031F 1 plot type
; 0320/1 2,3 X coordinate
; 0322/3 4,5 Y coordinate
D060 LDX #&20 ;X=&20
D062 JSR &D14D ;translate coordinates
D065 LDA &031F ;get plot type
D068 CMP #&04 ;if its 4
D06A BEQ &D0D9 ;D0D9 move absolute
D06C LDY #&05 ;Y=5
D06E AND #&03 ;mask only bits 0 and 1
D070 BEQ &D080 ;if result is 0 then its a move (multiple of 8)
D072 LSR ;else move bit 0 int C
D073 BCS &D078 ;if set then D078 graphics colour required
D075 DEY ;Y=4
D076 BNE &D080 ;logic inverse colour must be wanted
******** graphics colour wanted *****************************************
D078 TAX ;X=A if A=0 its a foreground colour 1 its background
D079 LDY &035B,X ;get fore or background graphics PLOT mode
D07C LDA &0359,X ;get fore or background graphics colour
D07F TAX ;X=A
D080 JSR &D0B3 ;set up colour masks in D4/5
D083 LDA &031F ;get plot type
D086 BMI &D0AB ;if &80-&FF then D0AB type not implemented
D088 ASL ;bit 7=bit 6
D089 BPL &D0C6 ;if bit 6 is 0 then plot type is 0-63 so D0C6
D08B AND #&F0 ;else mask out lower nybble
D08D ASL ;shift old bit 6 into C bit old 5 into bit 7
D08E BEQ &D0D6 ;if 0 then type 64-71 was called single point plot
;goto D0D6
D090 EOR #&40 ;if bit 6 NOT set type &80-&87 fill triangle
D092 BEQ &D0A8 ;so D0A8
D094 PHA ;else push A
D095 JSR &D0DC ;copy 0320/3 to 0324/7 setting XY in current graphics
;coordinates
D098 PLA ;get back A
D099 EOR #&60 ;if BITS 6 and 5 NOT SET type 72-79 lateral fill
D09B BEQ &D0AE ;so D0AE
D09D CMP #&40 ;if type 88-95 horizontal line blanking
D09F BNE &D0AB ;so D0AB
D0A1 LDA #&02 ;else A=2
D0A3 STA &DC ;store it
D0A5 JMP &D506 ;and jump to D506 type not implemented
D0A8 JMP &D5EA ;to fill triangle routine
D0AB JMP &C938 ;VDU extension access entry
D0AE STA &DC ;store A
D0B0 JMP &D4BF ;
*********:set colour masks **********************************************
;graphics mode in Y
;colour in X
D0B3 TXA ;A=X
D0B4 ORA &C41C,Y ;or with GCOL plot options table byte
D0B7 EOR &C41D,Y ;EOR with following byte
D0BA STA &D4 ;and store it
D0BC TXA ;A=X
D0BD ORA &C41B,Y ;
D0C0 EOR &C420,Y ;
D0C3 STA &D5 ;
D0C5 RTS ;exit with masks in &D4/5
************** analyse first parameter in 0-63 range ********************
;
D0C6 ASL ;shift left again
D0C7 BMI &D0AB ;if -ve options are in range 32-63 not implemented
D0C9 ASL ;shift left twice more
D0CA ASL ;
D0CB BPL &D0D0 ;if still +ve type is 0-7 or 16-23 so D0D0
D0CD JSR &D0EB ;else display a point
D0D0 JSR &D1ED ;perform calculations
D0D3 JMP &D0D9 ;
*************************************************************************
* *
* PLOT A SINGLE POINT *
* *
*************************************************************************
D0D6 JSR &D0EB ;display a point
D0D9 JSR &CDE2 ;swap current and last graphics position
D0DC LDY #&24 ;Y=&24
D0DE LDX #&20 ;X=&20
D0E0 JMP &D48A ;copy parameters to 324/7 (300/3 +Y)
D0E3 LDX #&24 ;
D0E5 JSR &D85F ;calculate position
D0E8 BEQ &D0F0 ;if result =0 then D0F0
D0EA RTS ;else exit
;
D0EB JSR &D85D ;calculate position
D0EE BNE &D103 ;if A<>0 D103 and return
D0F0 LDY &031A ;else get current graphics scan line
D0F3 LDA &D1 ;pick up and modify screen byte
D0F5 AND &D4 ;
D0F7 ORA (&D6),Y ;
D0F9 STA &DA ;
D0FB LDA &D5 ;
D0FD AND &D1 ;
D0FF EOR &DA ;
D101 STA (&D6),Y ;put it back again
D103 RTS ;and exit
;
D104 LDA (&D6),Y ;this is a more simplistic version of the above
D106 ORA &D4 ;
D108 EOR &D5 ;
D10A STA (&D6),Y ;
D10C RTS ;and exit
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/D10D b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/D10D new file mode 100644 index 0000000..7978697 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/D10D @@ -0,0 +1 @@ +************************** Check window limits *************************
;
D10D LDX #&24 ;X=&24
D10F LDY #&00 ;Y=0
D111 STY &DA ;&DA=0
D113 LDY #&02 ;Y=2
D115 JSR &D128 ;check vertical graphics position 326/7
;bottom and top margins 302/3, 306/7
D118 ASL &DA ;DATA is set in &DA bits 0 and 1 then shift left
D11A ASL &DA ;twice to make room for next pass
D11C DEX ;X=&22
D11D DEX ;
D11E LDY #&00 ;Y=0
D120 JSR &D128 ;left and right margins 300/1, 304/5
;cursor horizontal position 324/5
D123 INX ;X=X+2
D124 INX ;
D125 LDA &DA ;A=&DA
D127 RTS ;exit
*** cursor and margins check ******************************************
;
D128 LDA &0302,X ;check for window violation
D12B CMP &0300,Y ;300/1 +Y > 302/3+X
D12E LDA &0303,X ;then window fault
D131 SBC &0301,Y ;
D134 BMI &D146 ;so D146
D136 LDA &0304,Y ;check other windows
D139 CMP &0302,X ;
D13C LDA &0305,Y ;
D13F SBC &0303,X ;
D142 BPL &D148 ;if no violation exit
D144 INC &DA ;else DA=DA+1
D146 INC &DA ;DA=DA+1
D148 RTS ;and exit DA=0 no problems DA=1 first check 2, 2nd
;
***********set up and adjust positional data ****************************
D149 LDA #&FF ;A=&FF
D14B BNE &D150 ;then &D150
D14D LDA &031F ;get first parameter in plot
D150 STA &DA ;store in &DA
D152 LDY #&02 ;Y=2
D154 JSR &D176 ;set up vertical coordinates/2
D157 JSR &D1AD ;/2 again to convert 1023 to 0-255 for internal use
;this is why minimum vertical plot separation is 4
D15A LDY #&00 ;Y=0
D15C DEX ;X=x-2
D15D DEX ;
D15E JSR &D176 ;set up horiz. coordinates/2 this is OK for mode0,4
D161 LDY &0361 ;get number of pixels/byte (-1)
D164 CPY #&03 ;if Y=3 (modes 1 and 5)
D166 BEQ &D16D ;D16D
D168 BCS &D170 ;for modes 0 & 4 this is 7 so D170
D16A JSR &D1AD ;for other modes divide by 2 twice
D16D JSR &D1AD ;divide by 2
D170 LDA &0356 ;get screen display type
D173 BNE &D1AD ;if not 0 (modes 3-7) divide by 2 again
D175 RTS ;and exit
;for mode 0 1 division 1280 becomes 640 = horizontal resolution
;for mode 1 2 divisions 1280 becomes 320 = horizontal resolution
;for mode 2 3 divisions 1280 becomes 160 = horizontal resolution
;for mode 4 2 divisions 1280 becomes 320 = horizontal resolution
;for mode 5 3 divisions 1280 becomes 160 = horizontal resolution
********** calculate external coordinates in internal format ***********
;on entry X is usually &1E or &20
;
D176 CLC ;clear carry
D177 LDA &DA ;get &DA
D179 AND #&04 ;if bit 2=0
D17B BEQ &D186 ;then D186 to calculate relative coordinates
D17D LDA &0302,X ;else get coordinate
D180 PHA ;
D181 LDA &0303,X ;
D184 BCC &D194 ;and goto D194
D186 LDA &0302,X ;get coordinate
D189 ADC &0310,Y ;add cursor position
D18C PHA ;save it
D18D LDA &0303,X ;
D190 ADC &0311,Y ;add cursor
D193 CLC ;clear carry
D194 STA &0311,Y ;save new cursor
D197 ADC &030D,Y ;add graphics origin
D19A STA &0303,X ;store it
D19D PLA ;get back lo byte
D19E STA &0310,Y ;save it in new cursor lo
D1A1 CLC ;clear carry
D1A2 ADC &030C,Y ;add to graphics orgin
D1A5 STA &0302,X ;store it
D1A8 BCC &D1AD ;if carry set
D1AA INC &0303,X ;increment hi byte as you would expect!
D1AD LDA &0303,X ;get hi byte
D1B0 ASL ;
D1B1 ROR &0303,X ;divide by 2
D1B4 ROR &0302,X ;
D1B7 RTS ;and exit
;
***** calculate external coordinates from internal coordinates************
D1B8 LDY #&10 ;Y=10
D1BA JSR &D488 ;copy 324/7 to 310/3 i.e.current graphics cursor
;position to position in external values
D1BD LDX #&02 ;X=2
D1BF LDY #&02 ;Y=2
D1C1 JSR &D1D5 ;multiply 312/3 by 4 and subtract graphics origin
D1C4 LDX #&00 ;X=0
D1C6 LDY #&04 ;Y=4
D1C8 LDA &0361 ;get number of pixels/byte
D1CB DEY ;Y=Y-1
D1CC LSR ;divide by 2
D1CD BNE &D1CB ;if result not 0 D1CB
D1CF LDA &0356 ;else get screen display type
D1D2 BEQ &D1D5 ;and if 0 D1D5
D1D4 INY ;
D1D5 ASL &0310,X ;multiply coordinate by 2
D1D8 ROL &0311,X ;
D1DB DEY ;Y-Y-1
D1DC BNE &D1D5 ;and if Y<>0 do it again
D1DE SEC ;set carry
D1DF JSR &D1E3 ;
D1E2 INX ;increment X
D1E3 LDA &0310,X ;get current graphics position in external coordinates
D1E6 SBC &030C,X ;subtract origin
D1E9 STA &0310,X ;store in graphics position
D1EC RTS ;and exit
;
************* compare X and Y PLOT spans ********************************
D1ED JSR &D40D ;Set X and Y spans in workspace 328/9 32A/B
D1F0 LDA &032B ;compare spans
D1F3 EOR &0329 ;if result -ve spans are different in sign so
D1F6 BMI &D207 ;goto D207
D1F8 LDA &032A ;else A=hi byte of difference in spans
D1FB CMP &0328 ;
D1FE LDA &032B ;
D201 SBC &0329 ;
D204 JMP &D214 ;and goto D214
D207 LDA &0328 ;A = hi byte of SUM of spans
D20A CLC ;
D20B ADC &032A ;
D20E LDA &0329 ;
D211 ADC &032B ;
D214 ROR ;A=A/2
D215 LDX #&00 ;X=0
D217 EOR &032B ;
D21A BPL &D21E ;if positive result D21E
D21C LDX #&02 ;else X=2
D21E STX &DE ;store it
D220 LDA &C4AA,X ;set up vector address
D223 STA &035D ;in 35D
D226 LDA &C4AB,X ;
D229 STA &035E ;and 35E
D22C LDA &0329,X ;get hi byte of span
D22F BPL &D235 ;if +ve D235
D231 LDX #&24 ;X=&24
D233 BNE &D237 ;jump to D237
D235 LDX #&20 ;X=&20
D237 STX &DF ;store it
D239 LDY #&2C ;Y=&2C
D23B JSR &D48A ;get X coordinate data or horizontal coord of
;curent graphics cursor
D23E LDA &DF ;get back original X
D240 EOR #&04 ;covert &20 to &24 and vice versa
D242 STA &DD ;
D244 ORA &DE ;
D246 TAX ;
D247 JSR &D480 ;copy 330/1 to 300/1+X
D24A LDA &031F ;get plot type
D24D AND #&10 ;check bit 4
D24F ASL ;
D250 ASL ;
D251 ASL ;move to bit 7
D252 STA &DB ;store it
D254 LDX #&2C ;X=&2C
D256 JSR &D10F ;check for window violations
D259 STA &DC ;
D25B BEQ &D263 ;if none then D263
D25D LDA #&40 ;else set bit 6 of &DB
D25F ORA &DB ;
D261 STA &DB ;
D263 LDX &DD ;
D265 JSR &D10F ;check window violations again
D268 BIT &DC ;if bit 7 of &DC NOT set
D26A BEQ &D26D ;D26D
D26C RTS ;else exit
;
D26D LDX &DE ;X=&DE
D26F BEQ &D273 ;if X=0 D273
D271 LSR ;A=A/2
D272 LSR ;A=A/2
D273 AND #&02 ;clear all but bit 2
D275 BEQ &D27E ;if bit 2 set D27E
D277 TXA ;else A=X
D278 ORA #&04 ;A=A or 4 setting bit 3
D27A TAX ;X=A
D27B JSR &D480 ;set 300/1+x to 330/1
D27E JSR &D42C ;more calcualtions
D281 LDA &DE ;A=&DE EOR 2
D283 EOR #&02 ;
D285 TAX ;X=A
D286 TAY ;Y=A
D287 LDA &0329 ;compare upper byte of spans
D28A EOR &032B ;
D28D BPL &D290 ;if signs are the same D290
D28F INX ;else X=X+1
D290 LDA &C4AE,X ;get vector addresses and store 332/3
D293 STA &0332 ;
D296 LDA &C4B2,X ;
D299 STA &0333 ;
D29C LDA #&7F ;A=&7F
D29E STA &0334 ;store it
D2A1 BIT &DB ;if bit 6 set
D2A3 BVS &D2CE ;the D2CE
D2A5 LDA &C447,X ;get VDU section number
D2A8 TAX ;X=A
D2A9 SEC ;set carry
D2AA LDA &0300,X ;subtract coordinates
D2AD SBC &032C,Y ;
D2B0 STA &DA ;
D2B2 LDA &0301,X ;
D2B5 SBC &032D,Y ;
D2B8 LDY &DA ;Y=hi
D2BA TAX ;X=lo=A
D2BB BPL &D2C0 ;and if A+Ve D2C0
D2BD JSR &D49B ;negate Y/A
D2C0 TAX ;X=A increment Y/A
D2C1 INY ;Y=Y+1
D2C2 BNE &D2C5 ;
D2C4 INX ;X=X+1
D2C5 TXA ;A=X
D2C6 BEQ &D2CA ;if A=0 D2CA
D2C8 LDY #&00 ;else Y=0
D2CA STY &DF ;&DF=Y
D2CC BEQ &D2D7 ;if 0 then D2D7
D2CE TXA ;A=X
D2CF LSR ;A=A/4
D2D0 ROR ;
D2D1 ORA #&02 ;bit 1 set
D2D3 EOR &DE ;
D2D5 STA &DE ;and store
D2D7 LDX #&2C ;X=&2C
D2D9 JSR &D864 ;
D2DC LDX &DC ;
D2DE BNE &D2E2 ;
D2E0 DEC &DD ;
D2E2 DEX ;X=X-1
D2E3 LDA &DB ;A=&3B
D2E5 BEQ &D306 ;if 0 D306
D2E7 BPL &D2F9 ;else if +ve D2F9
D2E9 BIT &0334 ;
D2EC BPL &D2F3 ;if bit 7=0 D2F3
D2EE DEC &0334 ;else decrement
D2F1 BNE &D316 ;and if not 0 D316
D2F3 INC &0334 ;
D2F6 ASL ;A=A*2
D2F7 BPL &D306 ;if +ve D306
D2F9 STX &DC ;
D2FB LDX #&2C ;
D2FD JSR &D85F ;calcualte screen position
D300 LDX &DC ;get back original X
D302 ORA #&00 ;
D304 BNE &D316 ;
D306 LDA &D1 ;byte mask for current graphics point
D308 AND &D4 ;and with graphics colour byte
D30A ORA (&D6),Y ;or with curent graphics cell line
D30C STA &DA ;store result
D30E LDA &D5 ;same again with next byte (hi??)
D310 AND &D1 ;
D312 EOR &DA ;
D314 STA (&D6),Y ;then store it inm current graphics line
D316 SEC ;set carry
D317 LDA &0335 ;A=&335/6-&337/8
D31A SBC &0337 ;
D31D STA &0335 ;
D320 LDA &0336 ;
D323 SBC &0338 ;
D326 BCS &D339 ;if carry set D339
D328 STA &DA ;
D32A LDA &0335 ;
D32D ADC &0339 ;
D330 STA &0335 ;
D333 LDA &DA ;
D335 ADC &033A ;
D338 CLC ;
D339 STA &0336 ;
D33C PHP ;
D33D BCS &D348 ;if carry clear jump to VDU routine else D348
D33F JMP (&0332) ;
****** vertical scan module 1******************************************
D342 DEY ;Y=Y-1
D343 BPL &D348 ;if + D348
D345 JSR &D3D3 ;else d3d3 to advance pointers
D348 JMP (&035D) ;and JUMP (&35D)
****** vertical scan module 2******************************************
D34B INY ;Y=Y+1
D34C CPY #&08 ;if Y<>8
D34E BNE &D348 ;then D348
D350 CLC ;else clear carry
D351 LDA &D6 ;get address of top line of cuirrent graphics cell
D353 ADC &0352 ;add number of bytes/character row
D356 STA &D6 ;store it
D358 LDA &D7 ;do same for hibyte
D35A ADC &0353 ;
D35D BPL &D363 ;if result -ve then we are above screen RAM
D35F SEC ;so
D360 SBC &0354 ;subtract screen memory size hi
D363 STA &D7 ;store it this wraps around point to screen RAM
D365 LDY #&00 ;Y=0
D367 JMP (&035D) ;
****** horizontal scan module 1******************************************
D36A LSR &D1 ;shift byte mask
D36C BCC &D348 ;if carry clear (&D1 was +ve) goto D348
D36E JSR &D3ED ;else reset pointers
D371 JMP (&035D) ;and off to do more
****** horizontal scan module 2******************************************
D374 ASL &D1 ;shift byte mask
D376 BCC &D348 ;if carry clear (&D1 was +ve) goto D348
D378 JSR &D3FD ;else reset pointers
D37B JMP (&035D) ;and off to do more
D37E DEY ;Y=Y-1
D37F BPL &D38D ;if +ve D38D
D381 JSR &D3D3 ;advance pointers
D384 BNE &D38D ;goto D38D normally
D386 LSR &D1 ;shift byte mask
D388 BCC &D38D ;if carry clear (&D1 was +ve) goto D348
D38A JSR &D3ED ;else reset pointers
D38D PLP ;pull flags
D38E INX ;X=X+1
D38F BNE &D395 ;if X>0 D395
D391 INC &DD ;else increment &DD
D393 BEQ &D39F ;and if not 0 D39F
D395 BIT &DB ;else if BIT 6 = 1
D397 BVS &D3A0 ;goto D3A0
D399 BCS &D3D0 ;if BIT 7=1 D3D0
D39B DEC &DF ;else Decrement &DF
D39D BNE &D3D0 ;and if not Zero D3D0
D39F RTS ;else return
;
D3A0 LDA &DE ;A=&DE
D3A2 STX &DC ;&DC=X
D3A4 AND #&02 ;clear all but bit 1
D3A6 TAX ;X=A
D3A7 BCS &D3C2 ;and if carry set goto D3C2
D3A9 BIT &DE ;if Bit 7 of &DE =1
D3AB BMI &D3B7 ;then D3B7
D3AD INC &032C,X ;else increment
D3B0 BNE &D3C2 ;and if not 0 D3C2
D3B2 INC &032D,X ;else increment hi byte
D3B5 BCC &D3C2 ;and if carry clear D3C2
D3B7 LDA &032C,X ;esle A=32C,X
D3BA BNE &D3BF ;and if not 0 D3BF
D3BC DEC &032D,X ;decrement hi byte
D3BF DEC &032C,X ;decrement lo byte
D3C2 TXA ;A=X
D3C3 EOR #&02 ;invert bit 2
D3C5 TAX ;X=A
D3C6 INC &032C,X ;Increment 32C/D
D3C9 BNE &D3CE ;
D3CB INC &032D,X ;
D3CE LDX &DC ;X=&DC
D3D0 JMP &D2E3 ;jump to D2E3
**********move display point up a line **********************************
D3D3 SEC ;SET CARRY
D3D4 LDA &D6 ;subtract number of bytes/line from address of
D3D6 SBC &0352 ;top line of current graphics cell
D3D9 STA &D6 ;
D3DB LDA &D7 ;
D3DD SBC &0353 ;
D3E0 CMP &034E ;compare with bottom of screen memory
D3E3 BCS &D3E8 ;if outside screen RAM
D3E5 ADC &0354 ;add screen memory size to wrap it around
D3E8 STA &D7 ;store in current address of graphics cell top line
D3EA LDY #&07 ;Y=7
D3EC RTS ;and RETURN
;
D3ED LDA &0362 ;get current left colour mask
D3F0 STA &D1 ;store it
D3F2 LDA &D6 ;get current top line of graphics cell
D3F4 ADC #&07 ;ADD 7
D3F6 STA &D6 ;
D3F8 BCC &D3FC ;
D3FA INC &D7 ;
D3FC RTS ;and return
;
D3FD LDA &0363 ;get right colour mask
D400 STA &D1 ;store it
D402 LDA &D6 ;A=top line graphics cell low
D404 BNE &D408 ;if not 0 D408
D406 DEC &D7 ;else decrement hi byte
D408 SBC #&08 ;subtract 9 (8 + carry)
D40A STA &D6 ;and store in low byte
D40C RTS ;return
;
********:: coordinate subtraction ***************************************
D40D LDY #&28 ;X=&28
D40F LDX #&20 ;Y=&20
D411 JSR &D418 ;
D414 INX ;X=X+2
D415 INX ;
D416 INY ;Y=Y+2
D417 INY ;
D418 SEC ;set carry
D419 LDA &0304,X ;subtract coordinates
D41C SBC &0300,X ;
D41F STA &0300,Y ;
D422 LDA &0305,X ;
D425 SBC &0301,X ;
D428 STA &0301,Y ;
D42B RTS ;and return
;
D42C LDA &DE ;A=&DE
D42E BNE &D437 ;if A=0 D437
D430 LDX #&28 ;X=&28
D432 LDY #&2A ;Y=&2A
D434 JSR &CDDE ;exchange 300/1+Y with 300/1+X
;IN THIS CASE THE X AND Y SPANS!
D437 LDX #&28 ;X=&28
D439 LDY #&37 ;Y=&37
D43B JSR &D48A ;copy &300/4+Y to &300/4+X
;transferring X and Y spans in this case
D43E SEC ;set carry
D43F LDX &DE ;X=&DE
D441 LDA &0330 ;subtract 32C/D,X from 330/1
D444 SBC &032C,X ;
D447 TAY ;partial answer in Y
D448 LDA &0331 ;
D44B SBC &032D,X ;
D44E BMI &D453 ;if -ve D453
D450 JSR &D49B ;else negate Y/A
D453 STA &DD ;store A
D455 STY &DC ;and Y
D457 LDX #&35 ;X=&35
D459 JSR &D467 ;get coordinates
D45C LSR ;
D45D STA &0301,X ;
D460 TYA ;
D461 ROR ;
D462 STA &0300,X ;
D465 DEX ;
D466 DEX ;
D467 LDY &0304,X ;
D46A LDA &0305,X ;
D46D BPL &D47B ;if A is +ve RETURN
D46F JSR &D49B ;else negate Y/A
D472 STA &0305,X ;store back again
D475 PHA ;
D476 TYA ;
D477 STA &0304,X ;
D47A PLA ;get back A
D47B RTS ;and exit
;
D47C LDA #&08 ;A=8
D47E BNE &D48C ;copy 8 bytes
D480 LDY #&30 ;Y=&30
D482 LDA #&02 ;A=2
D484 BNE &D48C ;copy 2 bytes
D486 LDY #&28 ;copy 4 bytes from 324/7 to 328/B
D488 LDX #&24 ;
D48A LDA #&04 ;
***********copy A bytes from 300,X to 300,Y ***************************
D48C STA &DA ;
D48E LDA &0300,X ;
D491 STA &0300,Y ;
D494 INX ;
D495 INY ;
D496 DEC &DA ;
D498 BNE &D48E ;
D49A RTS ;and return
;
************* negation routine ******************************************
D49B PHA ;save A
D49C TYA ;A=Y
D49D EOR #&FF ;invert
D49F TAY ;Y=A
D4A0 PLA ;get back A
D4A1 EOR #&FF ;invert
D4A3 INY ;Y=Y+1
D4A4 BNE &D4A9 ;if not 0 exit
D4A6 CLC ;else
D4A7 ADC #&01 ;add 1 to A
D4A9 RTS ;return
;
D4AA JSR &D85D ;check window boundaries and set up screen pointer
D4AD BNE &D4B7 ;if A<>0 D4B7
D4AF LDA (&D6),Y ;else get byte from current graphics cell
D4B1 EOR &035A ;compare with current background colour
D4B4 STA &DA ;store it
D4B6 RTS ;and RETURN
;
D4B7 PLA ;get back return link
D4B8 PLA ;
D4B9 INC &0326 ;increment current graphics cursor vertical lo
D4BC JMP &D545 ;
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/D4BF b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/D4BF new file mode 100644 index 0000000..2d10030 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/D4BF @@ -0,0 +1 @@ +OS SERIES IV
GEOFF COX
*************************************************************************
* *
* LATERAL FILL ROUTINE *
* *
*************************************************************************
D4BF JSR &D4AA ;check current screen state
D4C2 AND &D1 ;if A and &D1 <> 0 a plotted point has been found
D4C4 BNE &D4B9 ;so D4B9
D4C6 LDX #&00 ;X=0
D4C8 JSR &D592 ;update pointers
D4CB BEQ &D4FA ;if 0 then D4FA
D4CD LDY &031A ;else Y=graphics scan line
D4D0 ASL &D1 ;
D4D2 BCS &D4D9 ;if carry set D4D9
D4D4 JSR &D574 ;else D574
D4D7 BCC &D4FA ;if carry clear D4FA
D4D9 JSR &D3FD ;else D3FD to pick up colour multiplier
D4DC LDA (&D6),Y ;get graphics cell line
D4DE EOR &035A ;EOR with background colour
D4E1 STA &DA ;and store
D4E3 BNE &D4F7 ;if not 0 D4F7
D4E5 SEC ;else set carry
D4E6 TXA ;A=X
D4E7 ADC &0361 ;add pixels/byte
D4EA BCC &D4F0 ;and if carry clear D4F0
D4EC INC &DB ;else increment &DB
D4EE BPL &D4F7 ;and if +ve D4F7
D4F0 TAX ;else X=A
D4F1 JSR &D104 ;display a pixel
D4F4 SEC ;set carry
D4F5 BCS &D4D9 ;goto D4D9
D4F7 JSR &D574 ;
D4FA LDY #&00 ;Y=0
D4FC JSR &D5AC ;
D4FF LDY #&20 ;
D501 LDX #&24 ;
D503 JSR &CDE6 ;exchange 300/3 +Y with 300/3+X
D506 JSR &D4AA ;check screen pixel
D509 LDX #&04 ;Y=5
D50B JSR &D592 ;
D50E TXA ;A=x
D50F BNE &D513 ;if A<>0 d513
D511 DEC &DB ;else &DB=&dB-1
D513 DEX ;X=X-1
D514 JSR &D54B ;
D517 BCC &D540 ;
D519 JSR &D3ED ;update pointers
D51C LDA (&D6),Y ;get byte from graphics line
D51E EOR &035A ;EOR with background colour
D521 STA &DA ;and store it
D523 LDA &DC ;
D525 BNE &D514 ;If A-0 back to D514
D527 LDA &DA ;else A=&DA
D529 BNE &D53D ;if A<>d53D
D52B SEC ;else set carry
D52C TXA ;A=x
D52D ADC &0361 ;Add number of pixels/byte
D530 BCC &D536 ;and if carry clear D536
D532 INC &DB ;else inc DB
D534 BPL &D53D ;and if +ve D53D
D536 TAX ;get back X
D537 JSR &D104 ;display a point
D53A SEC ;set carry
D53B BCS &D519 ;goto D519
D53D JSR &D54B ;
D540 LDY #&04 ;
D542 JSR &D5AC ;
D545 JSR &D0D9 ;
D548 JMP &D1B8 ;scale pointers
D54B LDA &D1 ;get byte mask
D54D PHA ;save it
D54E CLC ;clear carry
D54F BCC &D560 ;
D551 PLA ;get back A
D552 INX ;X=X+1
D553 BNE &D559 ;if not 0 D559
D555 INC &DB ;else inc &DB
D557 BPL &D56F ;if +ve D56F
D559 LSR &D1 ;
D55B BCS &D56F ;if Bit 7 D1 set D56F
D55D ORA &D1 ;else or withA
D55F PHA ;save result
D560 LDA &D1 ;A=&D1
D562 BIT &DA ;test bits 6 and 7 of &DA
D564 PHP ;save flags
D565 PLA ;get into A
D566 EOR &DC ;EOR and DC
D568 PHA ;save A
D569 PLP ;
D56A BEQ &D551 ;
D56C PLA ;A=A EOR &D1 (byte mask)
D56D EOR &D1 ;
D56F STA &D1 ;store it
D571 JMP &D0F0 ;and display a pixel
D574 LDA #&00 ;A=0
D576 CLC ;Clear carry
D577 BCC &D583 ;goto D583 if carry clear
D579 INX ;X=X+1
D57A BNE &D580 ;If <>0 D580
D57C INC &DB ;else inc &DB
D57E BPL &D56F ;and if +ve d56F
D580 ASL ;A=A*2
D581 BCS &D58E ;if C set D58E
D583 ORA &D1 ;else A=A OR (&D1)
D585 BIT &DA ;set V and M from &DA b6 b7
D587 BEQ &D579 ;
D589 EOR &D1 ;A=AEOR &D1
D58B LSR ;/2
D58C BCC &D56F ;if carry clear D56F
D58E ROR ;*2
D58F SEC ;set carry
D590 BCS &D56F ;to D56F
D592 LDA &0300,X ;Y/A=(&300/1 +X)-(&320/1)
D595 SEC ;
D596 SBC &0320 ;
D599 TAY ;
D59A LDA &0301,X ;
D59D SBC &0321 ;
D5A0 BMI &D5A5 ;if result -ve D5A5
D5A2 JSR &D49B ;or negate Y/A
D5A5 STA &DB ;store A
D5A7 TYA ;A=Y
D5A8 TAX ;X=A
D5A9 ORA &DB ;
D5AB RTS ;exit
;
D5AC STY &DA ;Y=&DA
D5AE TXA ;A=X
D5AF TAY ;Y=A
D5B0 LDA &DB ;A=&DB
D5B2 BMI &D5B6 ;if -ve D5B6
D5B4 LDA #&00 ;A=0
D5B6 LDX &DA ;X=&DA
D5B8 BNE &D5BD ;if <>0 D5BD
D5BA JSR &D49B ;negate
D5BD PHA ;
D5BE CLC ;
D5BF TYA ;
D5C0 ADC &0300,X ;Y/A+(&300/1 +X)=(&320/1)
D5C3 STA &0320 ;
D5C6 PLA ;
D5C7 ADC &0301,X ;
D5CA STA &0321 ;
D5CD RTS ;return
*************************************************************************
* *
* OSWORD 13 - READ LAST TWO GRAPHIC CURSOR POSITIONS *
* *
*************************************************************************
;
D5CE LDA #&03 ;A=3
D5D0 JSR &D5D5 ;
D5D3 LDA #&07 ;A=7
D5D5 PHA ;Save A
D5D6 JSR &CDE2 ;exchange last 2 graphics cursor coordinates with
;current coordinates
D5D9 JSR &D1B8 ;convert to external coordinates
D5DC LDX #&03 ;X=3
D5DE PLA ;save A
D5DF TAY ;Y=A
D5E0 LDA &0310,X ;get graphics coordinate
D5E3 STA (&F0),Y ;store it in OS buffer
D5E5 DEY ;decrement Y and X
D5E6 DEX ;
D5E7 BPL &D5E0 ;if +ve do it again
D5E9 RTS ;then Exit
;
*************************************************************************
* *
* PLOT Fill triangle routine *
* *
*************************************************************************
D5EA LDX #&20 ;X=&20
D5EC LDY #&3E ;Y=&3E
D5EE JSR &D47C ;copy 300/7+X to 300/7+Y
;this gets XY data parameters and current graphics
;cursor position
D5F1 JSR &D632 ;exchange 320/3 with 324/7 if 316/7=<322/3
D5F4 LDX #&14 ;X=&14
D5F6 LDY #&24 ;Y=&24
D5F8 JSR &D636 ;
D5FB JSR &D632 ;
D5FE LDX #&20 ;
D600 LDY #&2A ;
D602 JSR &D411 ;calculate 032A/B-(324/5-320/1)
D605 LDA &032B ;and store
D608 STA &0332 ;result
D60B LDX #&28 ;set pointers
D60D JSR &D459 ;
D610 LDY #&2E ;
D612 JSR &D0DE ;copy 320/3 32/31
D615 JSR &CDE2 ;exchange 314/7 with 324/7
D618 CLC ;
D619 JSR &D658 ;execute fill routine
D61C JSR &CDE2 ;
D61F LDX #&20 ;
D621 JSR &CDE4 ;
D624 SEC ;
D625 JSR &D658 ;
D628 LDX #&3E ;;X=&3E
D62A LDY #&20 ;;Y=&20
D62C JSR &D47C ;;copy 300/7+X to 300/7+Y
D62F JMP &D0D9 ;;this gets XY data parameters and current graphics
;cursor position
D632 LDX #&20 ;X=&20
D634 LDY #&14 ;Y=&14
D636 LDA &0302,X ;
D639 CMP &0302,Y ;
D63C LDA &0303,X ;
D63F SBC &0303,Y ;
D642 BMI &D657 ;if 302/3+Y>302/3+X return
D644 JMP &CDE6 ;else swap 302/3+X with 302/3+Y
;
*************************************************************************
* *
* OSBYTE 134 - READ CURSOR POSITION *
* *
*************************************************************************
D647 LDA &0318 ;read current text cursor (X)
D64A SEC ;set carry
D64B SBC &0308 ;subtract left hand column of current text window
D64E TAX ;X=A
D64F LDA &0319 ;get current text cursor (Y)
D652 SEC ;
D653 SBC &030B ;suptract top row of current window
D656 TAY ;Y=A
D657 RTS ;and exit
;PLOT routines continue
;many of the following routines are just manipulations
;only points of interest will be explained
D658 PHP ;store flags
D659 LDX #&20 ;X=&20
D65B LDY #&35 ;Y=&35
D65D JSR &D411 ;335/6=(324/5+X-320/1)
D660 LDA &0336 ;
D663 STA &033D ;
D666 LDX #&33 ;
D668 JSR &D459 ;set pointers
D66B LDY #&39 ;set 339/C=320/3
D66D JSR &D0DE ;
D670 SEC ;
D671 LDA &0322 ;
D674 SBC &0326 ;
D677 STA &031B ;
D67A LDA &0323 ;
D67D SBC &0327 ;
D680 STA &031C ;
D683 ORA &031B ;check VDU queque
D686 BEQ &D69F ;
D688 JSR &D6A2 ;display a line
D68B LDX #&33 ;
D68D JSR &D774 ;update pointers
D690 LDX #&28 ;
D692 JSR &D774 ;and again!
D695 INC &031B ;update VDU queque
D698 BNE &D688 ;and if not empty do it again
D69A INC &031C ;else increment next byte
D69D BNE &D688 ;and do it again
D69F PLP ;pull flags
D6A0 BCC &D657 ;if carry clear exit
D6A2 LDX #&39 ;
D6A4 LDY #&2E ;
D6A6 STX &DE ;
D6A8 LDA &0300,X ;is 300/1+x<300/1+Y
D6AB CMP &0300,Y ;
D6AE LDA &0301,X ;
D6B1 SBC &0301,Y ;
D6B4 BMI &D6BC ;if so D6BC
D6B6 TYA ;else A=Y
D6B7 LDY &DE ;Y=&DE
D6B9 TAX ;X=A
D6BA STX &DE ;&DE=X
D6BC STY &DF ;&DF=Y
D6BE LDA &0300,Y ;
D6C1 PHA ;
D6C2 LDA &0301,Y ;
D6C5 PHA ;
D6C6 LDX &DF ;
D6C8 JSR &D10F ;check for window violations
D6CB BEQ &D6DA ;
D6CD CMP #&02 ;
D6CF BNE &D70E ;
D6D1 LDX #&04 ;
D6D3 LDY &DF ;
D6D5 JSR &D482 ;
D6D8 LDX &DF ;
D6DA JSR &D864 ;set a screen address
D6DD LDX &DE ;X=&DE
D6DF JSR &D10F ;check for window violations
D6E2 LSR ;A=A/2
D6E3 BNE &D70E ;if A<>0 then exit
D6E5 BCC &D6E9 ;else if C clear D6E9
D6E7 LDX #&00 ;
D6E9 LDY &DF ;
D6EB SEC ;
D6EC LDA &0300,Y ;
D6EF SBC &0300,X ;
D6F2 STA &DC ;
D6F4 LDA &0301,Y ;
D6F7 SBC &0301,X ;
D6FA STA &DD ;
D6FC LDA #&00 ;
D6FE ASL ;
D6FF ORA &D1 ;
D701 LDY &DC ;
D703 BNE &D719 ;
D705 DEC &DD ;
D707 BPL &D719 ;
D709 STA &D1 ;
D70B JSR &D0F0 ;display a point
D70E LDX &DF ;restore X
D710 PLA ;and A
D711 STA &0301,X ;store it
D714 PLA ;get back A
D715 STA &0300,X ;and store it
D718 RTS ;exit
;
D719 DEC &DC ;
D71B TAX ;
D71C BPL &D6FE ;
D71E STA &D1 ;
D720 JSR &D0F0 ;display a point
D723 LDX &DC ;
D725 INX ;
D726 BNE &D72A ;
D728 INC &DD ;
D72A TXA ;
D72B PHA ;
D72C LSR &DD ;
D72E ROR ;
D72F LDY &0361 ;number of pixels/byte
D732 CPY #&03 ;if 3 mode = goto D73B
D734 BEQ &D73B ;
D736 BCC &D73E ;else if <3 mode 2 goto D73E
D738 LSR &DD ;else rotate bottom bit of &DD
D73A ROR ;into Accumulator
D73B LSR &DD ;rotate bottom bit of &DD
D73D LSR ;into Accumulator
D73E LDY &031A ;Y=line in current graphics cell containing current
;point
D741 TAX ;X=A
D742 BEQ &D753 ;
D744 TYA ;Y=Y-8
D745 SEC ;
D746 SBC #&08 ;
D748 TAY ;
D749 BCS &D74D ;
D74B DEC &D7 ;decrement byte of top line off current graphics cell
D74D JSR &D104 ;display a point
D750 DEX ;
D751 BNE &D744 ;
D753 PLA ;
D754 AND &0361 ;pixels/byte
D757 BEQ &D70E ;
D759 TAX ;
D75A LDA #&00 ;A=0
D75C ASL ;
D75D ORA &0363 ;or with right colour mask
D760 DEX ;
D761 BNE &D75C ;
D763 STA &D1 ;store as byte mask
D765 TYA ;Y=Y-8
D766 SEC ;
D767 SBC #&08 ;
D769 TAY ;
D76A BCS &D76E ;if carry clear
D76C DEC &D7 ;decrement byte of top line off current graphics cell
D76E JSR &D0F3 ;display a point
D771 JMP &D70E ;and exit via D70E
D774 INC &0308,X ;
D777 BNE &D77C ;
D779 INC &0309,X ;
D77C SEC ;
D77D LDA &0300,X ;
D780 SBC &0302,X ;
D783 STA &0300,X ;
D786 LDA &0301,X ;
D789 SBC &0303,X ;
D78C STA &0301,X ;
D78F BPL &D7C1 ;
D791 LDA &030A,X ;
D794 BMI &D7A1 ;
D796 INC &0306,X ;
D799 BNE &D7AC ;
D79B INC &0307,X ;
D79E JMP &D7AC ;
D7A1 LDA &0306,X ;
D7A4 BNE &D7A9 ;
D7A6 DEC &0307,X ;
D7A9 DEC &0306,X ;
D7AC CLC ;
D7AD LDA &0300,X ;
D7B0 ADC &0304,X ;
D7B3 STA &0300,X ;
D7B6 LDA &0301,X ;
D7B9 ADC &0305,X ;
D7BC STA &0301,X ;
D7BF BMI &D791 ;
D7C1 RTS ;
;
;
*************************************************************************
* *
* OSBYTE 135 - READ CHARACTER AT TEXT CURSOR POSITION *
* *
*************************************************************************
D7C2 LDY &0360 ;get number of logical colours
D7C5 BNE &D7DC ;if Y<>0 mode <>7 so D7DC
D7C7 LDA (&D8),Y ;get address of top scan line of current text chr
D7C9 LDY #&02 ;Y=2
D7CB CMP &C4B7,Y ;compare with conversion table
D7CE BNE &D7D4 ;if not equal D7d4
D7D0 LDA &C4B6,Y ;else get next lower byte from table
D7D3 DEY ;Y=Y-1
D7D4 DEY ;Y=Y-1
D7D5 BPL &D7CB ;and if +ve do it again
D7D7 LDY &0355 ;Y=current screen mode
D7DA TAX ;return with character in X
D7DB RTS ;
;
D7DC JSR &D808 ;set up copy of the pattern bytes at text cursor
D7DF LDX #&20 ;X=&20
D7E1 TXA ;A=&20
D7E2 PHA ;Save it
D7E3 JSR &D03E ;get pattern address for code in A
D7E6 PLA ;get back A
D7E7 TAX ;and X
D7E8 LDY #&07 ;Y=7
D7EA LDA &0328,Y ;get byte in pattern copy
D7ED CMP (&DE),Y ;check against pattern source
D7EF BNE &D7F9 ;if not the same D7F9
D7F1 DEY ;else Y=Y-1
D7F2 BPL &D7EA ;and if +ve D7EA
D7F4 TXA ;A=X
D7F5 CPX #&7F ;is X=&7F (delete)
D7F7 BNE &D7D7 ;if not D7D7
D7F9 INX ;else X=X+1
D7FA LDA &DE ;get byte lo address
D7FC CLC ;clear carry
D7FD ADC #&08 ;add 8
D7FF STA &DE ;store it
D801 BNE &D7E8 ;and go back to check next character if <>0
D803 TXA ;A=X
D804 BNE &D7E1 ;if <>0 D7E1
D806 BEQ &D7D7 ;else D7D7
***************** set up pattern copy ***********************************
D808 LDY #&07 ;Y=7
D80A STY &DA ;&DA=Y
D80C LDA #&01 ;A=1
D80E STA &DB ;&DB=A
D810 LDA &0362 ;A=left colour mask
D813 STA &DC ;store an &DC
D815 LDA (&D8),Y ;get a byte from current text character
D817 EOR &0358 ;EOR with text background colour
D81A CLC ;clear carry
D81B BIT &DC ;and check bits of colour mask
D81D BEQ &D820 ;if result =0 then D820
D81F SEC ;else set carry
D820 ROL &DB ;&DB=&DB+Carry
D822 BCS &D82E ;if carry now set (bit 7 DB originally set) D82E
D824 LSR &DC ;else &DC=&DC/2
D826 BCC &D81B ;if carry clear D81B
D828 TYA ;A=Y
D829 ADC #&07 ;ADD ( (7+carry)
D82B TAY ;Y=A
D82C BCC &D810 ;
D82E LDY &DA ;read modified values into Y and A
D830 LDA &DB ;
D832 STA &0328,Y ;store copy
D835 DEY ;and do it again
D836 BPL &D80A ;until 8 bytes copied
D838 RTS ;exit
;
********* pixel reading *************************************************
D839 PHA ;store A
D83A TAX ;X=A
D83B JSR &D149 ;set up positional data
D83E PLA ;get back A
D83F TAX ;X=A
D840 JSR &D85F ;set a screen address after checking for window
;violations
D843 BNE &D85A ;if A<>0 D85A to exit with A=&FF
D845 LDA (&D6),Y ;else get top line of current graphics cell
D847 ASL ;A=A*2 C=bit 7
D848 ROL &DA ;&DA=&DA+2 +C C=bit 7 &DA
D84A ASL &D1 ;byte mask=bM*2 +carry from &DA
D84C PHP ;save flags
D84D BCS &D851 ;if carry set D851
D84F LSR &DA ;else restore &DA with bit '=0
D851 PLP ;pull flags
D852 BNE &D847 ;if Z set D847
D854 LDA &DA ;else A=&DA AND number of colours in current mode -1
D856 AND &0360 ;
D859 RTS ;then exit
;
D85A LDA #&FF ;A=&FF
D85C RTS ;exit
;
********** check for window violations and set up screen address **********
D85D LDX #&20 ;X=&20
D85F JSR &D10F ;
D862 BNE &D85C ;if A<>0 there is a window violation so D85C
D864 LDA &0302,X ;else set up graphics scan line variable
D867 EOR #&FF ;
D869 TAY ;
D86A AND #&07 ;
D86C STA &031A ;in 31A
D86F TYA ;A=Y
D870 LSR ;A=A/2
D871 LSR ;A=A/2
D872 LSR ;A=A/2
D873 ASL ;A=A*2 this gives integer value bit 0 =0
D874 TAY ;Y=A
D875 LDA (&E0),Y ;get high byte of offset from screen RAM start
D877 STA &DA ;store it
D879 INY ;Y=Y+1
D87A LDA (&E0),Y ;get lo byte
D87C LDY &0356 ;get screen map type
D87F BEQ &D884 ;if 0 (modes 0,1,2) goto D884
D881 LSR &DA ;else &DA=&DA/2
D883 ROR ;and A=A/2 +C if set
;so 2 byte offset =offset/2
D884 ADC &0350 ;add screen top left hand corner lo
D887 STA &D6 ;store it
D889 LDA &DA ;get high byte
D88B ADC &0351 ;add top left hi
D88E STA &D7 ;store it
D890 LDA &0301,X ;
D893 STA &DA ;
D895 LDA &0300,X ;
D898 PHA ;
D899 AND &0361 ;and then Add pixels per byte-1
D89C ADC &0361 ;
D89F TAY ;Y=A
D8A0 LDA &C406,Y ;A=&80 /2^Y using look up table
D8A3 STA &D1 ;store it
D8A5 PLA ;get back A
D8A6 LDY &0361 ;Y=&number of pixels/byte
D8A9 CPY #&03 ;is Y=3 (modes 1,6)
D8AB BEQ &D8B2 ;goto D8B2
D8AD BCS &D8B5 ;if mode =1 or 4 D8B5
D8AF ASL ;A/&DA =A/&DA *2
D8B0 ROL &DA ;
D8B2 ASL ;
D8B3 ROL &DA ;
D8B5 AND #&F8 ;clear bits 0-2
D8B7 CLC ;clear carry
D8B8 ADC &D6 ;add A/&DA to &D6/7
D8BA STA &D6 ;
D8BC LDA &DA ;
D8BE ADC &D7 ;
D8C0 BPL &D8C6 ;if result +ve D8C6
D8C2 SEC ;else set carry
D8C3 SBC &0354 ;and subtract screen memory size making it wrap round
D8C6 STA &D7 ;store it in &D7
D8C8 LDY &031A ;get line in graphics cell containing current graphics
D8CB LDA #&00 ;point A=0
D8CD RTS ;And exit
;
D8CE PHA ;Push A
D8CF LDA #&A0 ;A=&A0
D8D1 LDX &026A ;X=number of items in VDU queque
D8D4 BNE &D916 ;if not 0 D916
D8D6 BIT &D0 ;else check VDU status byte
D8D8 BNE &D916 ;if either VDU is disabled or plot to graphics
;cursor enabled then D916
D8DA BVS &D8F5 ;if cursor editing enabled D8F5
D8DC LDA &035F ;else get 6845 register start setting
D8DF AND #&9F ;clear bits 5 and 6
D8E1 ORA #&40 ;set bit 6 to modify last cursor size setting
D8E3 JSR &C954 ;change write cursor format
D8E6 LDX #&18 ;X=&18
D8E8 LDY #&64 ;Y=&64
D8EA JSR &D482 ;set text input cursor from text output cursor
D8ED JSR &CD7A ;modify character at cursor poistion
D8F0 LDA #&02 ;A=2
D8F2 JSR &C59D ;bit 1 of VDU status is set to bar scrolling
D8F5 LDA #&BF ;A=&BF
D8F7 JSR &C5A8 ;bit 6 of VDU status =0
D8FA PLA ;Pull A
D8FB AND #&7F ;clear hi bit (7)
D8FD JSR &C4C0 ;entire VDU routine !!
D900 LDA #&40 ;A=&40
D902 JMP &C59D ;exit
D905 LDA #&20 ;A=&20
D907 BIT &D0 ;if bit 6 cursor editing is set
D909 BVC &D8CB ;
D90B BNE &D8CB ;or bit 5 is set exit &D8CB
D90D JSR &D7C2 ;read a character from the screen
D910 BEQ &D917 ;if A=0 on return exit via D917
D912 PHA ;else store A
D913 JSR &C664 ;perform cursor right
D916 PLA ;restore A
D917 RTS ;and exit
;
D918 LDA #&BD ;zero bits 2 and 6 of VDU status
D91A JSR &C5A8 ;
D91D JSR &C951 ;set normal cursor
D920 LDA #&0D ;A=&0D
D922 RTS ;and return
;this is response of CR as end of edit line
*************************************************************************
* *
* OSBYTE 132 - READ BOTTOM OF DISPLAY RAM *
* *
*************************************************************************
;
D923 LDX &0355 ; Get current screen mode
*************************************************************************
* *
* OSBYTE 133 - READ LOWEST ADDRESS FOR GIVEN MODE *
* *
*************************************************************************
D926 TXA ; A=X
D927 AND #&07 ; Ensure mode 0-7
D929 TAY ; Pass to Y into index into screen size table
D92A LDX &C440,Y ; X=screen size type, 0-4
D92D LDA &C45E,X ; A=high byte of start address for screen type
D930 LDX #&00 ; Returned address is &xx00
D932 BIT &028E ; Check available RAM
D935 BMI &D93E ; If bit 7 set then 32K RAM, so return address
D937 AND #&3F ; 16K RAM, so drop address to bottom 16K
D939 CPY #&04 ; Check screen mode
D93B BCS &D93E ; If mode 4-7, return the address
D93D TXA ; If mode 0-3, return &0000 as not enough memory
; exit
D93E TAY ; Pass high byte of address to Y
D93F RTS ; and return address in YX
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/D940 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/D940 new file mode 100644 index 0000000..1c5c51c --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/D940 @@ -0,0 +1 @@ +*************************************************************************
*************************************************************************
** **
** SYSTEM STARTUP **
** **
*************************************************************************
*************************************************************************
* DEFAULT PAGE &02 SETTINGS (VECTORS, OSBYTE VARIABLES)
* RESET CODE
*************************************************************************
* *
* DEFAULT SYSTEM SETTINGS FOR PAGE &02 *
* *
*************************************************************************
-------------------------------------------------------------------------
| |
| DEFAULT VECTOR TABLE |
| |
-------------------------------------------------------------------------
D940 DW &E310 ; USERV &200
D942 DW &DC54 ; BRKV &202
D944 DW &DC93 ; IRQ1V &204
D946 DW &DE89 ; IRQ2V &206
D948 DW &DF89 ; CLIV &208
D94A DW &E772 ; BYTEV &20A
D94C DW &E7EB ; WORDV &20C
D94E DW &E0A4 ; WRCHV &20E
D950 DW &DEC5 ; RDCHV &210
D952 DW &F27D ; FILEV &212
D954 DW &F18E ; ARGSV &214
D956 DW &F4C9 ; BGETV &216
D958 DW &F529 ; BPUTV &218
D95A DW &FFA6 ; GBPBV &21A
D95C DW &F3CA ; FINDV &21C
D95E DW &F1B1 ; FSCV &21E
D960 DW &FFA6 ; EVNTV &220
D962 DW &FFA6 ; UPTV &222
D964 DW &FFA6 ; NETV &224
D966 DW &FFA6 ; VDUV &226
D968 DW &EF02 ; KEYV &228
D96A DW &E4B3 ; INSBV &22A
D96C DW &E464 ; REMVB &22C
D96E DW &E1D1 ; CNPV &22E
D970 DW &FFA6 ; IND1V &230
D972 DW &FFA6 ; IND2V &232
D974 DW &FFA6 ; IND3V &234
-------------------------------------------------------------------------
| |
| DEFAULT MOS VARIABLES SETTINGS |
| |
-------------------------------------------------------------------------
* Read/Written by OSBYTE &A6 to &FC
D976 DW &0190 ; OSBYTE variables base address &236 *FX166/7
; (address to add to osbyte number)
D978 DB &0D9F ; Address of extended vectors &238 *FX168/9
D97A DB &02A1 ; Address of ROM information table &23A *FX170/1
D97C DB &F02B ; Address of key translation table &23C *FX172/3
D97E DB &0300 ; Address of VDU variables &23E *FX174/5
D980 DB &00 ; CFS/Vertical sync Timeout counter &240 *FX176
D981 DB &00 ; Current input buffer number &241 *FX177
D982 DB &FF ; Keyboard interrupt processing flag &242 *FX178
D983 DB &00 ; Primary OSHWM (default PAGE) &243 *FX179
D984 DB &00 ; Current OSHWM (PAGE) &244 *FX180
D985 DB &01 ; RS423 input mode &245 *FX181
D986 DB &00 ; Character explosion state &246 *FX182
D987 DB &00 ; CFS/RFS selection, CFS=0 ROM=2 &247 *FX183
D988 DB &00 ; Video ULA control register copy &248 *FX184
D989 DB &00 ; Pallette setting copy &249 *FX185
D98A DB &00 ; ROM number selected at last BRK &24A *FX186
D98B DB &FF ; BASIC ROM number &24B *FX187
D98C DB &04 ; Current ADC channel number &24C *FX188
D98D DB &04 ; Maximum ADC channel number &24D *FX189
D98E DB &00 ; ADC conversion 0/8bit/12bit &24E *FX190
D98F DB &FF ; RS423 busy flag (bit 7=0, busy) &24F *FX191
D990 DB &56 ; ACIA control register copy &250 *FX192
D991 DB &19 ; Flash counter &251 *FX193
D992 DB &19 ; Flash mark period count &252 *FX194
D993 DB &19 ; Flash space period count &253 *FX195
D994 DB &32 ; Keyboard auto-repeat delay &254 *FX196
D995 DB &08 ; Keyboard auto-repeat rate &255 *FX197
D996 DB &00 ; *EXEC file handle &256 *FX198
D997 DB &00 ; *SPOOL file handle &257 *FX199
D998 DB &00 ; Break/Escape handing &258 *FX200
D999 DB &00 ; Econet keyboard disable flag &259 *FX201
D99A DB &20 ; Keyboard status &25A *FX202
; bit 3=1 shift pressed
; bit 4=0 caps lock
; bit 5=0 shift lock
; bit 6=1 control bit
; bit 7=1 shift enabled
D99B DB &09 ; Serial input buffer full threshold &25B *FX203
D99C DB &00 ; Serial input suppression flag &25C *FX204
D99D DB &00 ; Cassette/RS423 flag (0=CFS, &40=RS423) &25D *FX205
D99E DB &00 ; Econet OSBYTE/OSWORD interception flag &25E *FX206
D99F DB &00 ; Econet OSRDCH interception flag &25F *FX207
D9A0 DB &00 ; Econet OSWRCH interception flag &260 *FX208
D9A1 DB &50 ; Speech enable/disable flag (&20/&50) &261 *FX209
D9A2 DB &00 ; Sound output disable flag &262 *FX210
D9A3 DB &03 ; BELL channel number &263 *FX211
D9A4 DB &90 ; BELL amplitude/Envelope number &264 *FX212
D9A5 DB &64 ; BELL frequency &265 *FX213
D9A6 DB &06 ; BELL duration &266 *FX214
D9A7 DB &81 ; Startup message/!BOOT error status &267 *FX215
D9A8 DB &00 ; Length of current soft key string &268 *FX216
D9A9 DB &00 ; Lines printed since last paged halt &269 *FX217
D9AA DB &00 ; 0-(Number of items in VDU queue) &26A *FX218
D9AB DB &09 ; TAB key value &26B *FX219
D9AC DB &1B ; ESCAPE character &26C *FX220
; The following are input buffer code interpretation variables for
; bytes entered into the input buffer with b7 set (is 128-255).
; The standard keyboard only enters characters &80-&BF with the
; function keys, but other characters can be entered, for instance
; via serial input of via other keyboard input systems.
; 0=ignore key
; 1=expand as soft key
; 2-FF add to base for ASCII code
D9AD DB &01 ; C0-&CF &26D *FX221
D9AE DB &D0 ; D0-&DF &26E *FX222
D9AF DB &E0 ; E0-&EF &26F *FX223
D9B0 DB &F0 ; F0-&FF &270 *FX224
D9B1 DB &01 ; 80-&8F function key &271 *FX225
D9B2 DB &80 ; 90-&9F Shift+function key &272 *FX226
D9B3 DB &90 ; A0-&AF Ctrl+function key &273 *FX227
D9B4 DB &00 ; B0-&BF Shift+Ctrl+function key &274 *FX228
D9B5 DB &00 ; ESCAPE key status (0=ESC, 1=ASCII) &275 *FX229
D9B6 DB &00 ; ESCAPE action &276 *FX230
D9B7 DB &FF ; USER 6522 Bit IRQ mask &277 *FX231
D9B8 DB &FF ; 6850 ACIA Bit IRQ bit mask &278 *FX232
D9B9 DB &FF ; System 6522 IRQ bit mask &279 *FX233
D9BA DB &00 ; Tube prescence flag &27A *FX234
D9BB DB &00 ; Speech processor prescence flag &27B *FX235
D9BC DB &00 ; Character destination status &27C *FX236
D9BD DB &00 ; Cursor editing status &27D *FX237
****************** Soft Reset high water mark ***************************
D9BE DB &00 ; unused &27E *FX238
D9BF DB &00 ; unused &27F *FX239
D9C0 DB &00 ; Country code &280 *FX240
D9C1 DB &00 ; User flag &281 *FX241
D9C2 DB &64 ; Serial ULA control register copy &282 *FX242
D9C3 DB &05 ; Current system clock state &283 *FX243
D9C4 DB &FF ; Soft key consitancy flag &284 *FX244
D9C5 DB &01 ; Printer destination &285 *FX245
D9C6 DB &0A ; Printer ignore character &286 *FX246
****************** Hard Reset High water mark ***************************
D9C7 DB &00 ; Break Intercept Vector JMP opcode &288 *FX247
D9C8 DB &00 ; Break Intercept Vector address low &288 *FX248
D9C9 DB &00 ; Break Intercept Vector address high &289 *FX249
D9CA DB &00 ; unused (memory used for VDU) &28A *FX250
D9CB DB &00 ; unused (memory used for display) &28B *FX251
D9CC DB &FF ; Current language ROM number &28C *FX252
****************** Power-On Reset High Water mark ***********************
**************************************************************************
**************************************************************************
** **
** RESET (BREAK) ENTRY POINT **
** **
** Power up Enter with nothing set, 6522 System VIA IER bits **
** 0 to 6 will be clear **
** **
** BREAK IER bits 0 to 6 one or more will be set 6522 IER **
** not reset by BREAK **
** **
**************************************************************************
**************************************************************************
D9CD LDA #&40 ;set NMI first instruction to RTI
D9CF STA &0D00 ;NMI ram start
D9D2 SEI ;disable interrupts just in case
D9D3 CLD ;clear decimal flag
D9D4 LDX #&FF ;reset stack to where it should be
D9D6 TXS ;(&1FF)
D9D7 LDA &FE4E ;read interupt enable register of the system VIA
D9DA ASL ;shift bit 7 into carry
D9DB PHA ;save what's left
D9DC BEQ &D9E7 ;if Power up A=0 so D9E7
D9DE LDA &0258 ;else if BREAK pressed read BREAK Action flags (set by
;*FX200,n)
D9E1 LSR ;divide by 2
D9E2 CMP #&01 ;if (bit 1 not set by *FX200)
D9E4 BNE &DA03 ;then &DA03
D9E6 LSR ;divide A by 2 again (A=0 if *FX200,2/3 else A=n/4
********** clear memory routine ******************************************
D9E7 LDX #&04 ;get page to start clearance from (4)
D9E9 STX &01 ;store it in ZP 01
D9EB STA &00 ;store A at 00
D9ED TAY ;and in Y to set loop counter
D9EE STA (&00),Y ;clear store
D9F0 CMP &01 ;until address &01 =0
D9F2 BEQ &D9FD ;
D9F4 INY ;increment pointer
D9F5 BNE &D9EE ;if not zero loop round again
D9F7 INY ;else increment again (Y=1) this avoids overwriting
;RTI instruction at &D00
D9F8 INX ;increment X
D9F9 INC &01 ;increment &01
D9FB BPL &D9EE ;loop until A=&80 then exit
;note that RAM addressing for 16k loops around so
;&4000=&00 hence checking &01 for 00. This avoids
;overwriting zero page on BREAK
D9FD STX &028E ;writes marker for available RAM 40 =16k,80=32
DA00 STX &0284 ;write soft key consistency flag
**+********** set up system VIA *****************************************
DA03 LDX #&0F ;set PORT B to output on bits 0-3 Input 4-7
DA05 STX &FE42 ;
*************************************************************************
* *
* set addressable latch IC 32 for peripherals via PORT B *
* *
* ;bit 3 set sets addressed latch high adds 8 to VIA address *
* ;bit 3 reset sets addressed latch low *
* *
* Peripheral VIA bit 3=0 VIA bit 3=1 *
* *
* Sound chip Enabled Disabled *
* speech chip (RS) Low High *
* speech chip (WS) Low High *
* Keyboard Auto Scan Disabled Enabled *
* C0 address modifier Low High *
* C1 address modifier Low High *
* Caps lock LED ON OFF *
* Shift lock LED ON OFF *
* *
* C0 & C1 are involved with hardware scroll screen address *
*************************************************************************
;X=&F on entry
DA08 DEX ;loop start
DA09 STX &FE40 ;write latch IC32
DA0C CPX #&09 ;is it 9
DA0E BCS &DA08 ;if so go back and do it again
;X=8 at this point
;Caps lock On, SHIFT lock undetermined
;Keyboard Autoscan on
;sound disabled (may still sound)
DA10 INX ;X=9
DA11 TXA ;A=X
DA12 JSR &F02A ;interrogate keyboard
DA15 CPX #&80 ;for keyboard links 9-2 and CTRL key (1)
DA17 ROR &FC ;rotate MSB into bit 7 of &FC
DA19 TAX ;get back value of X for loop
DA1A DEX ;decrement it
DA1B BNE &DA11 ;and if >0 do loop again
; on exit if Carry set link 3 made
;link 2 = bit 0 of &FC and so on
;if CTRL pressed bit 7 of &FC=1
;X=0
DA1D STX &028D ;clear last BREAK flag
DA20 ROL &FC ;CTRL is now in carry &FC is keyboard links
DA22 JSR &EEEB ;set LEDs carry on entry bit 7 of A on exit
DA25 ROR ;get carry back into carry flag
****** set up page 2 ****************************************************
DA26 LDX #&9C ;
DA28 LDY #&8D ;
DA2A PLA ;get back A from &D9DB
DA2B BEQ &DA36 ;if A=0 power up reset so DA36 with X=&9C Y=&8D
DA2D LDY #&7E ;else Y=&7E
DA2F BCC &DA42 ;and if not CTRL-BREAK DA42 WARM RESET
DA31 LDY #&87 ;else Y=&87 COLD RESET
DA33 INC &028D ;&28D=1
DA36 INC &028D ;&28D=&28D+1
DA39 LDA &FC ;get keyboard links set
DA3B EOR #&FF ;invert
DA3D STA &028F ;and store at &28F
DA40 LDX #&90 ;X=&90
**********: set up page 2 *************************************************
;on entry &28D=0 Warm reset, X=&9C, Y=&7E
;&28D=1 Power up , X=&90, Y=&8D
;&28D=2 Cold reset, X=&9C, Y=&87
DA42 LDA #&00 ;A=0
DA44 CPX #&CE ;zero &200+X to &2CD
DA46 BCC &DA4A ;
DA48 LDA #&FF ;then set &2CE to &2FF to &FF
DA4A STA &0200,X ;
DA4D INX ;
DA4E BNE &DA44 ;
;A=&FF X=0
DA50 STA &FE63 ;set port A of user via to all outputs (printer out)
DA53 TXA ;A=0
DA54 LDX #&E2 ;X=&E2
DA56 STA &00,X ;zero zeropage &E2 to &FF
DA58 INX ;
DA59 BNE &DA56 ;X=0
DA5B LDA &D93F,Y ;copy data from &D93F+Y
DA5E STA &01FF,Y ;to &1FF+Y
DA61 DEY ;until
DA62 BNE &DA5B ;1FF+Y=&200
DA64 LDA #&62 ;A=&62
DA66 STA &ED ;store in &ED
DA68 JSR &FB0A ;set up ACIA
;X=0
************** clear interrupt and enable registers of Both VIAs ********
DA6B LDA #&7F ;
DA6D INX ;
DA6E STA &FE4D,X ;
DA71 STA &FE6D,X ;
DA74 DEX ;
DA75 BPL &DA6E ;
DA77 CLI ;briefly allow interrupts to clear anything pending
DA78 SEI ;disallow again N.B. All VIA IRQs are disabled
DA79 BIT &FC ;if bit 6=1 then JSR &F055 (normally 0)
DA7B BVC &DA80 ;else DA80
DA7D JSR &F055 ;F055 JMP (&FDFE) probably causes a BRK unless
;hardware there redirects it.
;
DA80 LDX #&F2 ;enable interrupts 1,4,5,6 of system VIA
DA82 STX &FE4E ;
;0 Keyboard enabled as needed
;1 Frame sync pulse
;4 End of A/D conversion
;5 T2 counter (for speech)
;6 T1 counter (10 mSec intervals)
;
DA85 LDX #&04 ;set system VIA PCR
DA87 STX &FE4C ;
;CA1 to interrupt on negative edge (Frame sync)
;CA2 Handshake output for Keyboard
;CB1 interrupt on negative edge (end of conversion)
;CB2 Negative edge (Light pen strobe)
;
DA8A LDA #&60 ;set system VIA ACR
DA8C STA &FE4B ;
;disable latching
;disable shift register
;T1 counter continuous interrupts
;T2 counter timed interrupt
DA8F LDA #&0E ;set system VIA T1 counter (Low)
DA91 STA &FE46 ;
;this becomes effective when T1 hi set
DA94 STA &FE6C ;set user VIA PCR
;CA1 interrupt on -ve edge (Printer Acknowledge)
;CA2 High output (printer strobe)
;CB1 Interrupt on -ve edge (user port)
;CB2 Negative edge (user port)
DA97 STA &FEC0 ;set up A/D converter
;Bits 0 & 1 determine channel selected
;Bit 3=0 8 bit conversion bit 3=1 12 bit
DA9A CMP &FE6C ;read user VIA IER if = &0E then DAA2 chip present
DA9D BEQ &DAA2 ;so goto DAA2
DA9F INC &0277 ;else increment user VIA mask to 0 to bar all
;user VIA interrupts
DAA2 LDA #&27 ;set T1 (hi) to &27 this sets T1 to &270E (9998 uS)
DAA4 STA &FE47 ;or 10msec, interrupts occur every 10msec therefore
DAA7 STA &FE45 ;
DAAA JSR &EC60 ;clear the sound channels
DAAD LDA &0282 ;read serial ULA control register
DAB0 AND #&7F ;zero bit 7
DAB2 JSR &E6A7 ;and set up serial ULA
DAB5 LDX &0284 ;get soft key status flag
DAB8 BEQ &DABD ;if 0 (keys OK) then DABD
DABA JSR &E9C8 ;else reset function keys
*************************************************************************
* *
* Check sideways ROMS and make rom list *
* *
*************************************************************************
;X=0
DABD JSR &DC16 ;set up ROM latch and RAM copy to X
DAC0 LDX #&03 ;set X to point to offset in table
DAC2 LDY &8007 ;get copyright offset from ROM
; DF0C = ")C(",0
DAC5 LDA &8000,Y ;get first byte
DAC8 CMP &DF0C,X ;compare it with table byte
DACB BNE &DAFB ;if not the same then goto DAFB
DACD INY ;point to next byte
DACE DEX ;(s)
DACF BPL &DAC5 ;and if still +ve go back to check next byte
;this point is reached if 5 bytes indicate valid
;ROM (offset +4 in (C) string)
*************************************************************************
* Check first 1k of each ROM against higher priority Roms to ensure that*
* there are no matches, if a match found ignore lower priority ROM *
*************************************************************************
DAD1 LDX &F4 ;get RAM copy of ROM No. in X
DAD3 LDY &F4 ;and Y
DAD5 INY ;increment Y to check
DAD6 CPY #&10 ;if ROM 15 is current ROM
DAD8 BCS &DAFF ;if equal or more than 16 goto &DAFF
;to store catalogue byte
DADA TYA ;else put Y in A
DADB EOR #&FF ;invert it
DADD STA &FA ;and store at &FA
DADF LDA #&7F ;store &7F at
DAE1 STA &FB ;&FB to get address &7FFF-Y
DAE3 STY &FE30 ;set new ROM
DAE6 LDA (&FA),Y ;Get byte
DAE8 STX &FE30 ;switch back to previous ROM
DAEB CMP (&FA),Y ;and compare with previous byte called
DAED BNE &DAD5 ;if not the same then go back and do it again
;with next rom up
DAEF INC &FA ;else increment &FA to point to new location
DAF1 BNE &DAE3 ;if &FA<>0 then check next byte
DAF3 INC &FB ;else inc &FB
DAF5 LDA &FB ;and check that it doesn't exceed
DAF7 CMP #&84 ;&84 (1k checked)
DAF9 BCC &DAE3 ;then check next byte(s)
DAFB LDX &F4 ;X=(&F4)
DAFD BPL &DB0C ;if +ve then &DB0C
DAFF LDA &8006 ;get rom type
DB02 STA &02A1,X ;store it in catalogue
DB05 AND #&8F ;check for BASIC (bit 7 not set)
DB07 BNE &DB0C ;if not BASIC the DB0C
DB09 STX &024B ;else store X at BASIC pointer
DB0C INX ;increment X to point to next ROM
DB0D CPX #&10 ;is it 15 or less
DB0F BCC &DABD ;if so goto &DABD for next ROM
OS SERIES V
GEOFF COX
*************************************************************************
* *
* Check SPEECH System *
* *
*************************************************************************
;X=&10
DB11 BIT &FE40 ;if bit 7 low then we have speech system fitted
DB14 BMI &DB27 ;else goto DB27
DB16 DEC &027B ;(027B)=&FF to indicate speech present
DB19 LDY #&FF ;Y=&FF
DB1B JSR &EE7F ;initialise speech generator
DB1E DEX ;via this
DB1F BNE &DB19 ;loop
;X=0
DB21 STX &FE48 ;set T2 timer for speech
DB24 STX &FE49 ;
*********** SCREEN SET UP **********************************************
;X=0
DB27 LDA &028F ;get back start up options (mode)
DB2A JSR &C300 ;then jump to screen initialisation
DB2D LDY #&CA ;Y=&CA
DB2F JSR &E4F1 ;to enter this in keyboard buffer
;this enables the *KEY 10 facility
********* enter BREAK intercept with Carry Clear ************************
DB32 JSR &EAD9 ;check to see if BOOT address is set up, if so
;JMP to it
DB35 JSR &F140 ;set up cassette options
DB38 LDA #&81 ;test for tube to FIFO buffer 1
DB3A STA &FEE0 ;
DB3D LDA &FEE0 ;
DB40 ROR ;put bit 0 into carry
DB41 BCC &DB4D ;if no tube then DB4D
DB43 LDX #&FF ;else
DB45 JSR &F168 ;issue ROM service call &FF
;to initialise TUBE system
DB48 BNE &DB4D ;if not 0 on exit (Tube not initialised) DB4D
DB4A DEC &027A ;else set tube flag to show it's active
DB4D LDY #&0E ;set current value of PAGE
DB4F LDX #&01 ;issue claim absolute workspace call
DB51 JSR &F168 ;via F168
DB54 LDX #&02 ;send private workspace claim call
DB56 JSR &F168 ;via F168
DB59 STY &0243 ;set primary OSHWM
DB5C STY &0244 ;set current OSHWM
DB5F LDX #&FE ;issue call for Tube to explode character set etc.
DB61 LDY &027A ;Y=FF if tube present else Y=0
DB64 JSR &F168 ;and make call via F168
DB67 AND &0267 ;if A=&FE and bit 7 of 0267 is set then continue
DB6A BPL &DB87 ;else ignore start up message
DB6C LDY #&02 ;output to screen
DB6E JSR &DEA9 ;'BBC Computer ' message
DB71 LDA &028D ;0=warm reset, anything else continue
DB74 BEQ &DB82 ;
DB76 LDY #&16 ;by checking length of RAM
DB78 BIT &028E ;
DB7B BMI &DB7F ;and either
DB7D LDY #&11 ;
DB7F JSR &DEA9 ;finishing message with '16k' or '32k'
DB82 LDY #&1B ;and two newlines
DB84 JSR &DEA9 ;
*********: enter BREAK INTERCEPT ROUTINE WITH CARRY SET (call 1)
DB87 SEC ;
DB88 JSR &EAD9 ;look for break intercept jump do *TV etc
DB8B JSR &E9D9 ;set up LEDs in accordance with keyboard status
DB8E PHP ;save flags
DB8F PLA ;and get back in A
DB90 LSR ;zero bits 4-7 and bits 0-2 bit 4 which was bit 7
DB91 LSR ;may be set
DB92 LSR ;
DB93 LSR ;
DB94 EOR &028F ;eor with start-up options which may or may not
DB97 AND #&08 ;invert bit 4
DB99 TAY ;Y=A
DB9A LDX #&03 ;make fs initialisation call, passing boot option in Y
DB9C JSR &F168 ;Eg, RUN, EXEC or LOAD !BOOT file
DB9F BEQ &DBBE ;if a ROM accepts this call then DBBE
DBA1 TYA ;else put Y in A
DBA2 BNE &DBB8 ;if Y<>0 DBB8
DBA4 LDA #&8D ;else set up standard cassete baud rates
DBA6 JSR &F135 ;via &F135
DBA9 LDX #&D2 ;
DBAB LDY #&EA ;
DBAD DEC &0267 ;decrement ignore start up message flag
DBB0 JSR OSCLI ;and execute */!BOOT
DBB3 INC &0267 ;restore start up message flag
DBB6 BNE &DBBE ;if not zero then DBBE
DBB8 LDA #&00 ;else A=0
DBBA TAX ;X=0
DBBB JSR &F137 ;set tape speed
******** Preserve current language on soft RESET ************************
DBBE LDA &028D ;get last RESET Type
DBC1 BNE &DBC8 ;if not soft reset DBC8
DBC3 LDX &028C ;else get current language ROM address
DBC6 BPL &DBE6 ;if +ve (language available) then skip search routine
*************************************************************************
* *
* SEARCH FOR LANGUAGE TO ENTER (Highest priority) *
* *
*************************************************************************
DBC8 LDX #&0F ;set pointer to highest available rom
DBCA LDA &02A1,X ;get rom type from map
DBCD ROL ;put hi-bit into carry, bit 6 into bit 7
DBCE BMI &DBE6 ;if bit 7 set then ROM has a language entry so DBE6
DBD0 DEX ;else search for language until X=&ff
DBD1 BPL &DBCA ;
*************** check if tube present ***********************************
DBD3 LDA #&00 ;if bit 7 of tube flag is set BMI succeeds
DBD5 BIT &027A ;and TUBE is connected else
DBD8 BMI &DC08 ;make error
********* no language error ***********************************************
DBDA BRK ;
DBDB DB &F9 ;error number
DBDC DB 'Language?' ;message
DBE5 BRK ;
DBE6 CLC ;
*************************************************************************
* *
* OSBYTE 142 - ENTER LANGUAGE ROM AT &8000 *
* *
* X=rom number C set if OSBYTE call clear if initialisation *
* *
*************************************************************************
DBE7 PHP ;save flags
DBE8 STX &028C ;put X in current ROM page
DBEB JSR &DC16 ;select that ROM
DBEE LDA #&80 ;A=128
DBF0 LDY #&08 ;Y=8
DBF2 JSR &DEAB ;display text string held in ROM at &8008,Y
DBF5 STY &FD ;save Y on exit (end of language string)
DBF7 JSR OSNEWL ;two line feeds
DBFA JSR OSNEWL ;are output
DBFD PLP ;then get back flags
DBFE LDA #&01 ;A=1 required for language entry
DC00 BIT &027A ;check if tube exists
DC03 BMI &DC08 ;and goto DC08 if it does
DC05 JMP &8000 ;else enter language at &8000
*************************************************************************
* *
* TUBE FOUND, ENTER TUBE SOFTWARE *
* *
*************************************************************************
DC08 JMP &0400 ;enter tube environment
*************************************************************************
* *
* OSRDRM entry point *
* *
* get byte from PHROM or page ROM *
* Y= rom number, address is in &F6/7 *
*************************************************************************
DC0B LDX &F4 ;get current ROM number into X
DC0D STY &F4 ;store new number in &F4
DC0F STY &FE30 ;switch in ROM
DC12 LDY #&00 ;get current PHROM address
DC14 LDA (&F6),Y ;and get byte
******** Set up Sideways Rom latch and RAM copy *************************
;on entry X=ROM number
DC16 STX &F4 ;RAM copy of rom latch
DC18 STX &FE30 ;write to rom latch
DC1B RTS ;and return
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/DC1C b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/DC1C new file mode 100644 index 0000000..b319f77 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/DC1C @@ -0,0 +1 @@ +**************************************************************************
**************************************************************************
** **
** MAIN IRQ Entry point **
** **
** **
**************************************************************************
**************************************************************************
;ON ENTRY STACK contains STATUS REGISTER,PCH,PCL ;
DC1C STA &FC ;save A
DC1E PLA ;get back status (flags)
DC1F PHA ;and save again
DC20 AND #&10 ;check if BRK flag set
DC22 BNE &DC27 ;if so goto DC27
DC24 JMP (&0204) ;else JMP (IRQ1V)
*************************************************************************
* *
* BRK handling routine *
* *
*************************************************************************
DC27 TXA ;save X on stack
DC28 PHA ;
DC29 TSX ;get status pointer
DC2A LDA &0103,X ;get Program Counter lo
DC2D CLD ;
DC2E SEC ;set carry
DC2F SBC #&01 ;subtract 2 (1+carry)
DC31 STA &FD ;and store it in &FD
DC33 LDA &0104,X ;get hi byte
DC36 SBC #&00 ;subtract 1 if necessary
DC38 STA &FE ;and store in &FE
DC3A LDA &F4 ;get currently active ROM
DC3C STA &024A ;and store it in &24A
DC3F STX &F0 ;store stack pointer in &F0
DC41 LDX #&06 ;and issue ROM service call 6
DC43 JSR &F168 ;(User BRK) to roms
;at this point &FD/E point to byte after BRK
;ROMS may use BRK for their own purposes
DC46 LDX &028C ;get current language
DC49 JSR &DC16 ;and activate it
DC4C PLA ;get back original value of X
DC4D TAX ;
DC4E LDA &FC ;get back original value of A
DC50 CLI ;allow interrupts
DC51 JMP (&0202) ;and JUMP via BRKV (normally into current language)
*************************************************************************
* *
* DEFAULT BRK HANDLER *
* *
*************************************************************************
DC54 LDY #&00 ;Y=0 to point to byte after BRK
DC56 JSR &DEB1 ;print message
DC59 LDA &0267 ;if BIT 0 set and DISC EXEC error
DC5C ROR ;occurs
DC5D BCS &DC5D ;hang up machine!!!!
DC5F JSR OSNEWL ;else print two newlines
DC62 JSR OSNEWL ;
DC65 JMP &DBB8 ;and set tape speed before entering current
;language
; ACIA IRQ, RxRDY but both Serial and Printer buffers empty
; ---------------------------------------------------------
DC68 SEC
DC69 ROR &024F ; Set b7 of RS423 busy flag
DC6C BIT &0250 ;check bit 7 of current ACIA control register
DC6F BPL &DC78 ;if interrupts NOT enabled DC78
DC71 JSR &E741 ;else E741 to check if serial buffer full
DC74 LDX #&00 ; X=&00 to set RTS low
DC76 BCS &DC7A ;if carry set goto DC7A to transfer data
DC78 LDX #&40 ; X=&40 to set RTS high
DC7A JMP &E17A ; Jump to set ACIA control register
; Serial IRQ and RxRDY - Get byte and store in serial buffer
; ----------------------------------------------------------
DC7D LDY &FE09 ; Read data from ACIA
DC80 AND #&3A ; Check PE:RO:FE:DCD
DC82 BNE &DCB8 ; If any set, jump to generate Serial Error Event
; Serial IRQ and RxRDY, no errors
; -------------------------------
DC84 LDX &025C ; Read RS423 input suppression flag
DC87 BNE &DC92 ; If not 0, jump to ignore
DC89 INX ; X=1, serial input buffer
DC8A JSR &E4F3 ; Put byte in buffer
DC8D JSR &E741 ; Check if serial buffer almost full
DC90 BCC &DC78 ; If almost full, jump to set RTS high
DC92 RTS ; Return
*************************************************************************
* *
* Main IRQ Handling routines, default IRQ1V destination *
* *
*************************************************************************
DC93 CLD ; Clear decimal flag
DC94 LDA &FC ; Get original value of A
DC96 PHA ; Save it
DC97 TXA ; Save X
DC98 PHA ;
DC99 TYA ; and Y
DC9A PHA ;
DC9B LDA #&DE ; Stack return address to &DE82
DC9D PHA
DC9E LDA #&81
DCA0 PHA
DCA1 CLV ; Clear V flag
DCA2 LDA &FE08 ; Read ACIA status register
DCA5 BVS &DCA9 ; b6 set, jump with serial parity error
DCA7 BPL &DD06 ; b7=0, no ACIA interrupt, jump to check VIAs
; ACIA Interrupt or ACIA Parity Error
; -----------------------------------
DCA9 LDX &EA ; Get RS423 timeout counter
DCAB DEX ; Decrement it
DCAC BMI &DCDE ; If 0 or <0, RS423 owns 6850, jump to DCDE
DCAE BVS &DCDD ; If &41..&80, nobody owns 6850, jump to exit
DCB0 JMP &F588 ; CFS owns 6850, jump to read ACIA in CFS routines
; ACIA Data Carrier Detect
; ------------------------
DCB3 LDY &FE09 ; Read ACIA data
DCB6 ROL A ;
DCB7 ASL A ; Rotate ACIA Status back
DCB8 TAX ; X=ACIA Status
DCB9 TYA ; A=ACIA Data
DCBA LDY #&07 ; Y=07 for RS423 Error Event
DCBC JMP &E494 ; Jump to issue event
; ACIA IRQ, TxRDY - Send a byte
; -----------------------------
DCBF LDX #&02
DCC1 JSR &E460 ; Read from Serial output buffer
DCC4 BCC &DCD6 ; Buffer is not empty, jump to send byte
DCC6 LDA &0285 ; Read printer destination
DCC9 CMP #&02 ; Is it serial printer??
DCCB BNE &DC68 ; Serial buffer empty, not Serial printer, jump to ... DC68
DCCD INX ; X=3 for Printer buffer
DCCE JSR &E460 ; Read from Printer buffer
DCD1 ROR &02D2 ; Copy Byte Fetched/Not fetched into Printer Buffer full flag
DCD4 BMI &DC68 ; Printer buffer was empty, so jump to ... DC68
DCD6 STA &FE09 ; Send byte to ACIA
DCD9 LDA #&E7 ; Set timeout counter to &E7
DCDB STA &EA ; Serial owns 6850 for 103 more calls
DCDD RTS ; Exit IRQ
; RS423 owns 6850, PE or RxRDY interupt occured
; ---------------------------------------------
; On entry, A contains ACIA status
;
DCDE AND &0278 ; AND with ACIA IRQ mask (normally &FF)
DCE1 LSR A ; Move RxRDY into Carry
DCE2 BCC &DCEB ; If no RxData, jump to check DCD and TxRDY
;
; Data in RxData, check for errors
;
DCE4 BVS &DCEB ; If IRQ=1 (now in b6) RxIRQ must have occured, so jump to DCEB
;
; RxData but no RxIRQ, check that IRQs are actually disabled
;
DCE6 LDY &0250 ; Get ACIA control setting
DCE9 BMI &DC7D ; If bit 7=1, IRQs enabled so jump to read byte and insert into buffer
;
; DCE9 -> RxData, no RxIRQ, IRQs disabled
; DCE4 -> RxData and RxIRQ
; DCE2 -> No RxData
;
; Check TxRDY and DCD, if neither set, send a Serial Error Event
; --------------------------------------------------------------
DCEB LSR A ; Move TxRDY into Carry
DCEC ROR A ; Rotate TxRDY into b7 and DCD into Carry
DCED BCS &DCB3 ; If Data Carrier Detected, jump to DCB3
DCEF BMI &DCBF ; If TxRDY (now in b7) jump to to DCBF to send a byte
DCF1 BVS &DCDD ; b6 should always be zero by now, but if set, then jump to exit
; Issue Unknown Interupt service call
; ===================================
DCF3 LDX #&05
DCF5 JSR &F168 ; Issue service call 5, 'Unknown Interrupt'
DCF8 BEQ &DCDD ; If claimed, then jump to exit
DCFA PLA ; Otherwise drop return address from stack
DCFB PLA ;
DCFC PLA ; And restore registers
DCFD TAY ;
DCFE PLA ;
DCFF TAX ;
DD00 PLA ;
DD01 STA &FC ; Store A in IRQA
DD03 JMP (&0206) ; And pass the IRQ in to IRQ2V
*************************************************************************
* *
* VIA INTERUPTS ROUTINES *
* *
*************************************************************************
DD06 LDA &FE4D ; Read System VIA interrupt flag register
DD09 BPL &DD47 ; No System VIA interrupt, jump to check User VIA
; System VIA interupt
;
DD0B AND &0279 ; Mask with System VIA bit mask
DD0E AND &FE4E ; and interrupt enable register
DD11 ROR ; Rotate to check for CA1 interupt (frame sync)
DD12 ROR ;
DD13 BCC &DD69 ; No CA1 (frame sync), jump to check speech
; System VIA CA1 interupt (Frame Sync)
;
DD15 DEC &0240 ;decrement vertical sync counter
DD18 LDA &EA ;A=RS423 Timeout counter
DD1A BPL &DD1E ;if +ve then DD1E
DD1C INC &EA ;else increment it
DD1E LDA &0251 ;load flash counter
DD21 BEQ &DD3D ;if 0 then system is not in use, ignore it
DD23 DEC &0251 ;else decrement counter
DD26 BNE &DD3D ;and if not 0 go on past reset routine
DD28 LDX &0252 ;else get mark period count in X
DD2B LDA &0248 ;current VIDEO ULA control setting in A
DD2E LSR ;shift bit 0 into C to check if first colour
DD2F BCC &DD34 ;is effective if so C=0 jump to DD34
DD31 LDX &0253 ;else get space period count in X
DD34 ROL ;restore bit
DD35 EOR #&01 ;and invert it
DD37 JSR &EA00 ;then change colour
DD3A STX &0251 ;&0251=X resetting the counter
DD3D LDY #&04 ;Y=4 and call E494 to check and implement vertical
DD3F JSR &E494 ;sync event (4) if necessary
DD42 LDA #&02 ;A=2
DD44 JMP &DE6E ;clear interrupt 1 and exit
*************************************************************************
* *
* PRINTER INTERRUPT USER VIA 1 *
* *
*************************************************************************
DD47 LDA &FE6D ; Read User VIA interrupt flag register
DD4A BPL &DCF3 ; No User VIA interrupt, jump to pass to ROMs
; User VIA interupt
;
DD4C AND &0277 ;else check for USER IRQ 1
DD4F AND &FE6E ;
DD52 ROR ;
DD53 ROR ;
DD54 BCC &DCF3 ;if bit 1=0 the no interrupt 1 so DCF3
DD56 LDY &0285 ;else get printer type
DD59 DEY ;decrement
DD5A BNE &DCF3 ;if not parallel then DCF3
DD5C LDA #&02 ;reset interrupt 1 flag
DD5E STA &FE6D ;
DD61 STA &FE6E ;disable interrupt 1
DD64 LDX #&03 ;and output data to parallel printer
DD66 JMP &E13A ;
*************************************************************************
* *
* SYSTEM INTERRUPT 5 Speech *
* *
*************************************************************************
DD69 ROL ; Rotate bit 5 into bit 7
DD6A ROL ;
DD6B ROL ;
DD6C ROL ;
DD6D BPL &DDCA ; Not a Timer 2 interrupt, jump to check timers
; System VIA Timer 2 interupt - Speech interupt
;
DD6F LDA #&20 ; Prepare to clear VIA interupt
DD71 LDX #&00
DD73 STA &FE4D ; Clear VIA interupt
DD76 STX &FE49 ; Zero high byte of T2 Timer
DD79 LDX #&08 ; X=8 for Speech buffer
DD7B STX &FB ; Prepare to loop up to four times for Speak from RAM
;
DD7D JSR &E45B ; Examine Speech buffer
DD80 ROR &02D7 ; Shift carry into bit 7
DD83 BMI &DDC9 ; Buffer empty, so exit
DD85 TAY ; Buffer not empty, A=first byte waiting
DD86 BEQ &DD8D ; Waiting byte=&00 (Speak, no reset), skip past
DD88 JSR &EE6D ;control speech chip
DD8B BMI &DDC9 ;if negative exit
DD8D JSR &E460 ; Fetch Speech command byte from buffer
DD90 STA &F5 ; Store it
DD92 JSR &E460 ; Fetch Speech word high byte from buffer
DD95 STA &F7 ; Store it
DD97 JSR &E460 ; Fetch Speech word low byte from buffer
DD9A STA &F6 ; Store it, giving &F6/7=address to be accessed
DD9C LDY &F5 ; Y=Speech command byte
DD9E BEQ &DDBB ; SOUND &FF00 - Speak from RAM, no reset
DDA0 BPL &DDB8 ; SOUND &FF01-&FF7F - Speak from RAM, with reset
DDA2 BIT &F5 ; Check bit 6 of Speech command
DDA4 BVS &DDAB ; SOUND &FFC0-&FFFF - Speak word number
; SOUND &FF80-&FFBF - Speak from absolute address
; &F5=command &80-&BF (b0-b3=PHROM number), &F6/7=address
;
DDA6 JSR &EEBB ; Write address to speech processor
DDA9 BVC &DDB2 ; Skip forward to speak from selected address
; SOUND &FFC0-&FFFF - Speak word number
; &F5=command &C0-&FF (b0-b3=PHROM number), &F6/7=word number
;
DDAB ASL &F6 ; Multiply address by 2 to index into word table
DDAD ROL &F7 ;
DDAF JSR &EE3B ; Read address from specified PHROM
; Speak from PHROM address
; By now, the address in the PHROM specified in Command b0-b3 has been set
; to the start of the speech data to be voiced.
;
DDB2 LDY &0261 ; Fetch command code, usually &50=Speak or &00=Nop
DDB5 JMP &EE7F ; Jump to send command to speak from current address
; SOUND &FF01-&FF7F - Speak from RAM with reset
; Y=Speech command byte, &F6/7=Speech data
; Use SOUND &FF60 to send Speak External command
;
DDB8 JSR &EE7F ; Send command byte to Speech processor
; SOUND &FF00 - Speak from RAM without reset
; &6/7=Speech data
;
DDBB LDY &F6
DDBD JSR &EE7F ; Send Speech data low byte
DDC0 LDY &F7
DDC2 JSR &EE7F ; Send Speech data high byte
DDC5 LSR &FB ; Shift loop counter
DDC7 BNE &DD7D ; Loop to send up to four byte-pairs
DDC9 RTS
***********************************************************************
* *
* SYSTEM INTERRUPT 6 10mS Clock *
* *
*************************************************************************
DDCA BCC &DE47 ;bit 6 is in carry so if clear there is no 6 int
;so go on to DE47
DDCC LDA #&40 ;Clear interrupt 6
DDCE STA &FE4D ;
;UPDATE timers routine, There are 2 timer stores &292-6 and &297-B
;these are updated by adding 1 to the current timer and storing the
;result in the other, the direction of transfer being changed each
;time of update. This ensures that at least 1 timer is valid at any call
;as the current timer is only read. Other methods would cause inaccuracies
;if a timer was read whilst being updated.
DDD1 LDA &0283 ;get current system clock store pointer (5,or 10)
DDD4 TAX ;put A in X
DDD5 EOR #&0F ;and invert lo nybble (5 becomes 10 and vv)
DDD7 PHA ;store A
DDD8 TAY ;put A in Y
;Carry is always set at this point
DDD9 LDA &0291,X ;get timer value
DDDC ADC #&00 ;update it
DDDE STA &0291,Y ;store result in alternate
DDE1 DEX ;decrement X
DDE2 BEQ &DDE7 ;if 0 exit
DDE4 DEY ;else decrement Y
DDE5 BNE &DDD9 ;and go back and do next byte
DDE7 PLA ;get back A
DDE8 STA &0283 ;and store back in clock pointer (i.e. inverse previous
;contents)
DDEB LDX #&05 ;set loop pointer for countdown timer
DDED INC &029B,X ;increment byte and if
DDF0 BNE &DDFA ;not 0 then DDFA
DDF2 DEX ;else decrement pointer
DDF3 BNE &DDED ;and if not 0 do it again
DDF5 LDY #&05 ;process EVENT 5 interval timer
DDF7 JSR &E494 ;
DDFA LDA &02B1 ;get byte of inkey countdown timer
DDFD BNE &DE07 ;if not 0 then DE07
DDFF LDA &02B2 ;else get next byte
DE02 BEQ &DE0A ;if 0 DE0A
DE04 DEC &02B2 ;decrement 2B2
DE07 DEC &02B1 ;and 2B1
DE0A BIT &02CE ;read bit 7 of envelope processing byte
DE0D BPL &DE1A ;if 0 then DE1A
DE0F INC &02CE ;else increment to 0
DE12 CLI ;allow interrupts
DE13 JSR &EB47 ;and do routine sound processes
DE16 SEI ;bar interrupts
DE17 DEC &02CE ;DEC envelope processing byte back to 0
DE1A BIT &02D7 ;read speech buffer busy flag
DE1D BMI &DE2B ;if set speech buffer is empty, skip routine
DE1F JSR &EE6D ;update speech system variables
DE22 EOR #&A0 ;
DE24 CMP #&60 ;
DE26 BCC &DE2B ;if result >=&60 DE2B
DE28 JSR &DD79 ;else more speech work
DE2B BIT &D9B7 ;set V and C
DE2E JSR &DCA2 ;check if ACIA needs attention
DE31 LDA &EC ;check if key has been pressed
DE33 ORA &ED ;
DE35 AND &0242 ;(this is 0 if keyboard is to be ignored, else &FF)
DE38 BEQ &DE3E ;if 0 ignore keyboard
DE3A SEC ;else set carry
DE3B JSR &F065 ;and call keyboard
DE3E JSR &E19B ;check for data in user defined printer channel
DE41 BIT &FEC0 ;if ADC bit 6 is set ADC is not busy
DE44 BVS &DE4A ;so DE4A
DE46 RTS ;else return
;
*************************************************************************
* *
* SYSTEM INTERRUPT 4 ADC end of conversion *
* *
*************************************************************************
DE47 ROL ;put original bit 4 from FE4D into bit 7 of A
DE48 BPL &DE72 ;if not set DE72
DE4A LDX &024C ;else get current ADC channel
DE4D BEQ &DE6C ;if 0 DE6C
DE4F LDA &FEC2 ;read low data byte
DE52 STA &02B5,X ;store it in &2B6,7,8 or 9
DE55 LDA &FEC1 ;get high data byte
DE58 STA &02B9,X ;and store it in hi byte
DE5B STX &02BE ;store in Analogue system flag marking last channel
DE5E LDY #&03 ;handle event 3 conversion complete
DE60 JSR &E494 ;
DE63 DEX ;decrement X
DE64 BNE &DE69 ;if X=0
DE66 LDX &024D ;get highest ADC channel preseny
DE69 JSR &DE8F ;and start new conversion
DE6C LDA #&10 ;reset interrupt 4
DE6E STA &FE4D ;
DE71 RTS ;and return
*************************************************************************
* *
* SYSTEM INTERRUPT 0 Keyboard *
* *
*************************************************************************
;
DE72 ROL ;get original bit 0 in bit 7 position
DE73 ROL ;
DE74 ROL ;
DE75 ROL ;
DE76 BPL &DE7F ;if bit 7 clear not a keyboard interrupt
DE78 JSR &F065 ;else scan keyboard
DE7B LDA #&01 ;A=1
DE7D BNE &DE6E ;and off to reset interrupt and exit
DE7F JMP &DCF3 ;
************** exit routine *********************************************
DE82 PLA ;restore registers
DE83 TAY ;
DE84 PLA ;
DE85 TAX ;
DE86 PLA ;
DE87 STA &FC ;store A
*************************************************************************
* *
* IRQ2V default entry *
*************************************************************************
DE89 LDA &FC ;get back original value of A
DE8B RTI ;and return to calling routine
*************************************************************************
* *
* OSBYTE 17 Start conversion *
* *
*************************************************************************
;
DE8C STY &02BE ;set last channel to finish conversion
DE8F CPX #&05 ;if X<4 then
DE91 BCC &DE95 ;DE95
DE93 LDX #&04 ;else X=4
DE95 STX &024C ;store it as current ADC channel
DE98 LDY &024E ;get conversion type
DE9B DEY ;decrement
DE9C TYA ;A=Y
DE9D AND #&08 ;and it with 08
DE9F CLC ;clear carry
DEA0 ADC &024C ;add to current ADC
DEA3 SBC #&00 ;-1
DEA5 STA &FEC0 ;store to the A/D control panel
DEA8 RTS ;and return
;
DEA9 LDA #&C3 ;point to start of string @&C300
DEAB STA &FE ;store it
DEAD LDA #&00 ;point to lo byte
DEAF STA &FD ;store it and start loop@
DEB1 INY ;print character in string
DEB2 LDA (&FD),Y ;pointed to by &FD/E
DEB4 JSR OSASCI ;print it expanding Carriage returns
DEB7 TAX ;store A in X
DEB8 BNE &DEB1 ;and loop again if not =0
DEBA RTS ;else exit
*********** OSBYTE 129 TIMED ROUTINE ******************************
;ON ENTRY TIME IS IN X,Y
DEBB STX &02B1 ;store time in INKEY countdown timer
DEBE STY &02B2 ;which is decremented every 10ms
DEC1 LDA #&FF ;A=&FF to flag timed wait
DEC3 BNE &DEC7 ;goto DEC7
**************************************************************************
**************************************************************************
** **
** OSRDCH Default entry point **
** **
** RDCHV entry point read a character **
** **
**************************************************************************
**************************************************************************
DEC5 LDA #&00 ;A=0 to flag wait forever
DEC7 STA &E6 ;store entry value of A
DEC9 TXA ;save X and Y
DECA PHA ;
DECB TYA ;
DECC PHA ;
DECD LDY &0256 ;get *EXEC file handle
DED0 BEQ &DEE6 ;if 0 (not open) then DEE6
DED2 SEC ;set carry
DED3 ROR &EB ;set bit 7 of CFS active flag to prevent clashes
DED5 JSR OSBGET ;get a byte from the file
DED8 PHP ;push processor flags to preserve carry
DED9 LSR &EB ;restore &EB
DEDB PLP ;get back flags
DEDC BCC &DF03 ;and if carry clear, character found so exit via DF03
DEDE LDA #&00 ;else A=00 as EXEC file empty
DEE0 STA &0256 ;store it in exec file handle
DEE3 JSR OSFIND ;and close file via OSFIND
DEE6 BIT &FF ;check ESCAPE flag, if bit 7 set Escape pressed
DEE8 BMI &DF00 ;so off to DF00
DEEA LDX &0241 ;else get current input buffer number
DEED JSR &E577 ;get a byte from input buffer
DEF0 BCC &DF03 ;and exit if character returned
DEF2 BIT &E6 ;(E6=0 or FF)
DEF4 BVC &DEE6 ;if entry was OSRDCH not timed keypress, so go back and
;do it again i.e. perform GET function
DEF6 LDA &02B1 ;else check timers
DEF9 ORA &02B2 ;
DEFC BNE &DEE6 ;and if not zero go round again
DEFE BCS &DF05 ;else exit
DEF0 .. BCC &DF03
DEF2 $æ BIT &E6
DEF4 Pð BVC &DEE6
DEF6 ±. LDA &02B1
DEF9 .². ORA &02B2
DEFC Ðè BNE &DEE6
DEFE °. BCS &DF05
DF00 8 SEC
DF01 ©. LDA #&1B
DF03 .æ STA &E6
DF05 h PLA
DF06 ¨ TAY
DF07 h PLA
DF08 ª TAX
DF09 ¥æ LDA &E6
DF0B ` RTS
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/DF0C b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/DF0C new file mode 100644 index 0000000..b273fa3 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/DF0C @@ -0,0 +1,512 @@ +**** STRINGS **** + +DF0C DB ')C)',0 ; Copyright string match + +**** COMMMANDS **** +; Command Address Call goes to +DF10 DB '.',E0,31,05 ; *. &E031, A=5 FSCV, XY=>String +DF14 DB 'FX',E3,42,FF ; *FX &E342, A=&FF Number paramters +DF19 DB 'BASIC',E0,18,00 ; *BASIC &E018, A=0 XY=>String +DF21 DB 'CAT',E0,31,05 ; *CAT &E031, A=5 FSCV, XY=>String +DF27 DB 'CODE',E3,48,88 ; *CODE &E348, A=&88 OSBYTE &88 +DF2E DB 'EXEC',F6,8D,00 ; *EXEC &F68D, A=0 XY=>String +DF35 DB 'HELP',F0,B9,FF ; *HELP &F0B9, A=&FF F2/3=>String +DF3C DB 'KEY',E3,27,FF ; *KEY &E327, A=&FF F2/3=>String +DF42 DB 'LOAD',E2,3C,00 ; *LOAD &E23C, A=0 XY=>String +DF49 DB 'LINE',E6,59,01 ; *LINE &E659, A=1 USERV, XY=>String +DF50 DB 'MOTOR',E3,48,89 ; *MOTOR &E348, A=&89 OSBYTE +DF58 DB 'OPT',E3,48,8B ; *OPT &E348, A=&8B OSBYTE +DF5E DB 'RUN',E0,31,04 ; *RUN &E031, A=4 FSCV, XY=>String +DF64 DB 'ROM',E3,48,8D ; *ROM &E348, A=&8D OSBYTE +DF6A DB 'SAVE',E2,3E,00 ; *SAVE &E23E, A=0 XY=>String +DF70 DB 'SPOOL',E2,81,00 ; *SPOOL &E281, A=0 XY=>String +DF79 DB 'TAPE',E3,48,8C ; *TAPE &E348, A=&8C OSBYTE +DF80 DB 'TV',E3,48,90 ; *TV &E348, A=&90 OSBYTE +DF85 DB E0 ; Table end marker + +; Command routines are entered with XY=>command tail, A=table parameter, +; &F2/3,&E6=>start of command string +; If table parameter if <&80, F2/3,Y converted to XY before entering + + +DF86 31 03 1. AND (&03),Y +DF88 00 . BRK + +************************************************************************* +* * +* CLI - COMMAND LINE INTERPRETER * +* * +* ENTRY: XY=>Command line * +* EXIT: All registers corrupted * +* [ A=13 - unterminated string ] +************************************************************************* +; +DF89 STX &F2 ; Store XY in &F2/3 +DF8B STY &F3 +DF8D LDA #&08 +DF8F JSR &E031 ; Inform filing system CLI being processed +DF92 LDY #&00 ; Check the line is correctly terminated +DF94 LDA (&F2),Y +DF96 CMP #&0D ; Loop until CR is found +DF98 BEQ &DF9E +DF9A INY ; Move to next character +DF9B BNE &DF94 ; Loop back if less than 256 bytes long +DF9D RTS ; Exit if string > 255 characters + +; String is terminated - skip prepended spaces and '*'s +DF9E LDY #&FF +DFA0 JSR &E039 ; Skip any spaces +DFA3 BEQ &E017 ; Exit if at CR +DFA5 CMP #&2A ; Is this character '*'? +DFA7 BEQ &DFA0 ; Loop back to skip it, and check for spaces again + +DFA9 JSR &E03A ; Skip any more spaces +DFAC BEQ &E017 ; Exit if at CR +DFAE CMP #&7C ; Is it '|' - a comment? +DFB0 BEQ &E017 ; Exit if so +DFB2 CMP #&2F ; Is it '/' - pass straight to filing system? +DFB4 BNE &DFBE ; Jump forward if not +DFB6 INY ; Move past the '/' +DFB7 JSR &E009 ; Convert &F2/3,Y->XY, ignore returned A +DFBA LDA #&02 ; 2=RunSlashCommand +DFBC BNE &E031 ; Jump to pass to FSCV +; +; Look command up in command table +DFBE 84 E6 .æ STY &E6 ; Store offset to start of command +DFC0 A2 00 ¢. LDX #&00 +DFC2 F0 13 ð. BEQ &DFD7 +; +DFC4 5D 10 DF ].ß EOR &DF10,X +DFC7 29 DF )ß AND #&DF +DFC9 D0 17 Ð. BNE &DFE2 +DFCB C8 È INY +DFCC 18 . CLC +; +DFCD B0 25 °% BCS &DFF4 +DFCF E8 è INX +DFD0 B1 F2 ±ò LDA (&F2),Y +DFD2 20 E3 E4 ãä JSR &E4E3 +DFD5 90 ED .í BCC &DFC4 +; +DFD7 BD 10 DF ½.ß LDA &DF10,X +DFDA 30 16 0. BMI &DFF2 +DFDC B1 F2 ±ò LDA (&F2),Y +DFDE C9 2E É. CMP #&2E +DFE0 F0 04 ð. BEQ &DFE6 +DFE2 18 . CLC +DFE3 A4 E6 ¤æ LDY &E6 +DFE5 88 . DEY +DFE6 C8 È INY +DFE7 E8 è INX +DFE8 E8 è INX +DFE9 BD 0E DF ½.ß LDA &DF0E,X +DFEC F0 33 ð3 BEQ &E021 +DFEE 10 F8 .ø BPL &DFE8 +DFF0 30 DB 0Û BMI &DFCD +; +DFF2 E8 è INX +DFF3 E8 è INX +; +DFF4 CA Ê DEX +DFF5 CA Ê DEX +DFF6 48 H PHA +DFF7 BD 11 DF ½.ß LDA &DF11,X +DFFA 48 H PHA +DFFB 20 3A E0 :à JSR &E03A +DFFE 18 . CLC +DFFF 08 . PHP +E000 20 04 E0 .à JSR &E004 +E003 40 @ RTI ; Jump to routine + +E004 LDA &DF12,X ; Get table parameter +E007 BMI &E017 ; If >=&80, number follow +; ; else string follows + +E009 TYA ; Pass Y line offset to A for later +E00A LDY &DF12,X ; Get looked-up parameter from table + +; Convert &F2/3,A to XY, put Y in A +E00D 18 . CLC +E00E 65 F2 eò ADC &F2 +E010 AA ª TAX +E011 98 . TYA ; Pass supplied Y into A +E012 A4 F3 ¤ó LDY &F3 +E014 90 01 .. BCC &E017 +E016 C8 È INY +; +E017 60 ` RTS + + +; *BASIC +E018 LDX &024B ; Get Basic rom number +E01B BMI &E021 ; If none set, jump to pass command on +E01D SEC ; Set Carry = not entering from RESET +E01E JMP &DBE7 ; Enter language rom in X + +; Pass command on to other roms and to filing system +E021 LDY &E6 ; Restore pointer to start of command +E023 LDX #&04 ; 4=UnknownCommand +E025 JSR &F168 ; Pass to sideways roms +E028 BEQ &E017 ; If claimed, exit +E02A LDA &E6 ; Restore pointer to start of command +E02C JSR &E00D ; Convert &F2/3,A to XY, ignore returned A +E02F LDA #&03 ; 3=PassCommandToFilingSystem + +; Pass to current filing system +E031 JMP (&021E) + +E034 0A . ASL A +E035 29 01 ). AND #&01 +E037 10 F8 .ø BPL &E031 + +; Skip spaces +E039 C8 È INY +E03A B1 F2 ±ò LDA (&F2),Y +E03C C9 20 É CMP #&20 +E03E F0 F9 ðù BEQ &E039 +E040 C9 0D É. CMP #&0D +E042 60 ` RTS + +; +E043 90 F5 .õ BCC &E03A +E045 20 3A E0 :à JSR &E03A +E048 C9 2C É, CMP #&2C +E04A D0 F4 Ðô BNE &E040 +E04C C8 È INY +E04D 60 ` RTS + +; +E04E 20 3A E0 :à JSR &E03A +E051 20 7D E0 }à JSR &E07D +E054 90 37 .7 BCC &E08D +E056 85 E6 .æ STA &E6 +E058 20 7C E0 |à JSR &E07C +E05B 90 19 .. BCC &E076 +E05D AA ª TAX +E05E A5 E6 ¥æ LDA &E6 +E060 0A . ASL A +E061 B0 2A °* BCS &E08D +E063 0A . ASL A +E064 B0 27 °' BCS &E08D +E066 65 E6 eæ ADC &E6 +E068 B0 23 °# BCS &E08D +E06A 0A . ASL A +E06B B0 20 ° BCS &E08D +E06D 85 E6 .æ STA &E6 +E06F 8A . TXA +E070 65 E6 eæ ADC &E6 +E072 B0 19 °. BCS &E08D +E074 90 E0 .à BCC &E056 +E076 A6 E6 ¦æ LDX &E6 +E078 C9 0D É. CMP #&0D +E07A 38 8 SEC +E07B 60 ` RTS + +E07C C8 È INY +E07D B1 F2 ±ò LDA (&F2),Y +E07F C9 3A É: CMP #&3A +E081 B0 0A °. BCS &E08D +E083 C9 30 É0 CMP #&30 +E085 90 06 .. BCC &E08D +E087 29 0F ). AND #&0F +E089 60 ` RTS + +E08A 20 45 E0 Eà JSR &E045 +E08D 18 . CLC +E08E 60 ` RTS + +E08F 20 7D E0 }à JSR &E07D +E092 B0 0E °. BCS &E0A2 +E094 29 DF )ß AND #&DF +E096 C9 47 ÉG CMP #&47 +E098 B0 F0 °ð BCS &E08A +E09A C9 41 ÉA CMP #&41 +E09C 90 EC .ì BCC &E08A +E09E 08 . PHP +E09F E9 37 é7 SBC #&37 +E0A1 28 ( PLP +E0A2 C8 È INY +E0A3 60 ` RTS + +; WRCH control routine +; ==================== +E0A4 48 H PHA ; Save all registers +E0A5 8A . TXA +E0A6 48 H PHA +E0A7 98 . TYA +E0A8 48 H PHA +E0A9 BA º TSX +E0AA BD 03 01 ½.. LDA &0103,X ; Get A back from stack +E0AD 48 H PHA ; Save A +E0AE 2C 60 02 ,`. BIT &0260 ; Check OSWRCH interception flag +E0B1 10 08 .. BPL &E0BB ; Not set, skip interception call +E0B3 A8 ¨ TAY ; Pass character to Y +E0B4 A9 04 ©. LDA #&04 ; A=4 for OSWRCH call +E0B6 20 7E E5 ~å JSR &E57E ; Call interception code +E0B9 B0 52 °R BCS &E10D ; If claimed, jump past to exit + +E0BB 18 . CLC ; Prepare to not send this to printer +E0BC A9 02 ©. LDA #&02 ; Check output destination +E0BE 2C 7C 02 ,|. BIT &027C ; Is VDU driver disabled? +E0C1 D0 05 Ð. BNE &E0C8 ; Yes, skip past VDU driver +E0C3 68 h PLA ; Get character back +E0C4 48 H PHA ; Resave character +E0C5 20 C0 C4 ÀÄ JSR &C4C0 ; Call VDU driver + ; On exit, C=1 if character to be sent to printer + +E0C8 A9 08 ©. LDA #&08 ; Check output destination +E0CA 2C 7C 02 ,|. BIT &027C ; Is printer seperately enabled? +E0CD D0 02 Ð. BNE &E0D1 ; Yes, jump to call printer driver +E0CF 90 05 .. BCC &E0D6 ; Carry clear, don't sent to printer +E0D1 68 h PLA ; Get character back +E0D2 48 H PHA ; Resave character +E0D3 20 14 E1 .á JSR &E114 ; Call printer driver + +E0D6 AD 7C 02 |. LDA &027C ; Check output destination +E0D9 6A j ROR A ; Is serial output enabled? +E0DA 90 1B .. BCC &E0F7 ; No, skip past serial output +E0DC A4 EA ¤ê LDY &EA ; Get serial timout counter +E0DE 88 . DEY ; Decrease counter +E0DF 10 16 .. BPL &E0F7 ; Timed out, skip past serial code +E0E1 68 h PLA ; Get character back +E0E2 48 H PHA ; Resace character +E0E3 08 . PHP ; Save IRQs +E0E4 78 x SEI ; Disable IRQs +E0E5 A2 02 ¢. LDX #&02 ; X=2 for serial output buffer +E0E7 48 H PHA ; Save character +E0E8 20 5B E4 [ä JSR &E45B ; Examine serial output buffer +E0EB 90 03 .. BCC &E0F0 ; Buffer not full, jump to send character +E0ED 20 70 E1 pá JSR &E170 ; Wait for buffer to empty a bit +E0F0 68 h PLA ; Get character back +E0F1 A2 02 ¢. LDX #&02 ; X=2 for serial output buffer +E0F3 20 F8 E1 øá JSR &E1F8 ; Send character to serial output buffer +E0F6 28 ( PLP ; Restore IRQs + +E0F7 A9 10 ©. LDA #&10 ; Check output destination +E0F9 2C 7C 02 ,|. BIT &027C ; Is SPOOL output disabled? +E0FC D0 0F Ð. BNE &E10D ; Yes, skip past SPOOL output +E0FE AC 57 02 ¬W. LDY &0257 ; Get SPOOL handle +E101 F0 0A ð. BEQ &E10D ; If not open, skip past SPOOL output +E103 68 h PLA ; Get character back +E104 48 H PHA ; Resave character +E105 38 8 SEC +E106 66 EB fë ROR &EB ; Set RFS/CFS's 'spooling' flag +E108 20 D4 FF Ô. JSR &FFD4 ; Write character to SPOOL channel +E10B 46 EB Fë LSR &EB ; Reset RFS/CFS's 'spooling' flag + +E10D 68 h PLA ; Restore all registers +E10E 68 h PLA +E10F A8 ¨ TAY +E110 68 h PLA +E111 AA ª TAX +E112 68 h PLA +E113 60 ` RTS ; Exit + + +************************************************************************* +* * +* PRINTER DRIVER * +* * +************************************************************************* + +;A=character to print + +E114 BIT &027C ;if bit 6 of VDU byte =1 printer is disabled +E117 BVS &E139 ;so E139 + +E119 CMP &0286 ;compare with printer ignore character +E11C BEQ &E139 ;if the same E139 + +E11E PHP ;else save flags +E11F SEI ;bar interrupts +E120 TAX ;X=A +E121 LDA #&04 ;A=4 +E123 BIT &027C ;read bit 2 'disable printer driver' +E126 BNE &E138 ;if set printer is disabled so exit E138 +E128 TXA ;else A=X +E129 LDX #&03 ;X=3 +E12B JSR &E1F8 ;and put character in printer buffer +E12E BCS &E138 ;if carry set on return exit, buffer not full (empty?) + +E130 BIT &02D2 ;else check buffer busy flag if 0 +E133 BPL &E138 ;then E138 to exit +E135 JSR &E13A ;else E13A to open printer cahnnel + +E138 PLP ;get back flags +E139 RTS ;and exit + +E13A LDA &0285 ;check printer destination +E13D BEQ &E1AD ;if 0 then E1AD clear printer buffer and exit +E13F CMP #&01 ;if parallel printer not selected +E141 BNE &E164 ;E164 +E143 JSR &E460 ;else read a byte from the printer buffer +E146 ROR &02D2 ;if carry is set then 2d2 is -ve +E149 BMI &E190 ;so return via E190 +E14B LDY #&82 ;else enable interrupt 1 of the external VIA +E14D STY &FE6E ; +E150 STA &FE61 ;pass code to centronics port +E153 LDA &FE6C ;pulse CA2 line to generate STROBE signal +E156 AND #&F1 ;to advise printer that +E158 ORA #&0C ;valid data is +E15A STA &FE6C ;waiting +E15D ORA #&0E ; +E15F STA &FE6C ; +E162 BNE &E190 ;then exit + +*********:serial printer ********************************************* + +E164 CMP #&02 ;is it Serial printer?? +E166 BNE &E191 ;if not E191 +E168 LDY &EA ;else is RS423 in use by cassette?? +E16A DEY ; +E16B BPL &E1AD ;if so E1AD to flush buffer + +E16D LSR &02D2 ;else clear buffer busy flag +E170 LSR &024F ;and RS423 busy flag +E173 JSR &E741 ;count buffer if C is clear on return +E176 BCC &E190 ;no room in buffer so exit +E178 LDX #&20 ;else +E17A LDY #&9F ; + + + + +************************************************************************* +* * +* OSBYTE 156 update ACIA setting and RAM copy * +* * +************************************************************************* +;on entry + +E17C PHP ;push flags +E17D SEI ;bar interrupts +E17E TYA ;A=Y +E17F STX &FA ;&FA=X +E181 AND &0250 ;A=old value AND Y EOR X +E184 EOR &FA ; +E186 LDX &0250 ;get old value in X +E189 STA &0250 ;put new value in +E18C STA &FE08 ;and store to ACIA control register +E18F PLP ;get back flags +E190 RTS ;and exit + + + +************ printer is neither serial or parallel so its user type ***** + +E191 CLC ;clear carry +E192 LDA #&01 ;A=1 +E194 JSR &E1A2 ; + + +************************************************************************* +* * +* OSBYTE 123 Warn printer driver going dormant * +* * +************************************************************************* + +E197 ROR &02D2 ;mark printer buffer empty for osbyte +E19A RTS ;and exit + +E19B BIT &02D2 ;if bit 7 is set buffer is empty +E19E BMI &E19A ;so exit + +E1A0 LDA #&00 ;else A=0 + +E1A2 LDX #&03 ;X=3 +E1A4 LDY &0285 ;Y=printer destination +E1A7 JSR &E57E ;to JMP (NETV) +E1AA JMP (&0222) ;jump to PRINT VECTOR for special routines + + +*************** Buffer handling ***************************************** + ;X=buffer number + ;Buffer number Address Flag Out pointer In pointer + ;0=Keyboard 3E0-3FF 2CF 2D8 2E1 + ;1=RS423 Input A00-AFF 2D0 2D9 2E2 + ;2=RS423 output 900-9BF 2D1 2DA 2E3 + ;3=printer 880-8BF 2D2 2DB 2E4 + ;4=sound0 840-84F 2D3 2DC 2E5 + ;5=sound1 850-85F 2D4 2DD 2E6 + ;6=sound2 860-86F 2D5 2DE 2E7 + ;7=sound3 870-87F 2D6 2DF 2E8 + ;8=speech 8C0-8FF 2D7 2E0 2E9 + + +E1AD CLC ;clear carry +E1AE PHA ;save A +E1AF PHP ;save flags +E1B0 SEI ;set interrupts +E1B1 BCS &E1BB ;if carry set on entry then E1BB +E1B3 LDA &E9AD,X ;else get byte from baud rate/sound data table +E1B6 BPL &E1BB ;if +ve the E1BB +E1B8 JSR &ECA2 ;else clear sound data + +E1BB SEC ;set carry +E1BC ROR &02CF,X ;rotate buffer flag to show buffer empty +E1BF CPX #&02 ;if X>1 then its not an input buffer +E1C1 BCS &E1CB ;so E1CB + +E1C3 LDA #&00 ;else Input buffer so A=0 +E1C5 STA &0268 ;store as length of key string +E1C8 STA &026A ;and length of VDU queque +E1CB JSR &E73B ;then enter via count purge vector any user routines +E1CE PLP ;restore flags +E1CF PLA ;restore A +E1D0 RTS ;and exit + + + +************************************************************************* +* * +* COUNT PURGE VECTOR DEFAULT ENTRY * +* * +* * +************************************************************************* +;on entry if V set clear buffer +; if C set get space left +; else get bytes used + +E1D1 BVC &E1DA ;if bit 6 is set then E1DA +E1D3 LDA &02D8,X ;else start of buffer=end of buffer +E1D6 STA &02E1,X ; +E1D9 RTS ;and exit + +E1DA PHP ;push flags +E1DB SEI ;bar interrupts +E1DC PHP ;push flags +E1DD SEC ;set carry +E1DE LDA &02E1,X ;get end of buffer +E1E1 SBC &02D8,X ;subtract start of buffer +E1E4 BCS &E1EA ;if carry caused E1EA +E1E6 SEC ;set carry +E1E7 SBC &E447,X ;subtract buffer start offset (i.e. add buffer length) +E1EA PLP ;pull flags +E1EB BCC &E1F3 ;if carry clear E1F3 to exit +E1ED CLC ;clear carry +E1EE ADC &E447,X ;adc to get bytes used +E1F1 EOR #&FF ;and invert to get space left +E1F3 LDY #&00 ;Y=0 +E1F5 TAX ;X=A +E1F6 PLP ;get back flags +E1F7 RTS ;and exit + + + +********** enter byte in buffer, wait and flash lights if full ********** + +E1F8 SEI ;prevent interrupts +E1F9 JSR &E4B0 ;entera byte in buffer X +E1FC BCC &E20D ;if successful exit +E1FE JSR &E9EA ;else switch on both keyboard lights +E201 PHP ;push p +E202 PHA ;push A +E203 JSR &EEEB ;switch off unselected LEDs +E206 PLA ;get back A +E207 PLP ;and flags +E208 BMI &E20D ;if return is -ve Escape pressed so exit +E20A CLI ;else allow interrupts +E20B BCS &E1F8 ;if byte didn't enter buffer go and try it again +E20D RTS ;then return + + diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/E20E b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/E20E new file mode 100644 index 0000000..4f0b4b6 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/E20E @@ -0,0 +1 @@ +OS SERIES VI
GEOFF COX
*************************************************************************
* *
* SAVE/LOAD ENTRY *
* *
* *
*************************************************************************
**************: clear osfile control block workspace ********************
E20E PHA ;push A
E20F LDA #&00 ;A=0
E211 STA &02EE,X ;clear osfile control block workspace
E214 STA &02EF,X ;
E217 STA &02F0,X ;
E21A STA &02F1,X ;
E21D PLA ;get back A
E21E RTS ;and exit
*********** shift through osfile control block **************************
E21F STY &E6 ;&E6=Y
E221 ROL ;A=A*2
E222 ROL ;*4
E223 ROL ;*8
E224 ROL ;*16
E225 LDY #&04 ;Y=4
E227 ROL ;A=A*32
E228 ROL &02EE,X ;shift bit 7 of A into shift register
E22B ROL &02EF,X ;and
E22E ROL &02F0,X ;shift
E231 ROL &02F1,X ;along
E234 BCS &E267 ;if carry set on exit then register has overflowed
;so bad address error
E236 DEY ;decrement Y
E237 BNE &E227 ;and if Y>0 then do another shift
E239 LDY &E6 ;get back original Y
E23B RTS ;and exit
*************************************************************************
* *
* *LOAD ENTRY *
* *
* *
*************************************************************************
E23C LDA #&FF ;signal that load is being performed
*************************************************************************
* *
* *SAVE ENTRY *
* *
* *
*************************************************************************
;on entry A=0 for save &ff for load
E23E STX &F2 ;store address of rest of command line
E240 STY &F3 ;
E242 STX &02EE ;x and Y are stored in OSfile control block
E245 STY &02EF ;
E248 PHA ;Push A
E249 LDX #&02 ;X=2
E24B JSR &E20E ;clear the shift register
E24E LDY #&FF ;Y=255
E250 STY &02F4 ;store im 2F4
E253 INY ;increment Y
E254 JSR &EA1D ;and call GSINIT to prepare for reading text line
E257 JSR &EA2F ;read a code from text line if OK read next
E25A BCC &E257 ;until end of line reached
E25C PLA ;get back A without stack changes
E25D PHA ;
E25E BEQ &E2C2 ;IF A=0 (SAVE) E2C2
E260 JSR &E2AD ;set up file block
E263 BCS &E2A0 ;if carry set do OSFILE
E265 BEQ &E2A5 ;else if A=0 goto OSFILE
E267 BRK ;
E268 DB &FC ;
E269 DB 'Bad Address' ;error
E274 BRK ;
*************************************************************************
* *
* OSBYTE 119 ENTRY *
* CLOSE SPOOL/ EXEC FILES *
* *
*************************************************************************
E275 LDX #&10 ;X=10 issue *SPOOL/EXEC files warning
E277 JSR &F168 ;and issue call
E27A BEQ &E29F ;if a rom accepts and issues a 0 then E29F to return
E27C JSR &F68B ;else close the current exec file
E27F LDA #&00 ;A=0
**************************************************************************
**************************************************************************
** **
** **
** *SPOOL **
** **
**************************************************************************
**************************************************************************
E281 PHP ;if A=0 file is closed so
E282 STY &E6 ;Store Y
E284 LDY &0257 ;get file handle
E287 STA &0257 ;store A as file handle
E28A BEQ &E28F ;if Y<>0 then E28F
E28C JSR OSFIND ;else close file via osfind
E28F LDY &E6 ;get back original Y
E291 PLP ;pull flags
E292 BEQ &E29F ;if A=0 on entry then exit
E294 LDA #&80 ;else A=&80
E296 JSR OSFIND ;to open file Y for output
E299 TAY ;Y=A
E29A BEQ &E310 ;and if this is =0 then E310 BAD COMMAND ERROR
E29C STA &0257 ;store file handle
E29F RTS ;and exit
E2A0 BNE &E310 ;if NE then BAD COMMAND error
E2A2 INC &02F4 ;increment 2F4 to 00
E2A5 LDX #&EE ;X=&EE
E2A7 LDY #&02 ;Y=&02
E2A9 PLA ;get back A
E2AA JMP OSFILE ;and JUMP to OSFILE
**** check for hex digit ************************************************
E2AD JSR &E03A ;look for NEWline
E2B0 JSR &E08F ;carry is set if it finds hex digit
E2B3 BCC &E2C1 ;so E2C1 exit
E2B5 JSR &E20E ;clear shift register
************** shift byte into control block ***************************
E2B8 JSR &E21F ;shift lower nybble of A into shift register
E2BB JSR &E08F ;then check for Hex digit
E2BE BCS &E2B8 ;if found then do it again
E2C0 SEC ;else set carry
E2C1 RTS ;and exit
**************; set up OSfile control block ****************************
E2C2 LDX #&0A ;X=0A
E2C4 JSR &E2AD ;
E2C7 BCC &E310 ;if no hex digit found EXIT via BAD Command error
E2C9 CLV ;clear bit 6
******************READ file length from text line************************
E2CA LDA (&F2),Y ;read next byte from text line
E2CC CMP #&2B ;is it '+'
E2CE BNE &E2D4 ;if not assume its a last byte address so e2d4
E2D0 BIT &D9B7 ;else set V and M flags
E2D3 INY ;increment Y to point to hex group
E2D4 LDX #&0E ;X=E
E2D6 JSR &E2AD ;
E2D9 BCC &E310 ;if carry clear no hex digit so exit via error
E2DB PHP ;save flags
E2DC BVC &E2ED ;if V set them E2ED explicit end address found
E2DE LDX #&FC ;else X=&FC
E2E0 CLC ;clear carry
E2E1 LDA &01FC,X ;and add length data to start address
E2E4 ADC &0200,X ;
E2E7 STA &0200,X ;
E2EA INX ;
E2EB BNE &E2E1 ;repeat until X=0
E2ED LDX #&03 ;X=3
E2EF LDA &02F8,X ;copy start adddress to load and execution addresses
E2F2 STA &02F4,X ;
E2F5 STA &02F0,X ;
E2F8 DEX ;
E2F9 BPL &E2EF ;
E2FB PLP ;get back flag
E2FC BEQ &E2A5 ;if end of command line reached then E2A5
; to do osfile
E2FE LDX #&06 ;else set up execution address
E300 JSR &E2AD ;
E303 BCC &E310 ;if error BAD COMMAND
E305 BEQ &E2A5 ;and if end of line reached do OSFILE
E307 LDX #&02 ;else set up load address
E309 JSR &E2AD ;
E30C BCC &E310 ;if error BAD command
E30E BEQ &E2A5 ;else on end of line do OSFILE
;anything else is an error!!!!
******** Bad command error ************************************
E310 BRK ;
E311 DB &FE ;error number
E312 DB 'Bad Command' ;
E31D BRK
E31E DB &FB ;
E31F DB 'Bad Key' ;
E326 BRK
*************************************************************************
* *
* *KEY ENTRY *
* *
*************************************************************************
E327 JSR &E04E ;set up key number in A
E32A BCC &E31D ;if not valid number give error
E32C CPX #&10 ;if key number greater than 15
E32E BCS &E31D ;if greater then give error
E330 JSR &E045 ;otherwise skip commas, and check for CR
E333 PHP ;save flags for later
E334 LDX &0B10 ;get pointer to top of existing key strings
E337 TYA ;save Y
E338 PHA ;to preserve text pointer
E339 JSR &E3D1 ;set up soft key definition
E33C PLA ;get back Y
E33D TAY ;
E33E PLP ;and flags
E33F BNE &E377 ;if CR found return else E377 to set up new string
E341 RTS ;else return to set null string
*************************************************************************
* *
* *FX OSBYTE *
* *
*************************************************************************
A=number
E342 JSR &E04E ;convert the number to binary
E345 BCC &E310 ;if bad number call bad command
E347 TXA ;save X
*************************************************************************
* *
* *CODE *MOTOR *OPT *ROM *TAPE *TV *
* *
*************************************************************************
;enter codes *CODE &88
*MOTOR &89
*OPT &8B
*TAPE &8C
*ROM &8D
*TV &90
E348 PHA ;save A
E349 LDA #&00 ;clear &E4/E5
E34B STA &E5 ;
E34D STA &E4 ;
E34F JSR &E043 ;skip commas and check for newline (CR)
E352 BEQ &E36C ;if CR found E36C
E354 JSR &E04E ;convert character to binary
E357 BCC &E310 ;if bad character bad command error
E359 STX &E5 ;else save it
E35B JSR &E045 ;skip comma and check CR
E35E BEQ &E36C ;if CR then E36C
E360 JSR &E04E ;get another parameter
E363 BCC &E310 ;if bad error
E365 STX &E4 ;else store in E4
E367 JSR &E03A ;now we must have a newline
E36A BNE &E310 ;if none then output an error
E36C LDY &E4 ;Y=third osbyte parameter
E36E LDX &E5 ;X=2nd
E370 PLA ;A=first
E371 JSR OSBYTE ;call osbyte
E374 BVS &E310 ;if V set on return then error
E376 RTS ;else RETURN
********* *KEY CONTINUED ************************************************
;X points to last byte of current key definitions
E377 SEC ;
E378 JSR &EA1E ;look for '"' on return bit 6 E4=1 bit 7=1 if '"'found
;this is a GSINIT call without initial CLC
E37B JSR &EA2F ;call GSREAD carry is set if end of line found
E37E BCS &E388 ;E388 to deal with end of line
E380 INX ;point to first byte of new key definition
E381 BEQ &E31D ;if X=0 buffer WILL overflow so exit with BAD KEY error
E383 STA &0B00,X ;store character
E386 BCC &E37B ;and loop to get next byte if end of line not found
E388 BNE &E31D ;if Z clear then no matching '"' found or for some
;other reason line doesn't terminate properly
E38A PHP ;else if all OK save flags
E38B SEI ;bar interrupts
E38C JSR &E3D1 ;and move string
E38F LDX #&10 ;set loop counter
E391 CPX &E6 ;if key being defined is found
E393 BEQ &E3A3 ;then skip rest of loop
E395 LDA &0B00,X ;else get start of string X
E398 CMP &0B00,Y ;compare with start of string Y
E39B BNE &E3A3 ;if not the same then skip rest of loop
E39D LDA &0B10 ;else store top of string definition
E3A0 STA &0B00,X ;in designated key pointer
E3A3 DEX ;decrement loop pointer X
E3A4 BPL &E391 ;and do it all again
E3A6 PLP ;get back flags
E3A7 RTS ;and exit
***********: set string lengths *****************************************
E3A8 PHP ;push flags
E3A9 SEI ;bar interrupts
E3AA LDA &0B10 ;get top of currently defined strings
E3AD SEC ;
E3AE SBC &0B00,Y ;subtract to get the number of bytes in strings
;above end of string Y
E3B1 STA &FB ;store this
E3B3 TXA ;save X
E3B4 PHA ;
E3B5 LDX #&10 ;and X=16
E3B7 LDA &0B00,X ;get start offset (from B00) of key string X
E3BA SEC ;
E3BB SBC &0B00,Y ;subtract offset of string we are working on
E3BE BCC &E3C8 ;if carry clear (B00+Y>B00+X) or
E3C0 BEQ &E3C8 ;result (in A)=0
E3C2 CMP &FB ;or greater or equal to number of bytes above
;string we are working on
E3C4 BCS &E3C8 ;then E3C8
E3C6 STA &FB ;else store A in &FB
E3C8 DEX ;point to next lower key offset
E3C9 BPL &E3B7 ;and if 0 or +ve go back and do it again
E3CB PLA ;else get back value of X
E3CC TAX ;
E3CD LDA &FB ;get back latest value of A
E3CF PLP ;pull flags
E3D0 RTS ;and return
***********: set up soft key definition *********************************
E3D1 PHP ;push P
E3D2 SEI ;bar interrupts
E3D3 TXA ;save X
E3D4 PHA ;push A
E3D5 LDY &E6 ;get key number
E3D7 JSR &E3A8 ;and set up &FB
E3DA LDA &0B00,Y ;get start of string
E3DD TAY ;put it in Y
E3DE CLC ;clear carry
E3DF ADC &FB ;add number of bytes above string
E3E1 TAX ;put this in X
E3E2 STA &FA ;and store it
E3E4 LDA &0268 ;check number of bytes left to remove from key buffer
;if not 0 key is being used (definition expanded so
;error. This stops *KEY 1 "*key1 FRED" etc.
E3E7 BEQ &E3F6 ;if not in use continue
E3E9 BRK ;
E3EA DB &FA ;error number
E3EB DB 'Key in use' ;
E3F5 BRK ;
E3F6 DEC &0284 ;decrement consistence flag to &FF to warn that key
;definitions are being changed
E3F9 PLA ;pull A
E3FA SEC ;
E3FB SBC &FA ;subtract &FA
E3FD STA &FA ;and re store it
E3FF BEQ &E40D ;if 0 then E40D
E401 LDA &0B01,X ;else move string
E404 STA &0B01,Y ;from X to Y
E407 INY ;
E408 INX ;
E409 DEC &FA ;for length of string
E40B BNE &E401 ;
E40D TYA ;store end of moved string(s)
E40E PHA ;
E40F LDY &E6 ;get back key number
E411 LDX #&10 ;point at top of last string
E413 LDA &0B00,X ;get this value
E416 CMP &0B00,Y ;compare it with start of new or re defined key
E419 BCC &E422 ;if less then E422
E41B BEQ &E422 ;if = then E422
E41D SBC &FB ;shift key definitions accordingly
E41F STA &0B00,X ;
E422 DEX ;point to next lowest string def
E423 BPL &E413 ;and if =>0 then loop and do it again
E425 LDA &0B10 ;else make top of key definitions
E428 STA &0B00,Y ;the start of our key def
E42B PLA ;get new end of strings
E42C STA &0B10 ;and store it
E42F TAX ;put A in X
E430 INC &0284 ;reset consistency flag
E433 PLP ;restore flags
E434 RTS ;and exit
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/E435 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/E435 new file mode 100644 index 0000000..636b244 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/E435 @@ -0,0 +1 @@ +**************** BUFFER ADDRESS HI LOOK UP TABLE ************************
E435 DB &03 ;keyboard
E436 DB &0A ;rs423 input
E437 DB &08 ;rs423 output
E438 DB &07 ;printer
E439 DB &07 ;sound 0
E43A DB &07 ;sound 1
E43B DB &07 ;sound 2
E43C DB &07 ;sound 3
E43D DB &09 ;speech
**************** BUFFER ADDRESS LO LOOK UP TABLE ************************
E43E DB &00
E43F DB &00
E440 DB &C0
E441 DB &C0
E442 DB &50
E443 DB &60
E444 DB &70
E445 DB &80
E446 DB &00
**************** BUFFER START ADDRESS OFFSET ****************************
E447 DB &E0
E448 DB &00
E449 DB &40
E44A DB &C0
E44B DB &F0
E44C DB &F0
E44D DB &F0
E44E DB &F0
E44F DB &C0
*******: get nominal buffer addresses in &FA/B **************************
; ON ENTRY X=buffer number
;Buffer number Address Flag Out pointer In pointer
;0=Keyboard 3E0-3FF 2CF 2D8 2E1
;1=RS423 Input A00-AFF 2D0 2D9 2E2
;2=RS423 output 900-9BF 2D1 2DA 2E3
;3=printer 880-8BF 2D2 2DB 2E4
;4=sound0 840-84F 2D3 2DC 2E5
;5=sound1 850-85F 2D4 2DD 2E6
;6=sound2 860-86F 2D5 2DE 2E7
;7=sound3 870-87F 2D6 2DF 2E8
;8=speech 8C0-8FF 2D7 2E0 2E9
E450 LDA &E43E,X ;get buffer base address lo
E453 STA &FA ;store it
E455 LDA &E435,X ;get buffer base address hi
E458 STA &FB ;store it
E45A RTS ;exit
*************************************************************************
* *
* OSBYTE 152 Examine Buffer status *
* *
*************************************************************************
;on entry X = buffer number
;on exit FA/B points to buffer start Y is offset to next character
;if buffer is empty C=1, Y is preserved else C=0
E45B BIT &D9B7 ;set V and
E45E BVS &E461 ;jump to E461
*************************************************************************
* *
* OSBYTE 145 Get byte from Buffer *
* *
*************************************************************************
;on entry X = buffer number
; ON EXIT Y is character extracted
;if buffer is empty C=1, else C=0
E460 CLV ;clear V
E461 JMP (&022C) ;Jump via REMV
*************************************************************************
* *
* REMV buffer remove vector default entry point *
* *
*************************************************************************
;on entry X = buffer number
;on exit if buffer is empty C=1, Y is preserved else C=0
E464 PHP ;push flags
E465 SEI ;bar interrupts
E466 LDA &02D8,X ;get output pointer for buffer X
E469 CMP &02E1,X ;compare to input pointer
E46C BEQ &E4E0 ;if equal buffer is empty so E4E0 to exit
E46E TAY ;else A=Y
E46F JSR &E450 ;and get buffer pointer into FA/B
E472 LDA (&FA),Y ;read byte from buffer
E474 BVS &E491 ;if V is set (on input) exit with CARRY clear
;Osbyte 152 has been done
E476 PHA ;else must be osbyte 145 so save byte
E477 INY ;increment Y
E478 TYA ;A=Y
E479 BNE &E47E ;if end of buffer not reached <>0 E47E
E47B LDA &E447,X ;get pointer start from offset table
E47E STA &02D8,X ;set buffer output pointer
E481 CPX #&02 ;if buffer is input (0 or 1)
E483 BCC &E48F ;then E48F
E485 CMP &02E1,X ;else for output buffers compare with buffer start
E488 BNE &E48F ;if not the same buffer is not empty so E48F
E48A LDY #&00 ;buffer is empty so Y=0
E48C JSR &E494 ;and enter EVENT routine to signal EVENT 0 buffer
;becoming empty
E48F PLA ;get back byte from buffer
E490 TAY ;put it in Y
E491 PLP ;get back flags
E492 CLC ;clear carry to indicate success
E493 RTS ;and exit
**************************************************************************
**************************************************************************
** **
** CAUSE AN EVENT **
** **
**************************************************************************
**************************************************************************
;on entry Y=event number
;A and X may be significant Y=A, A=event no. when event generated @E4A1
;on exit carry clear indicates action has been taken else carry set
E494 PHP ;push flags
E495 SEI ;bar interrupts
E496 PHA ;push A
E497 STA &FA ;&FA=A
E499 LDA &02BF,Y ;get enable event flag
E49C BEQ &E4DF ;if 0 event is not enabled so exit
E49E TYA ;else A=Y
E49F LDY &FA ;Y=A
E4A1 JSR &F0A5 ;vector through &220
E4A4 PLA ;get back A
E4A5 PLP ;get back flags
E4A6 CLC ;clear carry for success
E4A7 RTS ;and exit
********* check event 2 character entering buffer ***********************
E4A8 TYA ;A=Y
E4A9 LDY #&02 ;Y=2
E4AB JSR &E494 ;check event
E4AE TAY ;Y=A
*************************************************************************
* *
* OSBYTE 138 Put byte into Buffer *
* *
*************************************************************************
;on entry X is buffer number, Y is character to be written
E4AF TYA ;A=Y
E4B0 JMP (&022A) ;jump to INSBV
*************************************************************************
* *
* INSBV insert character in buffer vector default entry point *
* *
*************************************************************************
;on entry X is buffer number, A is character to be written
E4B3 PHP ;save flags
E4B4 SEI ;bar interrupts
E4B5 PHA ;save A
E4B6 LDY &02E1,X ;get buffer input pointer
E4B9 INY ;increment Y
E4BA BNE &E4BF ;if Y=0 then buffer is full else E4BF
E4BC LDY &E447,X ;get default buffer start
E4BF TYA ;put it in A
E4C0 CMP &02D8,X ;compare it with input pointer
E4C3 BEQ &E4D4 ;if equal buffer is full so E4D4
E4C5 LDY &02E1,X ;else get buffer end in Y
E4C8 STA &02E1,X ;and set it from A
E4CB JSR &E450 ;and point &FA/B at it
E4CE PLA ;get back byte
E4CF STA (&FA),Y ;store it in buffer
E4D1 PLP ;pull flags
E4D2 CLC ;clear carry for success
E4D3 RTS ;and exit
E4D4 PLA ;get back byte
E4D5 CPX #&02 ;if we are working on input buffer
E4D7 BCS &E4E0 ;then E4E0
E4D9 LDY #&01 ;else Y=1
E4DB JSR &E494 ;to service input buffer full event
E4DE PHA ;push A
***** return with carry set *********************************************
E4DF PLA ;restore A
E4E0 PLP ;restore flags
E4E1 SEC ;set carry
E4E2 RTS ;and exit
***************** CODE MODIFIER ROUTINE *********************************
* CHECK FOR ALPHA CHARACTER *
*************************************************************************
;ENTRY character in A
;exit with carry set if non-Alpha character
E4E3 PHA ;Save A
E4E4 AND #&DF ;convert lower to upper case
E4E6 CMP #&41 ;is it 'A' or greater ??
E4E8 BCC &E4EE ;if not exit routine with carry set
E4EA CMP #&5B ;is it less than 'Z'
E4EC BCC &E4EF ;if so exit with carry clear
E4EE SEC ;else clear carry
E4EF PLA ;get back original value of A
E4F0 RTS ;and Return
;
;
*******: INSERT byte in Keyboard buffer *********************************
E4F1 LDX #&00 ;X=0 to indicate keyboard buffer
*************************************************************************
* *
* OSBYTE 153 Put byte in input Buffer checking for ESCAPE *
* *
*************************************************************************
;on entry X = buffer number (either 0 or 1)
;X=1 is RS423 input
;X=0 is Keyboard
;Y is character to be written
E4F3 TXA ;A=buffer number
E4F4 AND &0245 ;and with RS423 mode (0 treat as keyboard
;1 ignore Escapes no events no soft keys)
E4F7 BNE &E4AF ;so if RS423 buffer AND RS423 in normal mode (1) E4AF
E4F9 TYA ;else Y=A character to write
E4FA EOR &026C ;compare with current escape ASCII code (0=match)
E4FD ORA &0275 ;or with current ESCAPE status (0=ESC, 1=ASCII)
E500 BNE &E4A8 ;if ASCII or no match E4A8 to enter byte in buffer
E502 LDA &0258 ;else get ESCAPE/BREAK action byte
E505 ROR ;Rotate to get ESCAPE bit into carry
E506 TYA ;get character back in A
E507 BCS &E513 ;and if escape disabled exit with carry clear
E509 LDY #&06 ;else signal EVENT 6 Escape pressed
E50B JSR &E494 ;
E50E BCC &E513 ;if event handles ESCAPE then exit with carry clear
E510 JSR &E674 ;else set ESCAPE flag
E513 CLC ;clear carry
E514 RTS ;and exit
******** get a byte from keyboard buffer and interpret as necessary *****
;on entry A=cursor editing status 1=return &87-&8B,
;2= use cursor keys as soft keys 11-15
;this area not reached if cursor editing is normal
E515 ROR ;get bit 1 into carry
E516 PLA ;get back A
E517 BCS &E592 ;if carry is set return
;else cursor keys are 'soft'
E519 TYA ;A=Y get back original key code (&80-&FF)
E51A PHA ;PUSH A
E51B LSR ;get high nybble into lo
E51C LSR ;
E51D LSR ;
E51E LSR ;A=8-&F
E51F EOR #&04 ;and invert bit 2
;&8 becomes &C
;&9 becomes &D
;&A becomes &E
;&B becomes &F
;&C becomes &8
;&D becomes &9
;&E becomes &A
;&F becomes &B
E521 TAY ;Y=A = 8-F
E522 LDA &0265,Y ;read 026D to 0274 code interpretation status
;0=ignore key, 1=expand as 'soft' key
;2-&FF add this to base for ASCII code
;note that provision is made for keypad operation
;as codes &C0-&FF cannot be generated from keyboard
;but are recognised by OS
;
E525 CMP #&01 ;is it 01
E527 BEQ &E594 ;if so expand as 'soft' key via E594
E529 PLA ;else get back original byte
E52A BCC &E539 ;if above CMP generated Carry then code 0 must have
;been returned so E539 to ignore
E52C AND #&0F ;else add ASCII to BASE key number so clear hi nybble
E52E CLC ;clear carry
E52F ADC &0265,Y ;add ASCII base
E532 CLC ;clear carry
E533 RTS ;and exit
;
*********** ERROR MADE IN USING EDIT FACILITY ***************************
E534 JSR &E86F ;produce bell
E537 PLA ;get back A, buffer number
E538 TAX ;X=buffer number
********get byte from buffer ********************************************
E539 JSR &E460 ;get byte from buffer X
E53C BCS &E593 ;if buffer empty E593 to exit
E53E PHA ;else Push byte
E53F CPX #&01 ;and if RS423 input buffer is not the one
E541 BNE &E549 ;then E549
E543 JSR &E173 ;else oswrch
E546 LDX #&01 ;X=1 (RS423 input buffer)
E548 SEC ;set carry
E549 PLA ;get back original byte
E54A BCC &E551 ;if carry clear (I.E not RS423 input) E551
E54C LDY &0245 ;else Y=RS423 mode (0 treat as keyboard )
E54F BNE &E592 ;if not 0 ignore escapes etc. goto E592
E551 TAY ;Y=A
E552 BPL &E592 ;if code is less that &80 its simple so E592
E554 AND #&0F ;else clear high nybble
E556 CMP #&0B ;if less than 11 then treat as special code
E558 BCC &E519 ;or function key and goto E519
E55A ADC #&7B ;else add &7C (&7B +C) to convert codes B-F to 7-B
E55C PHA ;Push A
E55D LDA &027D ;get cursor editing status
E560 BNE &E515 ;if not 0 (normal) E515
E562 LDA &027C ;else get character destination status
;Bit 0 enables RS423 driver
;BIT 1 disables VDU driver
;Bit 2 disables printer driver
;BIT 3 enables printer independent of CTRL B or CTRL C
;Bit 4 disables spooled output
;BIT 5 not used
;Bit 6 disables printer driver unless VDU 1 precedes character
;BIT 7 not used
E565 ROR ;get bit 1 into carry
E566 ROR ;
E567 PLA ;
E568 BCS &E539 ;if carry is set E539 screen disabled
E56A CMP #&87 ;else is it COPY key
E56C BEQ &E5A6 ;if so E5A6
E56E TAY ;else Y=A
E56F TXA ;A=X
E570 PHA ;Push X
E571 TYA ;get back Y
E572 JSR &D8CE ;execute edit action
E575 PLA ;restore X
E576 TAX ;
E577 BIT &025F ;check econet RDCH flag
E57A BPL &E581 ;if not set goto E581
E57C LDA #&06 ;else Econet function 6
E57E JMP (&0224) ;to the Econet vector
********* get byte from key string **************************************
;on entry 0268 contains key length
;and 02C9 key string pointer to next byte
E581 LDA &0268 ;get length of keystring
E584 BEQ &E539 ;if 0 E539 get a character from the buffer
E586 LDY &02C9 ;get soft key expansion pointer
E589 LDA &0B01,Y ;get character from string
E58C INC &02C9 ;increment pointer
E58F DEC &0268 ;decrement length
************** exit with carry clear ************************************
E592 CLC ;
E593 RTS ;exit
;
*** expand soft key strings *********************************************
Y=pointer to sring number
E594 PLA ;restore original code
E595 AND #&0F ;blank hi nybble to get key string number
E597 TAY ;Y=A
E598 JSR &E3A8 ;get string length in A
E59B STA &0268 ;and store it
E59E LDA &0B00,Y ;get start point
E5A1 STA &02C9 ;and store it
E5A4 BNE &E577 ;if not 0 then get byte via E577 and exit
*********** deal with COPY key ******************************************
E5A6 TXA ;A=X
E5A7 PHA ;Push A
E5A8 JSR &D905 ;read a character from the screen
E5AB TAY ;Y=A
E5AC BEQ &E534 ;if not valid A=0 so BEEP
E5AE PLA ;else restore X
E5AF TAX ;
E5B0 TYA ;and Y
E5B1 CLC ;clear carry
E5B2 RTS ;and exit
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/E6B0 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/E6B0 new file mode 100644 index 0000000..5f1e45f --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/E6B0 @@ -0,0 +1 @@ +*************************************************************************
* *
* OSBYTE LOOK UP TABLE
* *
*************************************************************************
E5B3 DB &21,&E8 ;OSBYTE 0 (&E821)
E5B5 DB &88,&E9 ;OSBYTE 1 (&E988)
E5B7 DB &D3,&E6 ;OSBYTE 2 (&E6D3)
E5B9 DB &97,&E9 ;OSBYTE 3 (&E997)
E5BB DB &97,&E9 ;OSBYTE 4 (&E997)
E5BD DB &76,&E9 ;OSBYTE 5 (&E976)
E5BF DB &88,&E9 ;OSBYTE 6 (&E988)
E5C1 DB &8B,&E6 ;OSBYTE 7 (&E68B)
E5C3 DB &89,&E6 ;OSBYTE 8 (&E689)
E5C5 DB &B0,&E6 ;OSBYTE 9 (&E6B0)
E5C7 DB &B2,&E6 ;OSBYTE 10 (&E6B2)
E5C9 DB &95,&E9 ;OSBYTE 11 (&E995)
E5CB DB &8C,&E9 ;OSBYTE 12 (&E98C)
E5CD DB &F9,&E6 ;OSBYTE 13 (&E6F9)
E5CF DB &FA,&E6 ;OSBYTE 14 (&E6FA)
E5D1 DB &A8,&F0 ;OSBYTE 15 (&F0A8)
E5D3 DB &06,&E7 ;OSBYTE 16 (&E706)
E5D5 DB &8C,&DE ;OSBYTE 17 (&DE8C)
E5D7 DB &C8,&E9 ;OSBYTE 18 (&E9C8)
E5D9 DB &B6,&E9 ;OSBYTE 19 (&E9B6)
E5DB DB &07,&CD ;OSBYTE 20 (&CD07)
E5DD DB &B4,&F0 ;OSBYTE 21 (&F0B4)
E5DF DB &6C,&E8 ;OSBYTE 117 (&E86C)
E5E1 DB &D9,&E9 ;OSBYTE 118 (&E9D9)
E5E3 DB &75,&E2 ;OSBYTE 119 (&E275)
E5E5 DB &45,&F0 ;OSBYTE 120 (&F045)
E5E7 DB &CF,&F0 ;OSBYTE 121 (&F0CF)
E5E9 DB &CD,&F0 ;OSBYTE 122 (&F0CD)
E5EB DB &97,&E1 ;OSBYTE 123 (&E197)
E5ED DB &73,&E6 ;OSBYTE 124 (&E673)
E5EF DB &74,&E6 ;OSBYTE 125 (&E674)
E5F1 DB &5C,&E6 ;OSBYTE 126 (&E65C)
E5F3 DB &35,&E0 ;OSBYTE 127 (&E035)
E5F5 DB &4F,&E7 ;OSBYTE 128 (&E74F)
E5F7 DB &13,&E7 ;OSBYTE 129 (&E713)
E5F9 DB &29,&E7 ;OSBYTE 130 (&E729)
E5FB DB &85,&F0 ;OSBYTE 131 (&F085)
E5FD DB &23,&D9 ;OSBYTE 132 (&D923)
E5FF DB &26,&D9 ;OSBYTE 133 (&D926)
E601 DB &47,&D6 ;OSBYTE 134 (&D647)
E603 DB &C2,&D7 ;OSBYTE 135 (&D7C2)
E605 DB &57,&E6 ;OSBYTE 136 (&E657)
E607 DB &7F,&E6 ;OSBYTE 137 (&E67F)
E609 DB &AF,&E4 ;OSBYTE 138 (&E4AF)
E60B DB &34,&E0 ;OSBYTE 139 (&E034)
E60D DB &35,&F1 ;OSBYTE 140 (&F135)
E60F DB &35,&F1 ;OSBYTE 141 (&F135)
E611 DB &E7,&DB ;OSBYTE 142 (&DBE7)
E613 DB &68,&F1 ;OSBYTE 143 (&F168)
E615 DB &E3,&EA ;OSBYTE 144 (&EAE3)
E617 DB &60,&E4 ;OSBYTE 145 (&E460)
E619 DB &AA,&FF ;OSBYTE 146 (&FFAA)
E61B DB &F4,&EA ;OSBYTE 147 (&EAF4)
E61D DB &AE,&FF ;OSBYTE 148 (&FFAE)
E61F DB &F9,&EA ;OSBYTE 149 (&EAF9)
E621 DB &B2,&FF ;OSBYTE 150 (&FFB2)
E623 DB &FE,&EA ;OSBYTE 151 (&EAFE)
E625 DB &5B,&E4 ;OSBYTE 152 (&E45B)
E627 DB &F3,&E4 ;OSBYTE 153 (&E4F3)
E629 DB &FF,&E9 ;OSBYTE 154 (&E9FF)
E62B DB &10,&EA ;OSBYTE 155 (&EA10)
E62D DB &7C,&E1 ;OSBYTE 156 (&E17C)
E62F DB &A7,&FF ;OSBYTE 157 (&FFA7)
E631 DB &6D,&EE ;OSBYTE 158 (&EE6D)
E633 DB &7F,&EE ;OSBYTE 159 (&EE7F)
E635 DB &C0,&E9 ;OSBYTE 160 (&E9C0)
E637 DB &9C,&E9 ;
E639 DB &59,&E6 ;
*************************************************************************
* *
* OSWORD LOOK UP TABLE *
* *
*************************************************************************
E63B DB &02,&E9 ;OSWORD 0 (&E902)
E63D DB &D5,&E8 ;OSWORD 1 (&E8D5)
E63F DB &E8,&E8 ;OSWORD 2 (&E8E8)
E641 DB &D1,&E8 ;OSWORD 3 (&E8D1)
E643 DB &E4,&E8 ;OSWORD 4 (&E8E4)
E645 DB &03,&E8 ;OSWORD 5 (&E803)
E647 DB &0B,&E8 ;OSWORD 6 (&E80B)
E649 DB &2D,&E8 ;OSWORD 7 (&E82D)
E64B DB &AE,&E8 ;OSWORD 8 (&E8AE)
E64D DB &35,&C7 ;OSWORD 9 (&C735)
E64F DB &F3,&CB ;OSWORD 10 (&CBF3)
E651 DB &48,&C7 ;OSWORD 11 (&C748)
E653 DB &E0,&C8 ;OSWORD 12 (&C8E0)
E655 DB &CE,&D5 ;OSWORD 13 (&D5CE)
*************************************************************************
* *
* OSBYTE 136 Execute Code via User Vector *
* *
* *CODE effectively *
* *
*************************************************************************
E658 LDA #00 ;A=0
*************************************************************************
* *
* *LINE entry *
* *
*************************************************************************
E659 JMP (&0200) ;Jump via USERV
*************************************************************************
* *
* OSBYTE 126 Acknowledge detection of ESCAPE condition *
* *
*************************************************************************
E65C LDX #&00 ;X=0
E65E BIT &FF ;if bit 7 not set there is no ESCAPE condition
E660 BPL &E673 ;so E673
E662 LDA &0276 ;else get ESCAPE Action, if this is 0
;Clear ESCAPE
;close EXEC files
;purge all buffers
;reset VDU paging counter
E665 BNE &E671 ;else do none of the above
E667 CLI ;allow interrupts
E668 STA &0269 ;number of lines printed since last halt in paged
;mode = 0
E66B JSR &F68D ;close any open EXEC files
E66E JSR &F0AA ;clear all buffers
E671 LDX #&FF ;X=&FF to indicate ESCAPE acknowledged
*************************************************************************
* *
* OSBYTE 124 Clear ESCAPE condition *
* *
*************************************************************************
E673 CLC ;clear carry
*************************************************************************
* *
* OSBYTE 125 Set ESCAPE flag *
* *
*************************************************************************
E674 ROR &FF ;clear bit 7 of ESCAPE flag
E676 BIT &027A ;read bit 7 of Tube flag
E679 BMI &E67C ;if set TUBE exists so E67C
E67B RTS ;else RETURN
;
E67C JMP &0403 ;Jump to Tube entry point
*************************************************************************
* *
* OSBYTE 137 Turn on Tape motor *
* *
*************************************************************************
E67F LDA &0282 ;get serial ULA control setting
E682 TAY ;Y=A
E683 ROL ;rotate left to get bit 7 into carry
E684 CPX #&01 ;if X=1 then user wants motor on so CARRY set else
;carry is cleared
E686 ROR ;put carry back in control RAM copy
E687 BVC &E6A7 ;if bit 6 is clear then cassette is selected
;so write to control register and RAM copy
E689 LDA #&38 ;A=ASCII 8
*************************************************************************
* *
* OSBYTE 08/07 set serial baud rates *
* *
*************************************************************************
on entry X=baud rate
A=8 transmit
A=7 receive
E68B EOR #&3F ;converts ASCII 8 to 7 binary and ASCII 7 to 8 binary
E68D STA &FA ;store result
E68F LDY &0282 ;get serial ULA control register setting
E692 CPX #&09 ;is it 9 or more?
E694 BCS &E6AD ;if so exit
E696 AND &E9AD,X ;and with byte from look up table
E699 STA &FB ;store it
E69B TYA ;put Y in A
E69C ORA &FA ;and or with Accumulator
E69E EOR &FA ;zero the three bits set true
E6A0 ORA &FB ;set up data read from look up table + bit 6
E6A2 ORA #&40 ;
E6A4 EOR &025D ;write cassette/RS423 flag
E6A7 STA &0282 ;store serial ULA flag
E6AA STA &FE10 ;and write to control register
E6AD TYA ;put Y in A to save old contents
E6AE TAX ;write new setting to X
E6AF RTS ;and return
OS SERIES VII
GEOFF COX
*************************************************************************
* *
* OSBYTE 9 Duration of first colour *
* *
*************************************************************************
;on entry Y=0, X=new value
E6B0 INY ;Y is incremented to 1
E6B1 CLC ;clear carry
*************************************************************************
* *
* OSBYTE 10 Duration of second colour *
* *
*************************************************************************
;on entry Y=0 or 1 if from FX 9 call, X=new value
E6B2 LDA &0252,Y ;get mark period count
E6B5 PHA ;push it
E6B6 TXA ;get new count
E6B7 STA &0252,Y ;store it
E6BA PLA ;get back original value
E6BB TAY ;put it in Y
E6BC LDA &0251 ;get value of flash counter
E6BF BNE &E6D1 ;if not zero E6D1
E6C1 STX &0251 ;else restore old value
E6C4 LDA &0248 ;get current video ULA control register setting
E6C7 PHP ;push flags
E6C8 ROR ;rotate bit 0 into carry, carry into bit 7
E6C9 PLP ;get back flags
E6CA ROL ;rotate back carry into bit 0
E6CB STA &0248 ;store it in RAM copy
E6CE STA &FE20 ;and ULA control register
E6D1 BVC &E6AD ;then exit via OSBYTE 7/8
*************************************************************************
* *
* OSBYTE 2 select input stream *
* *
*************************************************************************
;on input X contains stream number
E6D3 TXA ;A=X
E6D4 AND #&01 ;blank out bits 1 - 7
E6D6 PHA ;push A
E6D7 LDA &0250 ;and get current ACIA control setting
E6DA ROL ;Bit 7 into carry
E6DB CPX #&01 ;if X>=1 then
E6DD ROR ;bit 7 of A=1
E6DE CMP &0250 ;compare this with ACIA control setting
E6E1 PHP ;push processor
E6E2 STA &0250 ;put A into ACIA control setting
E6E5 STA &FE08 ;and write to control register
E6E8 JSR &E173 ;set up RS423 buffer
E6EB PLP ;get back P
E6EC BEQ &E6F1 ;if new setting different from old E6F1 else
E6EE BIT &FE09 ;set bit 6 and 7
E6F1 LDX &0241 ;get current input buffer number
E6F4 PLA ;get back A
E6F5 STA &0241 ;store it
E6F8 RTS ;and return
*************************************************************************
* *
* OSBYTE 13 disable events *
* *
*************************************************************************
;X contains event number 0-9
E6F9 TYA ;Y=0 A=0
*************************************************************************
* *
* OSBYTE 14 enable events *
* *
*************************************************************************
;X contains event number 0-9
E6FA CPX #&0A ;if X>9
E6FC BCS &E6AE ;goto E6AE for exit
E6FE LDY &02BF,X ;else get event enable flag
E701 STA &02BF,X ;store new value in flag
E704 BVC &E6AD ;and exit via E6AD
*************************************************************************
* *
* OSBYTE 16 Select A/D channel *
* *
*************************************************************************
;X contains channel number or 0 if disable conversion
E706 BEQ &E70B ;if X=0 then E70B
E708 JSR &DE8C ;start conversion
E70B LDA &024D ;get current maximum ADC channel number
E70E STX &024D ;store new value
E711 TAX ;put old value in X
E712 RTS ;and exit
;
*************************************************************************
* *
* OSBYTE 129 Read key within time limit *
* *
*************************************************************************
;X and Y contains either time limit in centi seconds Y=&7F max
; or Y=&FF and X=-ve INKEY value
E713 TYA ;A=Y
E714 BMI &E721 ;if Y=&FF the E721
E716 CLI ;else allow interrupts
E717 JSR &DEBB ;and go to timed routine
E71A BCS &E71F ;if carry set then E71F
E71C TAX ;then X=A
E71D LDA #&00 ;A=0
E71F TAY ;Y=A
E720 RTS ;and return
;
;scan keyboard
E721 TXA ;A=X
E722 EOR #&7F ;convert to keyboard input
E724 TAX ;X=A
E725 JSR &F068 ;then scan keyboard
E728 ROL ;put bit 7 into carry
E729 LDX #&FF ;X=&FF
E72B LDY #&FF ;Y=&FF
E72D BCS &E731 ;if bit 7 of A was set goto E731 (RTS)
E72F INX ;else X=0
E730 INY ;and Y=0
E731 RTS ;and exit
********** check occupancy of input or free space of output buffer *******
;X=buffer number
;Buffer number Address Flag Out pointer In pointer
;0=Keyboard 3E0-3FF 2CF 2D8 2E1
;1=RS423 Input A00-AFF 2D0 2D9 2E2
;2=RS423 output 900-9BF 2D1 2DA 2E3
;3=printer 880-8BF 2D2 2DB 2E4
;4=sound0 840-84F 2D3 2DC 2E5
;5=sound1 850-85F 2D4 2DD 2E6
;6=sound2 860-86F 2D5 2DE 2E7
;7=sound3 870-87F 2D6 2DF 2E8
;8=speech 8C0-8FF 2D7 2E0 2E9
E732 TXA ;buffer number in A
E733 EOR #&FF ;invert it
E735 TAX ;X=A
E736 CPX #&02 ;is X>1
E738 CLV ;clear V flag
E739 BVC &E73E ;and goto E73E count buffer
E73B BIT &D9B7 ;set V
E73E JMP (&022E) ;CNPV defaults to E1D1
************* check RS423 input buffer ************************************
E741 SEC
E742 LDX #&01 ;X=1 to point to buffer
E744 JSR &E738 ;and count it
E747 CPY #&01 ;if the hi byte of the answer is 1 or more
E749 BCS &E74E ;then Return
E74B CPX &025B ;else compare with minimum buffer space
E74E RTS ;and exit
*************************************************************************
* *
* OSBYTE 128 READ ADC CHANNEL *
* *
*************************************************************************
;ON Entry: X=0 Exit Y contains number of last channel converted
; X=channel number X,Y contain 16 bit value read from channe
; X<0 Y=&FF X returns information about various buffers
; X=&FF (keyboard ) X=number of characters in buffer
; X=&FE (RS423 Input) X=number of characters in buffer
; X=&FD (RS423 output) X=number of empty spaces in buffer
; X=&FC (Printer) X=number of empty spaces in buffer
; X=&FB (sound 0) X=number of empty spaces in buffer
; X=&FA (sound 1) X=number of empty spaces in buffer
; X=&F9 (sound 2) X=number of empty spaces in buffer
; X=&F8 (sound 3) X=number of empty spaces in buffer
; X=&F7 (Speech ) X=number of empty spaces in buffer
E74F BMI &E732 ;if X is -ve then E732 count spaces
E751 BEQ &E75F ;if X=0 then E75F
E753 CPX #&05 ;else check for Valid channel
E755 BCS &E729 ;if not E729 set X & Y to 0 and exit
E757 LDY &02B9,X ;get conversion values for channel of interest Hi &
E75A LDA &02B5,X ;lo byte
E75D TAX ;X=lo byte
E75E RTS ;and exit
E75F LDA &FE40 ;read system VIA port B
E762 ROR ;move high nybble to low
E763 ROR ;
E764 ROR ;
E765 ROR ;
E766 EOR #&FF ;and invert it
E768 AND #&03 ;isolate the FIRE buttons
E76A LDY &02BE ;get analogue system flag byte
E76D STX &02BE ;store X here
E770 TAX ;A=X bits 0 and 1 indicate fire buttons
E771 RTS ;and return
**************************************************************************
**************************************************************************
** **
** OSBYTE DEFAULT ENTRY POINT **
** **
** pointed to by default BYTEV **
** **
**************************************************************************
**************************************************************************
E772 PHA ;save A
E773 PHP ;save Processor flags
E774 SEI ;disable interrupts
E775 STA &EF ;store A,X,Y in zero page
E777 STX &F0 ;
E779 STY &F1 ;
E77B LDX #&07 ;X=7 to signal osbyte is being attempted
E77D CMP #&75 ;if A=0-116
E77F BCC &E7C2 ;then E7C2
E781 CMP #&A1 ;if A<161
E783 BCC &E78E ;then E78E
E785 CMP #&A6 ;if A=161-165
E787 BCC &E7C8 ;then EC78
E789 CLC ;clear carry
E78A LDA #&A1 ;A=&A1
E78C ADC #&00 ;
********* process osbyte calls 117 - 160 *****************************
E78E SEC ;set carry
E78F SBC #&5F ;convert to &16 to &41 (22-65)
E791 ASL ;double it (44-130)
E792 SEC ;set carry
E793 STY &F1 ;store Y
E795 TAY ;Y=A
E796 BIT &025E ;read econet intercept flag
E799 BPL &E7A2 ;if no econet intercept required E7A2
E79B TXA ;else A=X
E79C CLV ;V=0
E79D JSR &E57E ; to JMP via ECONET vector
E7A0 BVS &E7BC ;if return with V set E7BC
E7A2 LDA &E5B4,Y ;get address from table
E7A5 STA &FB ;store it as hi byte
E7A7 LDA &E5B3,Y ;repeat for lo byte
E7AA STA &FA ;
E7AC LDA &EF ;restore A
E7AE LDY &F1 ;Y
E7B0 BCS &E7B6 ;if carry is set E7B6
E7B2 LDY #&00 ;else
E7B4 LDA (&F0),Y ;get value from address pointed to by &F0/1 (Y,X)
E7B6 SEC ;set carry
E7B7 LDX &F0 ;restore X
E7B9 JSR &F058 ;call &FA/B
E7BC ROR ;C=bit 0
E7BD PLP ;get back flags
E7BE ROL ;bit 0=Carry
E7BF PLA ;get back A
E7C0 CLV ;clear V
E7C1 RTS ;and exit
*************** Process OSBYTE CALLS BELOW &75 **************************
E7C2 LDY #&00 ;Y=0
E7C4 CMP #&16 ;if A<&16
E7C6 BCC &E791 ;goto E791
E7C8 PHP ;push flags
E7C9 PHP ;push flags
E7CA PLA ;pull flags
E7CB PLA ;pull flags
E7CC JSR &F168 ;offer paged ROMS service 7/8 unrecognised osbyte/word
E7CF BNE &E7D6 ;if roms don't recognise it then E7D6
E7D1 LDX &F0 ;else restore X
E7D3 JMP &E7BC ;and exit
E7D6 PLP ;else pull flags
E7D7 PLA ;and A
E7D8 BIT &D9B7 ;set V and C
E7DB RTS ;and return
E7DC LDA &EB ;read cassette critical flag bit 7 = busy
E7DE BMI &E812 ;if busy then EB12
E7E0 LDA #&08 ;else A=8 to check current Catalogue status
E7E2 AND &E2 ;by anding with CFS status flag
E7E4 BNE &E7EA ;if not set (not in use) then E7EA RTS
E7E6 LDA #&88 ;A=%10001000
E7E8 AND &BB ;AND with FS options (short msg bits)
E7EA RTS ;RETURN
**************************************************************************
**************************************************************************
** **
** OSWORD DEFAULT ENTRY POINT **
** **
** pointed to by default WORDV **
** **
**************************************************************************
**************************************************************************
E7EB PHA ;Push A
E7EC PHP ;Push flags
E7ED SEI ;disable interrupts
E7EE STA &EF ;store A,X,Y
E7F0 STX &F0 ;
E7F2 STY &F1 ;
E7F4 LDX #&08 ;X=8
E7F6 CMP #&E0 ;if A=>224
E7F8 BCS &E78A ;then E78A with carry set
E7FA CMP #&0E ;else if A=>14
E7FC BCS &E7C8 ;else E7C8 with carry set pass to ROMS & exit
E7FE ADC #&44 ;add to form pointer to table
E800 ASL ;double it
E801 BCC &E793 ;goto E793 ALWAYS!! (carry clear E7F8)
;this reads bytes from table and enters routine
*************************************************************************
* *
* OSWORD 05 ENTRY POINT *
* *
* read a byte from I/O memory *
* *
*************************************************************************
;block of 4 bytes set at address pointed to by 00F0/1 (Y,X)
;XY +0 ADDRESS of byte
; +4 on exit byte read
E803 JSR &E815 ;set up address of data block
E806 LDA (&F9,X) ;get byte
E808 STA (&F0),Y ;store it
E80A RTS ;exit
*************************************************************************
* *
* OSWORD 06 ENTRY POINT *
* *
* write a byte to I/O memory *
* *
*************************************************************************
;block of 5 bytes set at address pointed to by 00F0/1 (Y,X)
;XY +0 ADDRESS of byte
; +4 byte to be written
E80B JSR &E815 ;set up address
E80E LDA (&F0),Y ;get byte
E810 STA (&F9,X) ;store it
E812 LDA #&00 ;a=0
E814 RTS ;exit
********************: set up data block *********************************
E815 STA &FA ;&FA=A
E817 INY ;Y=1
E818 LDA (&F0),Y ;get byte from block
E81A STA &FB ;store it
E81C LDY #&04 ;Y=4
E81E LDX #&01 ;X=1
E820 RTS ;and exit
*************************************************************************
* *
* OSBYTE 00 ENTRY POINT *
* *
* read OS version number *
* *
*************************************************************************
E821 BNE &E81E ;if A <> 0 then exit else print error
E823 BRK ;
E824 DB &F7 ;error number
E825 DB 'OS 1.20' ;error message
E82C BRK
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/E887 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/E887 new file mode 100644 index 0000000..cfdd00d --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/E887 @@ -0,0 +1 @@ +*************************************************************************
*************************************************************************
** **
** SOUND SYSTEM **
** **
*************************************************************************
*************************************************************************
-------------------------------------------------------------------------
| |
| OSWORD 07 - Make a sound |
| |
-------------------------------------------------------------------------
; On entry, control block pointed to by &F0/1
; Y=0 on entry
; XY +0 Channel - &hsfc for Hold, Sync, Flush, Channel
; 2 Amplitude/Envelope
; 4 Pitch
; 6 Duration
E82D INY
E82E LDA (&F0),Y ; Get channel high byte byte
E830 CMP #&FF
E832 BEQ &E88D ; Channel &FFxx, speech command
E834 CMP #&20 ; Is channel>=&20 ?
E836 LDX #&08 ; Prepare X=8 for unrecognised OSWORD call
E838 BCS &E7CA ; Pass to sideways ROMs for channel &2000+
E83A DEY ; Point back to channel low byte
E83B JSR &E8C9 ; Get Channel 0-3, and Cy if >=&10 for Flush
E83E ORA #&04 ; Convert to buffer number 4-7
E840 TAX
E841 BCC &E848 ; If no Flush, skip past
E843 JSR &E1AE ; Flush buffer
E846 LDY #&01 ; Point back to channel high byte
E848 JSR &E8C9 ; Get Sync 0-3, and Cy if >=&10 for Hold
E84B STA &FA ; Save Sync in &FA
E84D PHP ; Stack flags
E84E LDY #&06
E850 LDA (&F0),Y ; Get Duration byte
E852 PHA ; and stack it
E853 LDY #&04
E855 LDA (&F0),Y ; Get pitch byte
E857 PHA ; and stack it
E858 LDY #&02 ;
E85A LDA (&F0),Y ; Get amplitude/envelope byte
E85C ROL ; Move Hold into bit 0
E85D SEC ;set carry
E85E SBC #&02 ;subract 2
E860 ASL ;multiply by 4
E861 ASL ;
E862 ORA &FA ;add S byte (0-3)
; At this point,
; b7, 0=envelope, 1=volume
; b6-3, envelope-1 or volume+15
; b2, Hold
; b1-0, Sync
E864 JSR &E1F8 ; Insert into buffer
E867 BCC &E887 ; Buffer not full, jump to insert the rest
E869 PLA ; Drop stacked pitch
E86A PLA ; Drop stacked duration
E86B PLP ; Restore flags
; And exit
-------------------------------------------------------------------------
| |
| OSBYTE 117 - Read VDU status |
| |
-------------------------------------------------------------------------
E86C LDX &D0 ;get VDU status byte in X
E86E RTS ;and return
************* set up sound data for Bell ********************************
E86F PHP ;push P
E870 SEI ;bar interrupts
E871 LDA &0263 ;get bell channel number in A
E874 AND #&07 ; (bits 0-3 only set)
E876 ORA #&04 ;set bit 2
E878 TAX ;X=A = bell channel number +4=buffer number
E879 LDA &0264 ;get bell amplitude/envelope number
E87C JSR &E4B0 ;store it in buffer pointed to by X
E87F LDA &0266 ;get bell duration
E882 PHA ;save it
E883 LDA &0265 ;get bell frequency
E886 PHA ;save it
; Insert sound pitch and duration into sound buffer
;
E887 SEC ; Set carry
E888 ROR &0800,X ; Set bit 7 of channel flags to indicate it's active
E88B BMI &E8A4 ; Jump forward to insert pitch and duration
-------------------------------------------------------------------------
| |
| SOUND &FFxx - Speech System |
| |
-------------------------------------------------------------------------
; On entry, control block pointed to by &F0/1
; Y=1 on entry
; XY +0 Channel - &FFxx - xx=Speech command
; 2 Word number/Address
; 4 Ignored
; 6 Ignored
E88D PHP ; Save flags
E88E INY ; Y=2
E88F LDA (&F0),Y ; Get word number low byte
E891 PHA ; and stack it
E892 INY ; Y=3
E893 LDA (&F0),Y ; Get word number high byte
E895 PHA ; and stack it
E896 LDY #&00 ; Y=0
E898 LDA (&F0),Y ; Get speech command
E89A LDX #&08 ; X=8 for Speech buffer
E89C JSR &E1F8 ; Insert speech command into speech buffer
E89F BCS &E869 ; Buffer full, drop stack and abandon
E8A1 ROR &02D7 ; Clear bit 7 of speech buffer busy flag
; Insert two bytes into buffer
;
E8A4 PLA ; Get word number high byte or pitch back
E8A5 JSR &E4B0 ; Insert into speech buffer
E8A8 PLA ; Get word number low byte or duration back
E8A9 JSR &E4B0 ; Insert into speech buffer
E8AC PLP ; Restore flags
E8AD RTS ; and return
*************************************************************************
* *
* OSWORD 08 - Define Envelope *
* *
*************************************************************************
; On entry, control block pointed to by &F0/1
; Y=0 on entry
; A=envelope number from (&F0),0
;XY +0 Envelope number, also in A
; 1 bits 0-6 length of each step in centi-secsonds bit 7=0 auto repeat
; 2 change of Pitch per step (-128-+127) in section 1
; 3 change of Pitch per step (-128-+127) in section 2
; 4 change of Pitch per step (-128-+127) in section 3
; 5 number of steps in section 1 (0-255)
; 6 number of steps in section 2 (0-255)
; 7 number of steps in section 3 (0-255)
; 8 change of amplitude per step during attack phase (-127 to +127)
; 9 change of amplitude per step during decay phase (-127 to +127)
; 10 change of amplitude per step during sustain phase (-127 to +127)
; 11 change of amplitude per step during release phase (-127 to +127)
; 12 target level at end of attack phase (0-126)
; 13 target level at end of decay phase (0-126)
E8AE SBC #&01 ;set up appropriate displacement to storage area
E8B0 ASL ;A=(A-1)*16 or 15
E8B1 ASL ;
E8B2 ASL ;
E8B3 ASL ;
E8B4 ORA #&0F ;
E8B6 TAX ;X=A
E8B7 LDA #&00 ;A=0
E8B9 LDY #&10 ;Y=&10
E8BB CPY #&0E ;is Y>=14??
E8BD BCS &E8C1 ;yes then E8C1
E8BF LDA (&F0),Y ;else get byte from parameter block
E8C1 STA &08C0,X ;and store it in appropriate area
E8C4 DEX ;decrement X
E8C5 DEY ;Decrement Y
E8C6 BNE &E8BB ;if not 0 then do it again
E8C8 RTS ;else exit
;note that envelope number is NOT transferred
;
E8C9 LDA (&F0),Y ;get byte
E8CB CMP #&10 ;is it greater than 15, if so set carry
E8CD AND #&03 ;and 3 to clear bits 2-7
E8CF INY ;increment Y
E8D0 RTS ;and exit
*************************************************************************
* *
* OSWORD 03 ENTRY POINT *
* *
* read interval timer *
* *
*************************************************************************
F0/1 points to block to store data
E8D1 LDX #&0F ;X=&F displacement from clock to timer
E8D3 BNE &E8D8 ;jump to E8D8
*************************************************************************
* *
* OSWORD 01 ENTRY POINT *
* *
* read system clock *
* *
*************************************************************************
F0/1 points to block to store data
E8D5 LDX &0283 ;X=current system clock store pointer
E8D8 LDY #&04 ;Y=4
E8DA LDA &028D,X ;read byte
E8DD STA (&F0),Y ;store it in parameter block
E8DF INX ;X=x+1
E8E0 DEY ;Y=Y-1
E8E1 BPL &E8DA ;if Y>0 then do it again
E8E3 RTS ;else exit
*************************************************************************
* *
* OSWORD 04 ENTRY POINT *
* *
* write interval timer *
* *
*************************************************************************
F0/1 points to block to store data
E8E4 LDA #&0F ;offset between clock and timer
E8E6 BNE &E8EE ;jump to E8EE ALWAYS!!
*************************************************************************
* *
* OSWORD 02 ENTRY POINT *
* *
* write system clock *
* *
*************************************************************************
F0/1 points to block to store data
E8E8 LDA &0283 ;get current clock store pointer
E8EB EOR #&0F ;and invert to get inactive timer
E8ED CLC ;clear carry
E8EE PHA ;store A
E8EF TAX ;X=A
E8F0 LDY #&04 ;Y=4
E8F2 LDA (&F0),Y ;and transfer all 5 bytes
E8F4 STA &028D,X ;to the clock or timer
E8F7 INX ;
E8F8 DEY ;
E8F9 BPL &E8F2 ;if Y>0 then E8F2
E8FB PLA ;get back stack
E8FC BCS &E8E3 ;if set (write to timer) E8E3 exit
E8FE STA &0283 ;write back current clock store
E901 RTS ;and exit
*************************************************************************
* *
* OSWORD 00 ENTRY POINT *
* *
* read line from current input to memory *
* *
*************************************************************************
;F0/1 points to parameter block
; +0/1 buffer address for input
; +2 Maximum line length
; +3 minimum acceptable ASCII value
; +4 maximum acceptable ASCII value
E902 LDY #&04 ;Y=4
E904 LDA (&F0),Y ;transfer bytes 4,3,2 to 2B3-2B5
E906 STA &02B1,Y ;
E909 DEY ;decrement Y
E90A CPY #&02 ;until Y=1
E90C BCS &E904 ;
E90E LDA (&F0),Y ;get address of input buffer
E910 STA &E9 ;store it in &E9 as temporary buffer
E912 DEY ;decrement Y
E913 STY &0269 ;Y=0 store in print line counter for paged mode
E916 LDA (&F0),Y ;get lo byte of address
E918 STA &E8 ;and store in &E8
E91A CLI ;allow interrupts
E91B BCC &E924 ;Jump to E924
E91D LDA #&07 ;A=7
E91F DEY ;decrement Y
E920 INY ;increment Y
E921 JSR OSWRCH ;and call OSWRCH
E924 JSR OSRDCH ;else read character from input stream
E927 BCS &E972 ;if carry set then illegal character or other error
;exit via E972
E929 TAX ;X=A
E92A LDA &027C ;A=&27C get character destination status
E92D ROR ;put VDU driver bit in carry
E92E ROR ;if this is 1 VDU driver is disabled
E92F TXA ;X=A
E930 BCS &E937 ;if Carry set E937
E932 LDX &026A ;get number of items in VDU queque
E935 BNE &E921 ;if not 0 output character and loop round again
E937 CMP #&7F ;if character is not delete
E939 BNE &E942 ;goto E942
E93B CPY #&00 ;else is Y=0
E93D BEQ &E924 ;and goto E924
E93F DEY ;decrement Y
E940 BCS &E921 ;and if carry set E921 to output it
E942 CMP #&15 ;is it delete line &21
E944 BNE &E953 ;if not E953
E946 TYA ;else Y=A, if its 0 we are still reading first
;character
E947 BEQ &E924 ;so E924
E949 LDA #&7F ;else output DELETES
E94B JSR OSWRCH ;until Y=0
E94E DEY ;
E94F BNE &E94B ;
E951 BEQ &E924 ;then read character again
E953 STA (&E8),Y ;store character in designated buffer
E955 CMP #&0D ;is it CR?
E957 BEQ &E96C ;if so E96C
E959 CPY &02B3 ;else check the line length
E95C BCS &E91D ;if = or greater loop to ring bell
E95E CMP &02B4 ;check minimum character
E961 BCC &E91F ;if less than minimum backspace
E963 CMP &02B5 ;check maximum character
E966 BEQ &E920 ;if equal E920
E968 BCC &E920 ;or less E920
E96A BCS &E91F ;then JUMP E91F
E96C JSR OSNEWL ;output CR/LF
E96F JSR &E57E ;call Econet vector
E972 LDA &FF ;A=ESCAPE FLAG
E974 ROL ;put bit 7 into carry
E975 RTS ;and exit routine
*************************************************************************
* *
* OSBYTE 05 ENTRY POINT *
* *
* SELECT PRINTER TYPE *
* *
*************************************************************************
E976 CLI ;allow interrupts briefly
E977 SEI ;bar interrupts
E978 BIT &FF ;check if ESCAPE is pending
E97A BMI &E9AC ;if it is E9AC
E97C BIT &02D2 ;else check bit 7 buffer 3 (printer)
E97F BPL &E976 ;if not empty bit 7=0 E976
E981 JSR &E1A4 ;check for user defined routine
E984 LDY #&00 ;Y=0
E986 STY &F1 ;F1=0
*************************************************************************
* *
* OSBYTE 01 ENTRY POINT *
* *
* READ/WRITE USER FLAG (&281) *
* *
* AND *
* *
* OSBYTE 06 ENTRY POINT *
* *
* SET PRINTER IGNORE CHARACTER *
* *
*************************************************************************
; A contains osbyte number
E988 ORA #&F0 ;A=osbyte +&F0
E98A BNE &E99A ;JUMP to E99A
*************************************************************************
* *
* OSBYTE 0C ENTRY POINT *
* *
* SET KEYBOARD AUTOREPEAT RATE *
* *
*************************************************************************
E98C BNE &E995 ;if &F0<>0 goto E995
E98E LDX #&32 ;if X=0 in original call then X=32
E990 STX &0254 ;to set keyboard autorepeat delay ram copy
E993 LDX #&08 ;X=8
*************************************************************************
* *
* OSBYTE 0B ENTRY POINT *
* *
* SET KEYBOARD AUTOREPEAT DELAY *
* *
*************************************************************************
E995 ADC #&CF ;A=A+&D0 (carry set)
*************************************************************************
* *
* OSBYTE 03 ENTRY POINT *
* *
* SELECT OUTPUT STREAM *
* *
* AND *
* *
* *
* OSBYTE 04 ENTRY POINT *
* *
* ENABLE/DISABLE CURSOR EDITING *
* *
*************************************************************************
E997 CLC ;c,ear carry
E998 ADC #&E9 ;A=A+&E9
E99A STX &F0 ;store X
*************************************************************************
* *
* OSBYTE A6-FF ENTRY POINT *
* *
* READ/ WRITE SYSTEM VARIABLE OSBYTE NO. +&190 *
* *
*************************************************************************
E99C TAY ;Y=A
E99D LDA &0190,Y ;i.e. A=&190 +osbyte call!
E9A0 TAX ;preserve this
E9A1 AND &F1 ;new value = OLD value AND Y EOR X!
E9A3 EOR &F0 ;
E9A5 STA &0190,Y ;store it
E9A8 LDA &0191,Y ;get value of next byte into A
E9AB TAY ;Y=A
E9AC RTS ;and exit
******* SERIAL BAUD RATE LOOK UP TABLE ************************************
E9AD DB &64 ; % 01100100 75
E9AE DB &7F ; % 01111111 150
E9AF DB &5B ; % 01011011 300
E9B0 DB &6D ; % 01101101 1200
E9B1 DB &C9 ; % 11001001 2400
E9B2 DB &F6 ; % 11110110 4800
E9B3 DB &D2 ; % 11010010 9600
E9B4 DB &E4 ; % 11100100 19200
E9B5 DB &40 ; % 01000000
*************************************************************************
* *
* OSBYTE &13 ENTRY POINT *
* *
* Wait for VSync *
* *
*************************************************************************
E9B6 LDA &0240 ;read vertical sync counter
E9B9 CLI ;allow interrupts briefly
E9BA SEI ;bar interrupts
E9BB CMP &0240 ;has it changed?
E9BE BEQ &E9B9 ;no then E9B9
; falls through and reads VDU variable X
*************************************************************************
* *
* OSBYTE 160 ENTRY POINT *
* *
* READ VDU VARIABLE *
* *
*************************************************************************
;X contains the variable number
;0 =lefthand column in pixels current graphics window
;2 =Bottom row in pixels current graphics window
;4 =Right hand column in pixels current graphics window
;6 =Top row in pixels current graphics window
;8 =lefthand column in absolute characters current text window
;9 =Bottom row in absolute characters current text window
;10 =Right hand column in absolute characters current text window
;11 =Top row in absolute characters current text window
;12-15 current graphics origin in external coordinates
;16-19 current graphics cursor in external coordina4es
;20-23 old graphics cursor in internal coordinates
;24 current text cursor in X and Y
E9C0 LDY &0301,X ;get VDU variable hi
E9C3 LDA &0300,X ;low
E9C6 TAX ;X=low byte
E9C7 RTS ;and exit
*************************************************************************
* *
* OSBYTE 18 ENTRY POINT *
* *
* RESET SOFT KEYS *
* *
*************************************************************************
E9C8 LDA #&10 ;set consistency flag
E9CA STA &0284 ;
E9CD LDX #&00 ;X=0
E9CF STA &0B00,X ;and wipe clean
E9D2 INX ;soft key buffer
E9D3 BNE &E9CF ;until X=0 again
E9D5 STX &0284 ;zero consistency flag
E9D8 RTS ;and exit
*************************************************************************
* *
* OSBYTE &76 (118) SET LEDs to Keyboard Status *
* *
*************************************************************************
;osbyte entry with carry set
;called from &CB0E, &CAE3, &DB8B
E9D9 PHP ;PUSH P
E9DA SEI ;DISABLE INTERUPTS
E9DB LDA #&40 ;switch on CAPS and SHIFT lock lights
E9DD JSR &E9EA ;via subroutine
E9E0 BMI &E9E7 ;if ESCAPE exists (M set) E9E7
E9E2 CLC ;else clear V and C
E9E3 CLV ;before calling main keyboard routine to
E9E4 JSR &F068 ;switch on lights as required
E9E7 PLP ;get back flags
E9E8 ROL ;and rotate carry into bit 0
E9E9 RTS ;Return to calling routine
;
***************** Turn on keyboard lights and Test Escape flag ************
;called from &E1FE, &E9DD
;
E9EA BCC &E9F5 ;if carry clear
E9EC LDY #&07 ;switch on shift lock light
E9EE STY &FE40 ;
E9F1 DEY ;Y=6
E9F2 STY &FE40 ;switch on Caps lock light
E9F5 BIT &FF ;set minus flag if bit 7 of &00FF is set indicating
E9F7 RTS ;that ESCAPE condition exists, then return
;
****************** Write A to SYSTEM VIA register B *************************
;called from &CB6D, &CB73
E9F8 PHP ;push flags
E9F9 SEI ;disable interupts
E9FA STA &FE40 ;write register B from Accumulator
E9FD PLP ;get back flags
E9FE RTS ;and exit
;
*************************************************************************
* *
* OSBYTE 154 (&9A) SET VIDEO ULA *
* *
*************************************************************************
E9FF TXA ;osbyte entry! X transferred to A thence to
*******Set Video ULA control register **entry from VDU routines **************
;called from &CBA6, &DD37
EA00 PHP ;save flags
EA01 SEI ;disable interupts
EA02 STA &0248 ;save RAM copy of new parameter
EA05 STA &FE20 ;write to control register
EA08 LDA &0253 ;read space count
EA0B STA &0251 ;set flash counter to this value
EA0E PLP ;get back status
EA0F RTS ;and return
*************************************************************************
* *
* OSBYTE &9B (155) write to palette register *
* *
*************************************************************************
;entry X contains value to write
EA10 TXA ;A=X
EA11 EOR #&07 ;convert to palette format
EA13 PHP ;
EA14 SEI ;prevent interrupts
EA15 STA &0249 ;store as current palette setting
EA18 STA &FE21 ;store actual colour in register
EA1B PLP ;get back flags
EA1C RTS ;and exit
;
*************************************************************************
* GSINIT string initialisation *
* F2/3 points to string offset by Y *
* *
* ON EXIT *
* Z flag set indicates null string, *
* Y points to first non blank character *
* A contains first non blank character *
*************************************************************************
EA1D CLC ;clear carry
EA1E ROR &E4 ;Rotate moves carry to &E4
EA20 JSR &E03A ;get character from text
EA23 INY ;increment Y to point at next character
EA24 CMP #&22 ;check to see if its '"'
EA26 BEQ &EA2A ;if so EA2A (carry set)
EA28 DEY ;decrement Y
EA29 CLC ;clear carry
EA2A ROR &E4 ;move bit 7 to bit 6 and put carry in bit 7
EA2C CMP #&0D ;check to see if its CR to set Z
EA2E RTS ;and return
*************************************************************************
* GSREAD string read routine *
* F2/3 points to string offset by Y *
* *
*************************************************************************
;
EA2F LDA #&00 ;A=0
EA31 STA &E5 ;store A
EA33 LDA (&F2),Y ;read first character
EA35 CMP #&0D ;is it CR
EA37 BNE &EA3F ;if not goto EA3F
EA39 BIT &E4 ;if bit 7=1 no 2nd '"' found
EA3B BMI &EA8F ;goto EA8F
EA3D BPL &EA5A ;if not EA5A
EA3F CMP #&20 ;is less than a space?
EA41 BCC &EA8F ;goto EA8F
EA43 BNE &EA4B ;if its not a space EA4B
EA45 BIT &E4 ;is bit 7 of &E4 =1
EA47 BMI &EA89 ;if so goto EA89
EA49 BVC &EA5A ;if bit 6 = 0 EA5A
EA4B CMP #&22 ;is it '"'
EA4D BNE &EA5F ;if not EA5F
EA4F BIT &E4 ;if so and Bit 7 of &E4 =0 (no previous ")
EA51 BPL &EA89 ;then EA89
EA53 INY ;else point at next character
EA54 LDA (&F2),Y ;get it
EA56 CMP #&22 ;is it '"'
EA58 BEQ &EA89 ;if so then EA89
EA5A JSR &E03A ;read a byte from text
EA5D SEC ;and return with
EA5E RTS ;carry set
;
EA5F CMP #&7C ;is it '|'
EA61 BNE &EA89 ;if not EA89
EA63 INY ;if so increase Y to point to next character
EA64 LDA (&F2),Y ;get it
EA66 CMP #&7C ;and compare it with '|' again
EA68 BEQ &EA89 ;if its '|' then EA89
EA6A CMP #&22 ;else is it '"'
EA6C BEQ &EA89 ;if so then EA89
EA6E CMP #&21 ;is it !
EA70 BNE &EA77 ;if not then EA77
EA72 INY ;increment Y again
EA73 LDA #&80 ;set bit 7
EA75 BNE &EA31 ;loop back to EA31 to set bit 7 in next CHR
EA77 CMP #&20 ;is it a space
EA79 BCC &EA8F ;if less than EA8F Bad String Error
EA7B CMP #&3F ;is it '?'
EA7D BEQ &EA87 ;if so EA87
EA7F JSR &EABF ;else modify code as if CTRL had been pressed
EA82 BIT &D9B7 ;if bit 6 set
EA85 BVS &EA8A ;then EA8A
EA87 LDA #&7F ;else set bits 0 to 6 in A
EA89 CLV ;clear V
EA8A INY ;increment Y
EA8B ORA &E5 ;
EA8D CLC ;clear carry
EA8E RTS ;Return
;
EA8F BRK ;
EA90 DB &FD ;error number
EA93 DB 'Bad String' ; message
EA9B BRK ;
************ Modify code as if SHIFT pressed *****************************
EA9C CMP #&30 ;if A='0' skip routine
EA9E BEQ &EABE ;
EAA0 CMP #&40 ;if A='@' skip routine
EAA2 BEQ &EABE ;
EAA4 BCC &EAB8 ;if A<'@' then EAB8
EAA6 CMP #&7F ;else is it DELETE
EAA8 BEQ &EABE ;if so skip routine
EAAA BCS &EABC ;if greater than &7F then toggle bit 4
EAAC EOR #&30 ;reverse bits 4 and 5
EAAE CMP #&6F ;is it &6F (previously ' _' (&5F))
EAB0 BEQ &EAB6 ;goto EAB6
EAB2 CMP #&50 ;is it &50 (previously '`' (&60))
EAB4 BNE &EAB8 ;if not EAB8
EAB6 EOR #&1F ;else continue to convert ` _
EAB8 CMP #&21 ;compare &21 '!'
EABA BCC &EABE ;if less than return
EABC EOR #&10 ;else finish conversion by toggling bit 4
EABE RTS ;exit
;
;ASCII codes &00 &20 no change
;21-3F have bit 4 reverses (31-3F)
;41-5E A-Z have bit 5 reversed a-z
;5F & 60 are reversed
;61-7E bit 5 reversed a-z becomes A-Z
;DELETE unchanged
;&80+ has bit 4 changed
************** Implement CTRL codes *************************************
EABF CMP #&7F ;is it DEL
EAC1 BEQ &EAD1 ;if so ignore routine
EAC3 BCS &EAAC ;if greater than &7F go to EAAC
EAC5 CMP #&60 ;if A<>'`'
EAC7 BNE &EACB ;goto EACB
EAC9 LDA #&5F ;if A=&60, A=&5F
EACB CMP #&40 ;if A<&40
EACD BCC &EAD1 ;goto EAD1 and return unchanged
EACF AND #&1F ;else zero bits 5 to 7
EAD1 RTS ;return
;
EAD2 DB '/!BOOT',&0D
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/EAD9 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/EAD9 new file mode 100644 index 0000000..6682621 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/EAD9 @@ -0,0 +1 @@ +OS SERIES 8
GEOFF COX
*************************************************************************
* *
* OSBYTE &F7 (247) INTERCEPT BREAK *
* *
*************************************************************************
EAD9 LDA &0287 ;get BREAK vector code
EADC EOR #&4C ;produces 0 if JMP not in &287
EADE BNE &EAF3 ;if not goto EAF3
EAE0 JMP &0287 ;else jump to user BREAK code
*************************************************************************
* *
* OSBYTE &90 (144) *TV *
* *
*************************************************************************
;X=display delay
;Y=interlace flag
EAE3 LDA &0290 ;VDU vertical adjustment
EAE6 STX &0290 ;store new value
EAE9 TAX ;put old value in X
EAEA TYA ;put interlace flag in A
EAEB AND #&01 ;maximum value =1
EAED LDY &0291 ;get old value into Y
EAF0 STA &0291 ;put new value into A
EAF3 RTS ;and Exit
*************************************************************************
* *
* OSBYTE &93 (147) WRITE TO FRED *
* *
*************************************************************************
;X is offset within page
;Y is byte to write
EAF4 TYA ;
EAF5 STA &FC00,X ;
EAF8 RTS ;
*************************************************************************
* *
* OSBYTE &95 (149) WRITE TO JIM *
* *
*************************************************************************
;X is offset within page
;Y is byte to write
;
EAF9 TYA ;
EAFA STA &FD00,X ;
EAFD RTS ;
*************************************************************************
* *
* OSBYTE &97 (151) WRITE TO SHEILA *
* *
*************************************************************************
;X is offset within page
;Y is byte to write
EAFE TYA ;
EAFF STA &FE00,X ;
EB02 RTS ;
****************** Silence a sound channel *******************************
;X=channel number
EB03 LDA #&04 ;mark end of release phase
EB05 STA &0808,X ;to channel X
EB08 LDA #&C0 ;load code for zero volume
****** if sound not disabled set sound generator volume ******************
EB0A STA &0804,X ;store A to give basic sound level of Zero
EB0D LDY &0262 ;get sound output/enable flag
EB10 BEQ &EB14 ;if sound enabled goto EB14
EB12 LDA #&C0 ;else load zero sound code
EB14 SEC ;set carry
EB15 SBC #&40 ;subtract &40
EB17 LSR ;divide by 8
EB18 LSR ;to get into bits 0 - 3
EB19 LSR ;
EB1A EOR #&0F ;invert bits 0-3
EB1C ORA &EB3C,X ;get channel number into top nybble
EB1F ORA #&10 ;
EB21 PHP ;
EB22 SEI ;disable interrupts
EB23 LDY #&FF ;System VIA port A all outputs
EB25 STY &FE43 ;set
EB28 STA &FE4F ;output A on port A
EB2B INY ;Y=0
EB2C STY &FE40 ;enable sound chip
EB2F LDY #&02 ;set and
EB31 DEY ;execute short delay
EB32 BNE &EB31 ;
EB34 LDY #&08 ;then disable sound chip again
EB36 STY &FE40 ;
EB39 LDY #&04 ;set delay
EB3B DEY ;and loop delay
EB3C BNE &EB3B ;
EB3E PLP ;get back flags
EB3F RTS ;and exit
*******: Sound parameters look up table **********************************
EB40 DB &E0,&C0,&A0,&80
EB44 JMP &EC59 ;just to allow relative branches in early part
;of sound interrupt routine
*************************************************************************
* *
* PROCESS SOUND INTERRUPT *
* *
*************************************************************************
EB47 LDA #&00 ;
EB49 STA &083B ;zero number of channels on hold for sync
EB4C LDA &0838 ;get number of channels required for sync
EB4F BNE &EB57 ;if this <>0 then EB57
EB51 INC &083B ;else number of chanels on hold for sync =1
EB54 DEC &0838 ;number of channels required for sync =255
EB57 LDX #&08 ;set loop counter
EB59 DEX ;loop
EB5A LDA &0800,X ;get value of &800 +offset (sound queue occupancy)
EB5D BEQ &EB44 ;if 0 goto EC59 no sound this channel
EB5F LDA &02CF,X ;else get buffer busy flag
EB62 BMI &EB69 ;if negative (buffer empty) goto EB69
EB64 LDA &0818,X ;else if duration count not zer0
EB67 BNE &EB6C ;goto EB6C
EB69 JSR &EC6B ;check and pick up new sound if required
EB6C LDA &0818,X ;if duration count 0
EB6F BEQ &EB84 ;goto EB84
EB71 CMP #&FF ;else if it is &FF (infinite duration)
EB73 BEQ &EB87 ;go onto EB87
EB75 DEC &081C,X ;decrement 10 mS count
EB78 BNE &EB87 ;and if 0
EB7A LDA #&05 ;reset to 5
EB7C STA &081C,X ;to give 50 mSec delay
EB7F DEC &0818,X ;and decrement main counter
EB82 BNE &EB87 ;if not zero then EB87
EB84 JSR &EC6B ;else check and get nw sound
EB87 LDA &0824,X ;if step progress counter is 0 no envelope involved
EB8A BEQ &EB91 ;so jump to EB91
EB8C DEC &0824,X ;else decrement it
EB8F BNE &EB44 ;and if not zero go on to EC59
EB91 LDY &0820,X ;get envelope data offset from (8C0)
EB94 CPY #&FF ;if 255 no envelope set so
EB96 BEQ &EB44 ;goto EC59
EB98 LDA &08C0,Y ;else get get step length
EB9B AND #&7F ;zero repeat bit
EB9D STA &0824,X ;and store it
EBA0 LDA &0808,X ;get phase counter
EBA3 CMP #&04 ;if release phase completed
EBA5 BEQ &EC07 ;goto EC07
EBA7 LDA &0808,X ;else start new step by getting phase
EBAA CLC ;
EBAB ADC &0820,X ;add it to interval multiplier
EBAE TAY ;transfer to Y
EBAF LDA &08CB,Y ;and get target value base for envelope
EBB2 SEC ;
EBB3 SBC #&3F ;
EBB5 STA &083A ;store modified number as current target amplitude
EBB8 LDA &08C7,Y ;get byte from envelope store
EBBB STA &0839 ;store as current amplitude step
EBBE LDA &0804,X ;get base volumelevel
EBC1 PHA ;save it
EBC2 CLC ;clear carry
EBC3 ADC &0839 ;add to current amplitude step
EBC6 BVC &EBCF ;if no overflow
EBC8 ROL ;double it Carry = bit 7
EBC9 LDA #&3F ;if bit =1 A=&3F
EBCB BCS &EBCF ;into &EBCF
EBCD EOR #&FF ;else toggle bits (A=&C0)
;at this point the BASIC volume commands are converted
; &C0 (0) to &38 (-15) 3 times, In fact last 3 bits
;are ignored so &3F represents -15
EBCF STA &0804,X ;store in current volume
EBD2 ROL ;multiply by 2
EBD3 EOR &0804,X ;if bits 6 and 7 are equal
EBD6 BPL &EBE1 ;goto &EBE1
EBD8 LDA #&3F ;if carry clear A=&3F (maximum)
EBDA BCC &EBDE ;or
EBDC EOR #&FF ;&C0 minimum
EBDE STA &0804,X ;and this is stored in current volume
EBE1 DEC &0839 ;decrement amplitude change per step
EBE4 LDA &0804,X ;get volume again
EBE7 SEC ;set carry
EBE8 SBC &083A ;subtract target value
EBEB EOR &0839 ;negative value undicates correct trend
EBEE BMI &EBF9 ;so jump to next part
EBF0 LDA &083A ;else enter new phase
EBF3 STA &0804,X ;
EBF6 INC &0808,X ;
EBF9 PLA ;get the old volume level
EBFA EOR &0804,X ;and compare with the old
EBFD AND #&F8 ;
EBFF BEQ &EC07 ;if they are the same goto EC07
EC01 LDA &0804,X ;else set new level
EC04 JSR &EB0A ;via EB0A
EC07 LDA &0810,X ;get absolute pitch value
EC0A CMP #&03 ;if it =3
EC0C BEQ &EC59 ;skip rest of loop as all sections are finished
EC0E LDA &0814,X ;else if 814,X is not 0 current section is not
;complete
EC11 BNE &EC3D ;so EC3D
EC13 INC &0810,X ;else implement a section change
EC16 LDA &0810,X ;check if its complete
EC19 CMP #&03 ;if not
EC1B BNE &EC2D ;goto EC2D
EC1D LDY &0820,X ;else set A from
EC20 LDA &08C0,Y ;&820 and &8C0 (first envelope byte)
EC23 BMI &EC59 ;if negative there is no repeat
EC25 LDA #&00 ;else restart section sequence
EC27 STA &0830,X ;
EC2A STA &0810,X ;
EC2D LDA &0810,X ;get number of steps in new section
EC30 CLC ;
EC31 ADC &0820,X ;
EC34 TAY ;
EC35 LDA &08C4,Y ;
EC38 STA &0814,X ;set in 814+X
EC3B BEQ &EC59 ;and if 0 then EC59
EC3D DEC &0814,X ;decrement
EC40 LDA &0820,X ;and pick up rate of pitch change
EC43 CLC ;
EC44 ADC &0810,X ;
EC47 TAY ;
EC48 LDA &08C1,Y ;
EC4B CLC ;
EC4C ADC &0830,X ;add to rate of differential pitch change
EC4F STA &0830,X ;and save it
EC52 CLC ;
EC53 ADC &080C,X ;ad to base pitch
EC56 JSR &ED01 ;and set new pitch
EC59 CPX #&04 ;if X=4 (last channel)
EC5B BEQ &EC6A ;goto EC6A (RTS)
EC5D JMP &EB59 ;else do loop again
EC60 LDX #&08 ;X=7 again
EC62 DEX ;loop
EC63 JSR &ECA2 ;clear channel
EC66 CPX #&04 ;if not 4
EC68 BNE &EC62 ;do it again
EC6A RTS ;and return
;
EC6B LDA &0808,X ;check for last channel
EC6E CMP #&04 ;is it 4 (release complete)
EC70 BEQ &EC77 ;if so EC77
EC72 LDA #&03 ;else mark release in progress
EC74 STA &0808,X ;and store it
EC77 LDA &02CF,X ;is buffer not empty
EC7A BEQ &EC90 ;if so EC90
EC7C LDA #&00 ;else mark buffer not empty
EC7E STA &02CF,X ;an store it
EC81 LDY #&04 ;loop counter
EC83 STA &082B,Y ;zero sync bytes
EC86 DEY ;
EC87 BNE &EC83 ;until Y=0
EC89 STA &0818,X ;zero duration count
EC8C DEY ;and set sync count to
EC8D STY &0838 ;&FF
EC90 LDA &0828,X ;get synchronising flag
EC93 BEQ &ECDB ;if its 0 then ECDB
EC95 LDA &083B ;else get number of channels on hold
EC98 BEQ &ECD0 ;if 0 then ECD0
EC9A LDA #&00 ;else
EC9C STA &0828,X ;zero note length interval
EC9F JMP &ED98 ;and goto ED98
ECA2 JSR &EB03 ;silence the channel
ECA5 TYA ;Y=0 A=Y
ECA6 STA &0818,X ;zero main count
ECA9 STA &02CF,X ;mark buffer not empty
ECAC STA &0800,X ;mark channel dormant
ECAF LDY #&03 ;loop counter
ECB1 STA &082C,Y ;zero sync flags
ECB4 DEY ;
ECB5 BPL &ECB1 ;
ECB7 STY &0838 ;number of channels to &FF
ECBA BMI &ED06 ;jump to ED06 ALWAYS
ECBC PHP ;save flags
ECBD SEI ;and disable interrupts
ECBE LDA &0808,X ;check for end of release
ECC1 CMP #&04 ;
ECC3 BNE &ECCF ;and if not found ECCF
ECC5 JSR &E45B ;elseexamine buffer
ECC8 BCC &ECCF ;if not empty ECCF
ECCA LDA #&00 ;else mark channel dormant
ECCC STA &0800,X ;
ECCF PLP ;get back flags
ECD0 LDY &0820,X ;if no envelope 820=&FF
ECD3 CPY #&FF ;
ECD5 BNE &ECDA ;then terminate sound
ECD7 JSR &EB03 ;via EB03
ECDA RTS ;else return
;
************ Synchronise sound routines **********************************
ECDB JSR &E45B ;examine buffer if empty carry set
ECDE BCS &ECBC ;
ECE0 AND #&03 ;else examine next word if>3 or 0
ECE2 BEQ &EC9F ;goto ED98 (via EC9F)
ECE4 LDA &0838 ;else get synchronising count
ECE7 BEQ &ECFE ;in 0 (complete) goto ECFE
ECE9 INC &0828,X ;else set sync flag
ECEC BIT &0838 ;if 0838 is +ve S has already been set so
ECEF BPL &ECFB ;jump to ECFB
ECF1 JSR &E45B ;else get first byte
ECF4 AND #&03 ;mask bits 0,1
ECF6 STA &0838 ;and store result
ECF9 BPL &ECFE ;Jump to ECFE (ALWAYS!!)
ECFB DEC &0838 ;decrement 0838
ECFE JMP &ECD0 ;and silence the channel if envelope not in use
************ Pitch setting ***********************************************
ED01 CMP &082C,X ;If A=&82C,X then pitch is unchanged
ED04 BEQ &ECDA ;then exit via ECDA
ED06 STA &082C,X ;store new pitch
ED09 CPX #&04 ;if X<>4 then not noise so
ED0B BNE &ED16 ;jump to ED16
*********** Noise setting ************************************************
ED0D AND #&0F ;convert to chip format
ED0F ORA &EB3C,X ;
ED12 PHP ;save flags
ED13 JMP &ED95 ;and pass to chip control routine at EB22 via ED95
ED16 PHA ;
ED17 AND #&03 ;
ED19 STA &083C ;lose eigth tone surplus
ED1C LDA #&00 ;
ED1E STA &083D ;
ED21 PLA ;get back A
ED22 LSR ;divide by 12
ED23 LSR ;
ED24 CMP #&0C ;
ED26 BCC &ED2F ;
ED28 INC &083D ;store result
ED2B SBC #&0C ;with remainder in A
ED2D BNE &ED24 ;
;at this point 83D defines the Octave
;A the semitone within the octave
ED2F TAY ;Y=A
ED30 LDA &083D ;get octave number into A
ED33 PHA ;push it
ED34 LDA &EDFB,Y ;get byte from look up table
ED37 STA &083D ;store it
ED3A LDA &EE07,Y ;get byte from second table
ED3D PHA ;push it
ED3E AND #&03 ;keep two LS bits only
ED40 STA &083E ;save them
ED43 PLA ;pull second table byte
ED44 LSR ;push hi nybble into lo nybble
ED45 LSR ;
ED46 LSR ;
ED47 LSR ;
ED48 STA &083F ;store it
ED4B LDA &083D ;get back octave number
ED4E LDY &083C ;adjust for surplus eighth tones
ED51 BEQ &ED5F ;
ED53 SEC ;
ED54 SBC &083F ;
ED57 BCS &ED5C ;
ED59 DEC &083E ;
ED5C DEY ;
ED5D BNE &ED53 ;
ED5F STA &083D ;
ED62 PLA ;
ED63 TAY ;
ED64 BEQ &ED6F ;
ED66 LSR &083E ;
ED69 ROR &083D ;
ED6C DEY ;
ED6D BNE &ED66 ;
ED6F LDA &083D ;
ED72 CLC ;
ED73 ADC &C43D,X ;
ED76 STA &083D ;
ED79 BCC &ED7E ;
ED7B INC &083E ;
ED7E AND #&0F ;
ED80 ORA &EB3C,X ;
ED83 PHP ;push P
ED84 SEI ;bar interrupts
ED85 JSR &EB21 ;set up chip access 1
ED88 LDA &083D ;
ED8B LSR &083E ;
ED8E ROR ;
ED8F LSR &083E ;
ED92 ROR ;
ED93 LSR ;
ED94 LSR ;
ED95 JMP &EB22 ;set up chip access 2 and return
**************** Pick up and interpret sound buffer data *****************
ED98 PHP ;push flags
ED99 SEI ;disable interrupts
ED9A JSR &E460 ;read a byte from buffer
ED9D PHA ;push A
ED9E AND #&04 ;isolate H bit
EDA0 BEQ &EDB7 ;if 0 then EDB7
EDA2 PLA ;get back A
EDA3 LDY &0820,X ;if &820,X=&FF
EDA6 CPY #&FF ;envelope is not in use
EDA8 BNE &EDAD ;
EDAA JSR &EB03 ;so call EB03 to silence channel
EDAD JSR &E460 ;clear buffer of redundant data
EDB0 JSR &E460 ;and again
EDB3 PLP ;get back flags
EDB4 JMP &EDF7 ;set main duration count using last byte from buffer
EDB7 PLA ;get back A
EDB8 AND #&F8 ;zero bits 0-2
EDBA ASL ;put bit 7 into carry
EDBB BCC &EDC8 ;if zero (envelope) jump to EDC8
EDBD EOR #&FF ;invert A
EDBF LSR ;shift right
EDC0 SEC ;
EDC1 SBC #&40 ;subtract &40
EDC3 JSR &EB0A ;and set volume
EDC6 LDA #&FF ;A=&FF
EDC8 STA &0820,X ;get envelope no.-1 *16 into A
EDCB LDA #&05 ;set duration sub-counter
EDCD STA &081C,X ;
EDD0 LDA #&01 ;set phase counter
EDD2 STA &0824,X ;
EDD5 LDA #&00 ;set step counter
EDD7 STA &0814,X ;
EDDA STA &0808,X ;and envelope phase
EDDD STA &0830,X ;and pitch differential
EDE0 LDA #&FF ;
EDE2 STA &0810,X ;set step count
EDE5 JSR &E460 ;read pitch
EDE8 STA &080C,X ;set it
EDEB JSR &E460 ;read buffer
EDEE PLP ;
EDEF PHA ;save duration
EDF0 LDA &080C,X ;get back pitch value
EDF3 JSR &ED01 ;and set it
EDF6 PLA ;get back duration
EDF7 STA &0818,X ;set it
EDFA RTS ;and return
********************* Pitch look up table 1*****************************
EDFB DB &F0
EDFC DB &B7
EDFD DB &82
EDFE DB &4F
EDFF DB &20
EE00 DB &F3
EE01 DB &C8
EE02 DB &A0
EE03 DB &7B
EE04 DB &57
EE05 DB &35
EE06 DB &16
********************* Pitch look up table 2 *****************************
EE07 DB &E7
EE08 DB &D7
EE09 DB &CB
EE0A DB &C3
EE0B DB &B7
EE0C DB &AA
EE0D DB &A2
EE0E DB &9A
EE0F DB &92
EE10 DB &8A
EE11 DB &82
EE12 DB &7A
*********: set current filing system ROM/PHROM **************************
EE13 LDA #&EF ;get ROM
EE15 STA &F5 ;store it
EE17 RTS ;return
********** Get byte from data ROM ***************************************
EE18 LDX #&0D ;X=13
EE1A INC &F5 ;
EE1C LDY &F5 ;get Rom
EE1E BPL &EE59 ;if +ve it's a sideways ROM else it's a PHROM
EE20 LDX #&00 ;PHROM
EE22 STX &F7 ;set address pointer in PHROM
EE24 INX ;
EE25 STX &F6 ;to 0001
EE27 JSR &EEBB ;pass info to speech processor
EE2A LDX #&03 ;X=3
EE2C JSR &EE62 ;check for speech processor and output until
;it reports, read byte from ROM
EE2F CMP &DF0C,X ;if A<> DF0C+X then EE18 (DF0C = (C))
EE32 BNE &EE18 ;
EE34 DEX ;else decrement X
EE35 BPL &EE2C ;and do it again
EE37 LDA #&3E ;
EE39 STA &F6 ;get noe lo byte address
EE3B JSR &EEBB ;pass info to speech processor
EE3E LDX #&FF ;
EE40 JSR &EE62 ;check for speech proc. etc.
EE43 LDY #&08 ;
EE45 ASL ;
EE46 ROR &F7,X ;
EE48 DEY ;
EE49 BNE &EE45 ;
EE4B INX ;
EE4C BEQ &EE40 ;
EE4E CLC ;
EE4F BCC &EEBB ;
************ ROM SERVICE ************************************************
EE51 LDX #&0E ;
EE53 LDY &F5 ;if Y is negative (PHROM)
EE55 BMI &EE62 ;GOTO EE62
EE57 LDY #&FF ;else Y=255
EE59 PHP ;push flags
EE5A JSR &F168 ;offer paged rom service
EE5D PLP ;pull processor flags
EE5E CMP #&01 ;if A>0 set carry
EE60 TYA ;A=Y
EE61 RTS ;return
********* PHROM SERVICE *************************************************
;
EE62 PHP ;push processor flags
EE63 SEI ;disable interrupts
EE64 LDY #&10 ;Y=16
EE66 JSR &EE7F ;call EE7F (osbyte 159 write to speech processor
EE69 LDY #&00 ;Y=0
EE6B BEQ &EE84 ;Jump to EE84 (ALWAYS!!)
*************************************************************************
* *
* OSBYTE 158 read from speech processor *
* *
*************************************************************************
EE6D LDY #&00 ;Y=0 to set speech proc to read
EE6F BEQ &EE82 ;jump to EE82 always
;write A to speech processor as two nybbles
EE71 PHA ;push A
EE72 JSR &EE7A ;to write to speech processor
EE75 PLA ;get back A
EE76 ROR ;bring upper nybble to lower nybble
EE77 ROR ;by rotate right
EE78 ROR ;4 times
EE79 ROR ;
EE7A AND #&0F ;Y=lo nybble A +&40
EE7C ORA #&40 ;
EE7E TAY ;forming command for speech processor
*************************************************************************
* *
* OSBYTE 159 Write to speech processor *
* *
*************************************************************************
; on entry data or command in Y
EE7F TYA ;transfer command to A
EE80 LDY #&01 ;to set speech proc to write
;if Y=0 read speech processor
;if Y=1 write speech processor
EE82 PHP ;push flags
EE83 SEI ;disable interrupts
EE84 BIT &027B ;test for prescence of speech processor
EE87 BPL &EEAA ;if not there goto EEAA
EE89 PHA ;else push A
EE8A LDA &F075,Y ;
EE8D STA &FE43 ;set DDRA of system VIA to give 8 bit input (Y=0)
;or 8 bit output (Y=1)
EE90 PLA ;get back A
EE91 STA &FE4F ;and send to speech chip
EE94 LDA &F077,Y ;output Prt B of system VIA
EE97 STA &FE40 ;to select read or write (dependent on Y)
EE9A BIT &FE40 ;loop until
EE9D BMI &EE9A ;speech proceessor reports ready (bit 7 Prt B=0)
EE9F LDA &FE4F ;read speech processor data if input selected
EEA2 PHA ;push A
EEA3 LDA &F079,Y ;reset speech
EEA6 STA &FE40 ;processor
EEA9 PLA ;get back A
EEAA PLP ;get back flags
EEAB TAY ;transfer A to Y
EEAC RTS ;and exit routine
;
EEAD LDA &03CB ;set rom displacement pointer
EEB0 STA &F6 ;in &F6
EEB2 LDA &03CC ;
EEB5 STA &F7 ;And &F7
EEB7 LDA &F5 ;if F5 is +ve ROM is selected so
EEB9 BPL &EED9 ;goto EED9
EEBB PHP ;else push processor
EEBC SEI ;disable interrupts
EEBD LDA &F6 ;get lo displacement
EEBF JSR &EE71 ;pass two nyblles to speech proc.
EEC2 LDA &F5 ;&FA=&F5
EEC4 STA &FA ;
EEC6 LDA &F7 ;get hi displacement value
EEC8 ROL ;replace two most significant bits of A
EEC9 ROL ;by 2 LSBs of &FA
EECA LSR &FA ;
EECC ROR ;
EECD LSR &FA ;
EECF ROR ;
EED0 JSR &EE71 ;pass two nybbles to speech processor
EED3 LDA &FA ;FA has now been divided by 4 so pass
EED5 JSR &EE7A ;lower nybble to speech proc.
EED8 PLP ;get back flags
EED9 RTS ;and Return
;
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/EEDA b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/EEDA new file mode 100644 index 0000000..14e3c49 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/EEDA @@ -0,0 +1 @@ +
************ Keyboard Input and housekeeping ************************
;entered from &F00C
EEDA LDX #&FF ;
EEDC LDA &EC ;get value of most recently pressed key
EEDE ORA &ED ;Or it with previous key to check for presses
EEE0 BNE &EEE8 ;if A=0 no keys pressed so off you go
EEE2 LDA #&81 ;else enable keybd interupt only by writing bit 7
EEE4 STA &FE4E ;and bit 0 of system VIA interupt register
EEE7 INX ;set X=0
EEE8 STX &0242 ;reset keyboard semaphore
**********: Turn on Keyboard indicators *******************************
EEEB PHP ;save flags
EEEC LDA &025A ;read keyboard status;
;Bit 7 =1 shift enabled
;Bit 6 =1 control pressed
;bit 5 =0 shift lock
;Bit 4 =0 Caps lock
;Bit 3 =1 shift pressed
EEEF LSR ;shift Caps bit into bit 3
EEF0 AND #&18 ;mask out all but 4 and 3
EEF2 ORA #&06 ;returns 6 if caps lock OFF &E if on
EEF4 STA &FE40 ;turn on or off caps light if required
EEF7 LSR ;bring shift bit into bit 3
EEF8 ORA #&07 ;
EEFA STA &FE40 ;turn on or off shift lock light
EEFD JSR &F12E ;set keyboard counter
EF00 PLA ;get back flags
EF01 RTS ;return
;
*************************************************************************
* *
* MAIN KEYBOARD HANDLING ROUTINE ENTRY FROM KEYV *
* ========================================================== *
* *
* ENTRY CONDITIONS *
* ================ *
* C=0, V=0 Test Shift and CTRL keys.. exit with N set if CTRL pressed *
* ........with V set if Shift pressed *
* *
* C=1, V=0 Scan Keyboard as OSBYTE &79 *
* *
* C=0, V=1 Key pressed interrupt entry *
* *
* C=1, V=1 Timer interrupt entry *
* *
*************************************************************************
EF02 BVC &EF0E ;if V is clear then leave interrupt routine
EF04 LDA #&01 ;disable keyboard interrupts
EF06 STA &FE4E ;by writing to VIA interrupt vector
EF09 BCS &EF13 ;if timer interrupt then EF13
EF0B JMP &F00F ;else to F00F
EF0E BCC &EF16 ;if test SHFT & CTRL goto EF16
EF10 JMP &F0D1 ;else to F0D1
;to scan keyboard
*************************************************************************
* Timer interrupt entry *
*************************************************************************
EF13 INC &0242 ;increment keyboard semaphore (to 0)
*************************************************************************
* Test Shift and Control Keys entry *
*************************************************************************
EF16 LDA &025A ;read keyboard status;
;Bit 7 =1 shift enabled
;Bit 6 =1 control pressed
;bit 5 =0 shift lock
;Bit 4 =0 Caps lock
;Bit 3 =1 shift pressed
EF19 AND #&B7 ;zero bits 3 and 6
EF1B LDX #&00 ;zero X to test for shift key press
EF1D JSR &F02A ;interrogate keyboard X=&80 if key determined by
;X on entry is pressed
EF20 STX &FA ;save X
EF22 CLV ;clear V
EF23 BPL &EF2A ;if no key press (X=0) then EF2A else
EF25 BIT &D9B7 ;set M and V
EF28 ORA #&08 ;set bit 3 to indicate Shift was pressed
EF2A INX ;check the control key
EF2B JSR &F02A ;via keyboard interrogate
EF2E BCC &EEEB ;if carry clear (entry via EF16) then off to EEEB
;to turn on keyboard lights as required
EF30 BPL &EF34 ;if key not pressed goto EF30
EF32 ORA #&40 ;or set CTRL pressed bit in keyboard status byte in A
EF34 STA &025A ;save status byte
EF37 LDX &EC ;if no key previously pressed
EF39 BEQ &EF4D ;then EF4D
EF3B JSR &F02A ;else check to see if key still pressed
EF3E BMI &EF50 ;if so enter repeat routine at EF50
EF40 CPX &EC ;else compare X with last key pressed (set flags)
EF42 STX &EC ;store X in last key pressed
EF44 BNE &EF4D ;if different from previous (Z clear) then EF4D
EF46 LDX #&00 ;else zero
EF48 STX &EC ;last key pressed
EF4A JSR &F01F ;and reset repeat system
EF4D JMP &EFE9 ;
********** REPEAT ACTION *************************************************
EF50 CPX &EC ;if X<>than last key pressed
EF52 BNE &EF42 ;then back to EF42
EF54 LDA &E7 ;else get value of AUTO REPEAT COUNTDOWN TIMER
EF56 BEQ &EF7B ;if 0 goto EF7B
EF58 DEC &E7 ;else decrement
EF5A BNE &EF7B ;and if not 0 goto EF7B
;this means that either the repeat system is dormant
;or it is not at the end of its count
EF5C LDA &02CA ;next value for countdown timer
EF5F STA &E7 ;store it
EF61 LDA &0255 ;get auto repeat rate from 0255
EF64 STA &02CA ;store it as next value for Countdown timer
EF67 LDA &025A ;get keyboard status
EF6A LDX &EC ;get last key pressed
EF6C CPX #&D0 ;if not SHIFT LOCK key (&D0) goto
EF6E BNE &EF7E ;EF7E
EF70 ORA #&90 ;sets shift enabled, & no caps lock all else preserved
EF72 EOR #&A0 ;reverses shift lock disables Caps lock and Shift enab
EF74 STA &025A ;reset keyboard status
EF77 LDA #&00 ;and set timer
EF79 STA &E7 ;to 0
EF7B JMP &EFE9 ;
EF7E CPX #&C0 ;if not CAPS LOCK
EF80 BNE &EF91 ;goto EF91
EF82 ORA #&A0 ;sets shift enabled and disables SHIFT LOCK
EF84 BIT &FA ;if bit 7 not set by (EF20) shift NOT pressed
EF86 BPL &EF8C ;goto EF8C
EF88 ORA #&10 ;else set CAPS LOCK not enabled
EF8A EOR #&80 ;reverse SHIFT enabled
EF8C EOR #&90 ;reverse both SHIFT enabled and CAPs Lock
EF8E JMP &EF74 ;reset keyboard status and set timer
*********** get ASCII code *********************************************
;on entry X=key pressed internal number
EF91 LDA &EFAB,X ;get code from look up table
EF94 BNE &EF99 ;if not zero goto EF99 else TAB pressed
EF96 LDA &026B ;get TAB character
EF99 LDX &025A ;get keyboard status
EF9C STX &FA ;store it in &FA
EF9E ROL &FA ;rotate to get CTRL pressed into bit 7
EFA0 BPL &EFA9 ;if CTRL NOT pressed EFA9
EFA2 LDX &ED ;get no. of previously pressed key
EFA4 BNE &EF4A ;if not 0 goto EF4A to reset repeat system etc.
EFA6 JSR &EABF ;else perform code changes for CTRL
EFA9 ROL &FA ;move shift lock into bit 7
EFAB BMI &EFB5 ;if not effective goto EFB5 else
EFAD JSR &EA9C ;make code changes for SHIFT
EFB0 ROL &FA ;move CAPS LOCK into bit 7
EFB2 JMP &EFC1 ;and Jump to EFC1
EFB5 ROL &FA ;move CAPS LOCK into bit 7
EFB7 BMI &EFC6 ;if not effective goto EFC6
EFB9 JSR &E4E3 ;else make changes for CAPS LOCK on, return with
;C clear for Alphabetic codes
EFBC BCS &EFC6 ;if carry set goto EFC6 else make changes for
EFBE JSR &EA9C ;SHIFT as above
EFC1 LDX &025A ;if shift enabled bit is clear
EFC4 BPL &EFD1 ;goto EFD1
EFC6 ROL &FA ;else get shift bit into 7
EFC8 BPL &EFD1 ;if not set goto EFD1
EFC8 BPL &EFD1 ;if not set goto EFD1
EFCA LDX &ED ;get previous key press
EFCC BNE &EFA4 ;if not 0 reset repeat system etc. via EFA4
EFCE JSR &EA9C ;else make code changes for SHIFT
EFD1 CMP &026C ;if A<> ESCAPE code
EFD4 BNE &EFDD ;goto EFDD
EFD6 LDX &0275 ;get Escape key status
EFD9 BNE &EFDD ;if ESCAPE returns ASCII code goto EFDD
EFDB STX &E7 ;store in Auto repeat countdown timer
EFDD TAY ;
EFDE JSR &F129 ;disable keyboard
EFE1 LDA &0259 ;read Keyboard disable flag used by Econet
EFE4 BNE &EFE9 ;if keyboard locked goto EFE9
EFE6 JSR &E4F1 ;put character in input buffer
EFE9 LDX &ED ;get previous keypress
EFEB BEQ &EFF8 ;if none EFF8
EFED JSR &F02A ;examine to see if key still pressed
EFF0 STX &ED ;store result
EFF2 BMI &EFF8 ;if pressed goto EFF8
EFF4 LDX #&00 ;else zero X
EFF6 STX &ED ;and &ED
EFF8 LDX &ED ;get &ED
EFFA BNE &F012 ;if not 0 goto F012
EFFC LDY #&EC ;get first keypress into Y
EFFE JSR &F0CC ;scan keyboard from &10 (osbyte 122)
F001 BMI &F00C ;if exit is negative goto F00C
F003 LDA &EC ;else make last key the
F005 STA &ED ;first key pressed i.e. rollover
F007 STX &EC ;save X into &EC
F009 JSR &F01F ;set keyboard repeat delay
F00C JMP &EEDA ;go back to EEDA
*************************************************************************
* Key pressed interrupt entry point *
*************************************************************************
;enters with X=key
F00F JSR &F02A ;check if key pressed
F012 LDA &EC ;get previous key press
F014 BNE &F00C ;if none back to housekeeping routine
F016 LDY #&ED ;get last keypress into Y
F018 JSR &F0CC ;and scan keyboard
F01B BMI &F00C ;if negative on exit back to housekeeping
F01D BPL &F007 ;else back to store X and reset keyboard delay etc.
**************** Set Autorepeat countdown timer **************************
F01F LDX #&01 ;set timer to 1
F021 STX &E7 ;
F023 LDX &0254 ;get next timer value
F026 STX &02CA ;and store it
F029 RTS ;
*************** Interrogate Keyboard routine ***********************
;
F02A LDY #&03 ;stop Auto scan
F02C STY &FE40 ;by writing to system VIA
F02F LDY #&7F ;set bits 0 to 6 of port A to input on bit 7
;output on bits 0 to 6
F031 STY &FE43 ;
F034 STX &FE4F ;write X to Port A system VIA
F037 LDX &FE4F ;read back &80 if key pressed (M set)
F03A RTS ;and return
*************************************************************************
* *
* KEY TRANSLATION TABLES *
* *
* 7 BLOCKS interspersed with unrelated code *
*************************************************************************
*key data block 1
F03B DB 71,33,34,35,84,38,87,2D,5E,8C
; q ,3 ,4 ,5 ,f4,8 ,f7,- ,^ ,rt
*************************************************************************
* *
* OSBYTE 120 Write KEY pressed Data *
* *
*************************************************************************
F045 STY &EC ;store Y as latest key pressed
F047 STX &ED ;store X as previous key pressed
F049 RTS ;and exit
*key data block 2
F04A DB 80,77,65,74,37,69,39,30,5F,8E
; f0,w ,e ,t ,7 ,i ,9 ,0 ,_ ,lft
F055 JMP (&FDFE) ;Jim paged entry vector
F058 JMP (&FA) ;
*key data block 3
F05A DB 31,32,64,72,36,75,6F,70,5B,8F
; 1 ,2 ,d ,r ,6 ,u ,o ,p ,[ ,dn
*************************************************************************
* *
* Main entry to keyboard routines *
* *
*************************************************************************
F065 BIT &D9B7 ;set V and M
F068 JMP (&0228) ;i.e. KEYV
*key data block 4
F06B DB 01,61,78,66,79,6A,6B,40,3A,0D
; CL,a ,x ,f ,y ,j ,k ,@ ,: ,RETN N.B CL=CAPS LOCK
*speech routine data
F075 DB 00,FF,01,02,09,0A
*key data block 5
F07B DB 02,73,63,67,68,6E,6C,3B,5D,7F
; SL,s ,c ,g ,h ,n ,l ,; ,] ,DEL N.B. SL=SHIFT LOCK
*************************************************************************
* *
* OSBYTE 131 READ OSHWM (PAGE in BASIC) *
* *
*************************************************************************
F085 LDY &0244 ;read current OSHWM
F088 LDX #&00 ;
F08A RTS ;
*key data block 6
F08B DB 00 ,7A,20 ,76,62,6D,2C,2E,2F,8B
; TAB,Z ,SPACE,V ,b ,m ,, ,. ,/ ,copy
***** set input buffer number and flush it *****************************
F095 LDX &0241 ;get current input buffer
F098 JMP &E1AD ;flush it
*key data block 7
F09B DB 1B,81,82,83,85,86,88,89,5C,8D
; ESC,f1,f2,f3,f5,f6,f8,f9,\ ,
F0A5 JMP (&0220) ;goto eventV handling routine
*************************************************************************
* *
* OSBYTE 15 FLUSH SELECTED BUFFER CLASS *
* *
*************************************************************************
;flush selected buffer
;X=0 flush all buffers
;X>1 flush input buffer
F0A8 BNE &F095 ;if X<>1 flush input buffer only
F0AA LDX #&08 ;else load highest buffer number (8)
F0AC CLI ;allow interrupts
F0AD SEI ;briefly!
F0AE JSR &F0B4 ;flush buffer
F0B1 DEX ;decrement X to point at next buffer
F0B2 BPL &F0AC ;if X>=0 flush next buffer
;at this point X=255
*************************************************************************
* *
* OSBYTE 21 FLUSH SPECIFIC BUFFER *
* *
*************************************************************************
;on entry X=buffer number
F0B4 CPX #&09 ;is X<9?
F0B6 BCC &F098 ;if so flush buffer or else
F0B8 RTS ;exit
;
*************************************************************************
* *
* Issue *HELP to ROMS *
* *
*************************************************************************
F0B9 LDX #&09 ;
F0BB JSR &F168 ;
F0BE JSR &FA4A ;print following message routine return after BRK
F0C1 DB &0D ;carriage return
F0C2 DS 'OS 1.20' ;help message
F0C9 DB &0D ;carriage return
F0CA BRK ;
F0CB RTS ;
*************************************************************************
* *
* OSBYTE 122 KEYBOARD SCAN FROM &10 (16) *
* *
*************************************************************************
;
F0CC CLC ;clear carry
F0CD LDX #&10 ;set X to 10
;
*************************************************************************
* *
* OSBYTE 121 KEYBOARD SCAN FROM VALUE IN X *
* *
*************************************************************************
F0CF BCS &F068 ;if carry set (by osbyte 121) F068
;Jmps via KEYV and hence back to;
*************************************************************************
* Scan Keyboard C=1, V=0 entry via KEYV *
*************************************************************************
F0D1 TXA ;if X is +ve goto F0D9
F0D2 BPL &F0D9 ;
F0D4 JSR &F02A ;else interrogate keyboard
F0D7 BCS &F12E ;if carry set F12E to set Auto scan else
F0D9 PHP ;push flags
F0DA BCC &F0DE ;if carry clear goto FODE else
F0DC LDY #&EE ;set Y so next operation saves to 2cd
F0DE STA &01DF,Y ;can be 2cb,2cc or 2cd
F0E1 LDX #&09 ;set X to 9
F0E3 JSR &F129 ;select auto scan
F0E6 LDA #&7F ;set port A for input on bit 7 others outputs
F0E8 STA &FE43 ;
F0EB LDA #&03 ;stop auto scan
F0ED STA &FE40 ;
F0F0 LDA #&0F ;select non-existent keyboard column F (0-9 only!)
F0F2 STA &FE4F ;
F0F5 LDA #&01 ;cancel keyboard interrupt
F0F7 STA &FE4D ;
F0FA STX &FE4F ;select column X (9 max)
F0FD BIT &FE4D ;if bit 1 =0 there is no keyboard interrupt so
F100 BEQ &F123 ;goto F123
F102 TXA ;else put column address in A
F103 CMP &01DF,Y ;compare with 1DF+Y
F106 BCC &F11E ;if less then F11E
F108 STA &FE4F ;else select column again
F10B BIT &FE4F ;and if bit 7 is 0
F10E BPL &F11E ;then F11E
F110 PLP ;else push and pull flags
F111 PHP ;
F112 BCS &F127 ;and if carry set goto F127
F114 PHA ;else Push A
F115 EOR &0000,Y ;EOR with EC,ED, or EE depending on Y value
F118 ASL ;shift left
F119 CMP #&01 ;set carry if = or greater than number holds EC,ED,EE
F11B PLA ;get back A
F11C BCS &F127 ;if carry set F127
F11E CLC ;else clear carry
F11F ADC #&10 ;add 16
F121 BPL &F103 ;and do it again if 0=<result<128
F123 DEX ;decrement X
F124 BPL &F0E3 ;scan again if greater than 0
F126 TXA ;
F127 TAX ;
F128 PLP ;pull flags
F129 JSR &F12E ;call autoscan
F12C CLI ;allow interrupts
F12D SEI ;disable interrupts
*************Enable counter scan of keyboard columns *******************
;called from &EEFD, &F129
F12E LDA #&0B ;select auto scan of keyboard
F130 STA &FE40 ;tell VIA
F133 TXA ;Get A into X
F134 RTS ;and return
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/F135 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/F135 new file mode 100644 index 0000000..11211c6 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/F135 @@ -0,0 +1,549 @@ +OS SERIES 9 +GEOFF COX +************************************************************************* +* * +* OSBYTE 140 *TAPE * +* selects TAPE filing system * +* * +* OSBYTE 141 *ROM * +* selects ROM filing system * +* * +************************************************************************* + +F135 EOR #&8C ;if it's *TAPE A=0 *ROM A=1 +F137 ASL ;double it +F138 STA &0247 ;store it in filing system flag store +F13B CPX #&03 ;if X>=3 C set X=3 Z set +F13D JMP &F14B ; + +******** set cassette options ******************************************* + ;called after BREAK etc + ;lower nybble sets sequential access + ;upper sets load and save options + + ;0000 Ignore errors, no messages + ;0001 Abort if error, no messages + ;0010 Retry after error, no messages + ;1000 Ignore error short messages + ;1001 Abort if error short messages + ;1010 Retry after error short messages + ;1100 Ignore error long messages + ;1101 Abort if error long messages + ;1110 Retry after error long messages + + +F140 PHP ;save flags +F141 LDA #&A1 ;set sequential access abort if error, no messages +F143 STA &E3 ;set load/save retry if error, short messages +F145 LDA #&19 ;set interblock gap +F147 STA &03D1 ;and store it +F14A PLP ;get back flags + +F14B PHP ;push flags +F14C LDA #&06 ;get close files command to FSCV +F14E JSR &E031 ;and gosub OSFSC +F151 LDX #&06 ; +F153 PLP ;get back flags +F154 BEQ &F157 ;if Z set earlier +F156 DEX ;do not decrement X +F157 STX &C6 ;set current baud rate X=5 300 baud X=6 1200 baud + +********* reset FILEV,ARGSV,BGETV,BPUTV,GBPBV,FINDV,FSCV ****************** +********** to F27D, F18E, F4C9, F529, FFA6, F3CA, F1B1 ****************** + +F159 LDX #&0E ;RESET VECTORS FOR FILE RELATED OPERATIONS +F15B LDA &D951,X ; +F15E STA &0211,X ; +F161 DEX ; +F162 BNE &F15B ; + +F164 STX &C2 ;&C2=0 PROGRESS FLAG +F166 LDX #&0F ;set X to make Rom service call &F claim vectors! + + + +************************************************************************* +* * +* OSBYTE 143 * +* Pass service commands to sideways ROMs * +* * +************************************************************************* + ; On entry X=service call number + ; Y=any additional parameter + ; On entry X=0 if claimed, or preserved if unclaimed + ; Y=any returned parameter + ; When called internally, EQ set if call claimed + +F168 LDA &F4 ; Get current ROM number +F16A PHA ; Save it +F16B TXA ; Pass service call number to A +F16C LDX #&0F ; Start at ROM 15 + + ; Issue service call loop +F16E INC &02A1,X ; Read bit 7 on ROM type table (no ROM has type 254 &FE) +F171 DEC &02A1,X ; +F174 BPL &F183 ; If not set (+ve result), step to next ROM down +F176 STX &F4 ; Otherwise, select this ROM, &F4 RAM copy +F178 STX &FE30 ; Page in selected ROM +F17B JSR &8003 ; Call the ROM's service entry + ; X and P do not need to be preserved by the ROM +F17E TAX ; On exit pass A to X to chech if claimed +F17F BEQ &F186 ; If 0, service call claimed, reselect ROM and exit +F181 LDX &F4 ; Otherwise, get current ROM back +F183 DEX ; Step to next ROM down +F184 BPL &F16E ; Loop until done ROM 0 + +F186 PLA ; Get back original ROM number +F187 STA &F4 ; Set ROM number RAM copy +F189 STA &FE30 ; Page in the original ROM +F18C TXA ; Pass X back to A to set zero flag +F18D RTS ; And return + + + +************************************************************************* +* * +* CFS OSARGS entry point * +* +************************************************************************* + +F18E ORA #&00 ;is A=00 +F190 BNE &F1A2 ;if not return +F192 CPY #&00 ;is Y=0 +F194 BNE &F1A2 ;if not return +F196 LDA &C6 ;else get current baud rate and zero bit 2 +F198 AND #&FB ;C6=5 becomes 1, 6 becomes 2 +F19A ORA &0247 ;if cassette selected A=0 else A=2 +F19D ASL ;multiply by 2 +F19E ORA &0247 ;Or it again +F1A1 LSR ;divide by 2 +F1A2 RTS ;return cassette =0 + +************************************************************************* +* * +* FSC VECTOR TABLE * +* * +************************************************************************* + +F1A3 DB 4C,F5 ; *OPT (F54C) +F1A5 DB 1D,F6 ; check EOF (F61D) +F1A7 DB 04,F3 ; */ (F304) +F1A9 DB 0F,E3 ; unknown command (E30F) +F1AB DB 04,F3 ; *RUN (F304) +F1AD DB 2A,F3 ; *CAT (F32A) +F1AF DB 74,E2 ; osbyte 77 (E274) + + +************************************************************************* +* Filing System control entry OSFSC * +* Entry via 021E FSCV * +* A= index 0 to 7 * +************************************************************************* + ;on entry A is reason code + ;A=0 A *OPT command has been used X & Y are the 2 parameters + ;A=1 EOF is being checked, on entry X=File handle + on Exit X=FF = EOF exists else 00 + ;A=2 A */ command has been used *RUN the file + ;A=3 An unrecognised OS command has ben used X,Y point at command + ;A=4 A *RUN command has been used X,Y point at filename + ;A=5 A *CAT cammand has been issued X,Y point to rest of command + ;A=6 New filing system about to take over, close SPOOL & EXEC files + ;A=7 Return in X and Y lowest and highest file handle used + ;A=8 OS about to process *command + +F1B1 CMP #&07 ;if A>6 +F1B3 BCS &F1A2 ;goto F1A2 (RTS) +F1B5 STX &BC ;else save X +F1B7 ASL ;A=A*2 +F1B8 TAX ;X=A to get offset +F1B9 LDA &F1A4,X ;get hi byte of address +F1BC PHA ;push it +F1BD LDA &F1A3,X ;get lo byte of address +F1C0 PHA ;push it +F1C1 LDX &BC ;get back X +F1C3 RTS ;this now jumps to the address got from the table +1 + ;the next RTS takes us back to CLI + + + +************************************************************************* +* * +* LOAD FILE * +* * +************************************************************************* + +F1C4 PHP ;save flags on stack +F1C5 PHA ;save A on stack +F1C6 JSR &FB27 ;Set cassette optionsinto (BB),set C7=6 + ;claim serial system for cassette +F1C9 LDA &03C2 ;execution address LO +F1CC PHA ;save A on stack +F1CD JSR &F631 ;search for file +F1D0 PLA ;get back A +F1D1 BEQ &F1ED ;if A=0 F1ED +F1D3 LDX #&03 ;else X=3 +F1D5 LDA #&FF ;A=&FF +F1D7 PHA ;save A on stack +F1D8 LDA &03BE,X ;get load address +F1DB STA &B0,X ;store it as current load address +F1DD PLA ;get back A +F1DE AND &B0,X ; +F1E0 DEX ;X=X-1 +F1E1 BPL &F1D7 ;until all 4 bytes copied + +F1E3 CMP #&FF ;if all bytes contain don't contain &FF +F1E5 BNE &F1ED ;continue +F1E7 JSR &FAE8 ;else sound bell, reset ACIA & motor off +F1EA JMP &E267 ;'Bad Address' error + +F1ED LDA &03CA ;block flag +F1F0 LSR ;set carry from bit 0 +F1F1 PLA ;get back A +F1F2 BEQ &F202 ;if A=0 F202 +F1F4 BCC &F209 ;if carry clear F209 + + +*************** LOCKED FILE ROUTINE ************************************* + +F1F6 JSR &FAF2 ;enable second processor and reset serial system + +F1F9 BRK ; +F1FA DB &E5 ;error number +F1FC 'Locked' ; +F201 BRK ; + + +F202 BCC &F209 ;if carry clear F209 +F204 LDA #&03 ;else A=3 +F206 STA &0258 ;store to cause ESCAPE disable and memory + ;clear on break + +F209 LDA #&30 ; +F20B AND &BB ;current OPTions +F20D BEQ &F213 ;if options and #&30 =0 ignore error condition is set +F20F LDA &C1 ;else get checksum result +F211 BNE &F21D ;and if not 0 F21D + +F213 TYA ;A=Y +F214 PHA ;save A on stack +F215 JSR &FBBB ;read from second processor if present +F218 PLA ;get back A +F219 TAY ;Y=A +F21A JSR &F7D5 ;reset flags and check block length +F21D JSR &F9B4 ;load file from tape +F220 BNE &F255 ;if not found return to search +F222 JSR &FB69 ;increment current block number +F225 BIT &03CA ;block flag +F228 BMI &F232 ;if bit 7=1 then this is last block so F232 +F22A JSR &F96A ;else increment current load address +F22D JSR &F77B ;read block header +F230 BNE &F209 ;and goto F209 + +******** store data in OSFILE parameter block *************************** + +F232 LDY #&0A ;Y=&0A +F234 LDA &CC ;file length counter lo +F236 STA (&C8),Y ;OSFILE parameter block +F238 INY ;Y=Y+1 +F239 LDA &CD ;file length counter hi +F23B STA (&C8),Y ;OSFILE parameter block +F23D LDA #&00 ;A=0 +F23F INY ;Y=Y+1 +F240 STA (&C8),Y ;OSFILE parameter block +F242 INY ;Y=Y+1 +F243 STA (&C8),Y ;OSFILE parameter block +F245 PLP ;get back flags +F246 JSR &FAE8 ;bell, reset ACIA & motor +F249 BIT &BA ;current block flag +F24B BMI &F254 ;return +F24D PHP ;save flags on stack +F24E JSR &FA46 ; print message following call (in this case NEWLINE!) +F251 DB &0D,&00 ;message +F254 RTS ;return + ; +************RETRY AFTER A FAILURE ROUTINE ******************************* + +F255 JSR &F637 ;search for a specified block +F258 BNE &F209 ;goto F209 + + + +*********** Read Filename using Command Line Interpreter **************** + +;filename pointed to by X and Y + +F25A STX &F2 ;OS filename/command line pointer lo +F25C STY &F3 ;OS filename/command line pointer +F25E LDY #&00 ;Y=0 +F260 JSR &EA1D ;initialise string +F263 LDX #&00 ;X=0 +F265 JSR &EA2F ;GSREAD call +F268 BCS &F277 ;if end of character string F277 +F26A BEQ &F274 ;if 0 found F274 +F26C STA &03D2,X ;else store character in CFS filename area +F26F INX ;X=X+1 +F270 CPX #&0B ;if X<>11 +F272 BNE &F265 ;then read next +F274 JMP &EA8F ;else Bad String error + + + +************* terminate Filename **************************************** + +F277 LDA #&00 ;terminate filename with 0 +F279 STA &03D2,X ; +F27C RTS ;return + + + + +************************************************************************* +* * +* OSFILE ENTRY * +* * +* on entry A determines action * +* A=0 save block of memory as a file * +* A=1 write catalogue info for existing file * +* A=2 write load address only for existing file * +* A=3 write execution address only for existing file * +* A=4 write attributes only for existing file * +* A=5 Read catalogue info, return file type in A * +* A=6 Delete named file * +* A=&FF load the named file if lo byte of Exec address=0 use * +* address in parameter block else files own load address * +* X,Y point to parameter block * +* bytes 0,1 filename address, 2-5 load,6-9 exec,A-D length or * +* start of data for save, 0E End address /attributes * +************************************************************************* + +;parameter block located by XY +;0/1 Address of Filename terminated by &0D +;2/4 Load Address of File +;6/9 Execution Address of File +;A/D Start address of data for write operations or length of file +; for read operations +;E/11 End address of Data; i.e. byte AFTER last byte to be written +; or file attributes +; +;On Entry action is determined by value in A +; +;A=0 Save section of memory as named file, write catalogue information +;A=1 Write catalogue information for named file +;A=2 Write the LOAD address (only) for the named File +;A=3 Write the EXECUTION address (only) for the named File +;A=4 Write the ATTRIBUTES for the named File +;A=5 Read the named files catalogue information Place file type in A +;A=6 Delete the named file +;A=&FF Load the named file and read its catalogue information + +F27D PHA ;save A on stack +F27E STX &C8 ;osfile block pointer lo +F280 STY &C9 ;osfile block pointer hi +F282 LDY #&00 ;Y=0 +F284 LDA (&C8),Y ;OSFILE parameter block +F286 TAX ;X=A +F287 INY ;Y=Y+1 +F288 LDA (&C8),Y ;OSFILE parameter block +F28A TAY ;Y=A +F28B JSR &F25A ;get filename from BUFFER +F28E LDY #&02 ;Y=2 + +F290 LDA (&C8),Y ;copy parameters to Cassette block at 3BE/C5 +F292 STA &03BC,Y ;from LOAD and EXEC address +F295 STA &00AE,Y ;make second copy at B0-B8 +F298 INY ;Y=Y+1 +F299 CPY #&0A ;until Y=10 +F29B BNE &F290 ; + +F29D PLA ;get back A +F29E BEQ &F2A7 ;if A=0 F2A7 +F2A0 CMP #&FF ;else if A<>&FF +F2A2 BNE &F254 ;RETURN as cassette has no other options +F2A4 JMP &F1C4 ;load file + + +************** Save a file ********************************************** + +F2A7 STA &03C6 ;zero block number +F2AA STA &03C7 ;zero block number hi + +F2AD LDA (&C8),Y ;OSFILE parameter block +F2AF STA &00A6,Y ;store to Zero page copy (&B0 to &B7) +F2B2 INY ;data start and data end address +F2B3 CPY #&12 ;until Y=18 +F2B5 BNE &F2AD ; +F2B7 TXA ;A=X +F2B8 BEQ &F274 ;if X=0 no filename found so B274 else BAD STRING error + +F2BA JSR &FB27 ;Set cassette option sinto (BB),set C7=6 + ;claim serial system for cassette +F2BD JSR &F934 ;prompt to start recording + +F2C0 LDA #&00 ;A=0 +F2C2 JSR &FBBD ;enable 2nd proc. if present and set up osfile block +F2C5 JSR &FBE2 ;set up CFS for write operation +F2C8 SEC ;set carry flag +F2C9 LDX #&FD ;X=&FD + +F2CB LDA &FFB7,X ;set 03C8/A block length and block flag +F2CE SBC &FFB3,X ;to B4/6-B0/2 the number of pages (blocks) to be + ;saved +F2D1 STA &02CB,X ; +F2D4 INX ;X=X+1 +F2D5 BNE &F2CB ; + +F2D7 TAY ;Y=A +F2D8 BNE &F2E8 ;if last byte is non zero F2E8 else +F2DA CPX &03C8 ;compare X with block length +F2DD LDA #&01 ;A=1 +F2DF SBC &03C9 ;subtract block length hi +F2E2 BCC &F2E8 ;if carry clear F2E8 + +F2E4 LDX #&80 ;X=&80 +F2E6 BNE &F2F0 ;jump F2F0 + +F2E8 LDA #&01 ;A=1 +F2EA STA &03C9 ;block length hi +F2ED STX &03C8 ;block length +F2F0 STX &03CA ;block flag +F2F3 JSR &F7EC ;write block to Tape +F2F6 BMI &F341 ;return if negative +F2F8 JSR &F96A ;increment current load address +F2FB INC &03C6 ;block number +F2FE BNE &F2C8 ;if not 0 loop back again else +F300 INC &03C7 ;block number hi +F303 BNE &F2C8 ;and loop back again + + + +************************************************************************* +* * +* *RUN ENTRY * +* * +************************************************************************* + +F305 JSR &F25A ;get filename from BUFFER +F308 LDX #&FF ;X=&FF +F30A STX &03C2 ;execution address +F30D JSR &F1C4 ;load file +F310 BIT &027A ;&FF if tube present +F313 BPL &F31F ;so if not present F31F else +F315 LDA &03C4 ;execution address extend +F318 AND &03C5 ;execution address extend +F31B CMP #&FF ;if they are NOT both &FF i.e.for base processor +F31D BNE &F322 ;F322 else +F31F JMP (&03C2) ; RUN file + +F322 LDX #&C2 ;point to execution address +F324 LDY #&03 ;(&03C2) +F326 LDA #&04 ;Tube call 4 +F328 JMP &FBC7 ;and issue to Tube to run file + + +************************************************************************* +* * +* *CAT ENTRY * +* * +************************************************************************* + + ;CASSETTE OPTIONS in &E2 + + ;bit 0 input file open + ;bit 1 output file open + ;bit 2,4,5 not used + ;bit 3 current CATalogue status + ;bit 6 EOF reached + ;bit 7 EOF warning given + +F32B LDA #&08 ;A=8 +F32D JSR &F344 ;set status bits from A +F330 JSR &FB27 ;Set cassette options into (BB),set C7=6 + ;claim serial system for cassette +F333 LDA #&00 ;A=0 +F335 JSR &F348 ;read data from CFS/RFS +F338 JSR &FAFC ;perform read +F33B LDA #&F7 ;A=&F7 +F33D AND &E2 ;clear bit 3 of CFS status bit +F33F STA &E2 ; +F341 RTS ;return + ; + +F342 LDA #&40 ;set bit 6 of E2 cassette options +F344 ORA &E2 ; +F346 BNE &F33F ;and Jump F33F + + + +********** search routine *********************************************** + +F348 PHA ;save A on stack +F349 LDA &0247 ;filing system flag 0=CFS 2=RFS +F34C BEQ &F359 ;if CFS F359 else +F34E JSR &EE13 ;set current Filing System ROM/PHROM +F351 JSR &EE18 ;get byte from data Romcheck type +F354 BCC &F359 ;if carry clear F359 else +F356 CLV ;clear overflow flag +F357 BVC &F39A ;JUMP F39A + + +*********** cassette routine******************************************** + +F359 JSR &F77B ;read block header +F35C LDA &03C6 ;block number +F35F STA &B4 ;current block no. lo +F361 LDA &03C7 ;block number hi +F364 STA &B5 ;current block no. hi +F366 LDX #&FF ;X=&FF +F368 STX &03DF ;copy of last read block flag +F36B INX ;X=X+1 +F36C STX &BA ;current block flag +F36E BEQ &F376 ;if 0 F376 + +F370 JSR &FB69 ;inc. current block no. +F373 JSR &F77B ;read block header +F376 LDA &0247 ;get filing system flag 0=CFS 2=RFS +F379 BEQ &F37D ;if CFS F37D +F37B BVC &F39A ;if V clear F39A +F37D PLA ;get back A +F37E PHA ;save A on stack +F37F BEQ &F3AE ;if A=0 F3AE +F381 JSR &FA72 ;else check filename header block matches searched Fn +F384 BNE &F39C ;if so F39C +F386 LDA #&30 ;else A=30 to clear all but bits 4/5 of current OPTions + +F388 AND &BB ;current OPTions +F38A BEQ &F39A ;if 0 F39A else + +F38C LDA &03C6 ;block number +F38F CMP &B6 ;next block no. lo +F391 BNE &F39C ; +F393 LDA &03C7 ;block number hi +F396 CMP &B7 ;next block no. hi +F398 BNE &F39C ; +F39A PLA ;get back A +F39B RTS ;return + ; +F39C LDA &0247 ;filing system flag 0=CFS 2=RFS +F39F BEQ &F3AE ;if tape F3AE +F3A1 JSR &EEAD ;else set ROM displacement address + +F3A4 LDA #&FF ;A=&FF +F3A6 STA &03C6 ;block number +F3A9 STA &03C7 ;block number hi +F3AC BNE &F370 ;jump F370 + +F3AE BVC &F3B5 ;if carry clear F3B5 +F3B0 LDA #&FF ;A=&FF +F3B2 JSR &F7D7 ;set flags +F3B5 LDX #&00 ;X=0 +F3B7 JSR &F9D9 ;report 'DATA?' +F3BA LDA &0247 ;filing system flag 0=CFS 2=RFS +F3BD BEQ &F3C3 ; +F3BF BIT &BB ;current OPTions +F3C1 BVC &F3A1 ;long messages not required if BIT 6 =0 +F3C3 BIT &03CA ;block flag +F3C6 BMI &F3A4 ;if -ve F3A4 +F3C8 BPL &F370 ;else loop back and do it again + + + diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/F3CA b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/F3CA new file mode 100644 index 0000000..7ddf502 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/F3CA @@ -0,0 +1 @@ +*************************************************************************
* *
* OSFIND ENTRY *
* file handling *
* *
*************************************************************************
;on entry A determines Action Y may contain file handle or
;X/Y point to filename terminated by &0D in memory
;A=0 closes file in channel Y if Y=0 closes all files
;A=&40 open a file for input (reading) X/Y points to filename
;A=&80 open a file for output (writing) X/Y points to filename
;A=&C0 open a file for input and output (random access)
;ON EXIT Y=0 if no file found else Y=channel number in use for file
;save A X and Y
F3CA STA &BC ;file status or temporary store
F3CC TXA ;A=X
F3CD PHA ;save X on stack
F3CE TYA ;A=Y
F3CF PHA ;save Y on stack
F3D0 LDA &BC ;file status or temporary store
F3D2 BNE &F3F2 ;if A is non zero open a file via F3F2
************ close a file ***********************************************
F3D4 TYA ;A=Y
F3D5 BNE &F3E3 ;if A<> 0 close specified file else close them all
F3D7 JSR &E275 ;close spool/exec files via OSBYTE 77
F3DA JSR &F478 ;tidy up
F3DD LSR &E2 ;CFS status byte is shifted left and right to zero
F3DF ASL &E2 ;bit 0
F3E1 BCC &F3EF ;and if carry clear no input file was open so F3EF
F3E3 LSR ;A contains file handle so shift bit 0 into carry
F3E4 BCS &F3DD ;if carry set close input file
F3E6 LSR ;else shift bit 1 into carry
F3E7 BCS &F3EC ;if carry set close output file
F3E9 JMP &FBB1 ;else report 'Channel Error' as CFS can only support
;1 input and 1 output file
F3EC JSR &F478 ;tidy up
F3EF JMP &F471 ;and exit
************ OPEN A FILE ************************************************
F3F2 JSR &F25A ;get filename from BUFFER
F3F5 BIT &BC ;file status or temporary store
F3F7 BVC &F436 ;check A at input if bit 6 not set its an output file
********* Input files +**************************************************
F3F9 LDA #&00 ;else its an input file
F3FB STA &039E ;BGET buffer offset for next byte
F3FE STA &03DD ;Expected BGET file block number lo
F401 STA &03DE ;expected BGET file block number hi
F404 LDA #&3E ;A=&3E
F406 JSR &F33D ;CFS status =CFS status AND A
F409 JSR &FB1A ;claim serial system and set OPTions
F40C PHP ;save flags on stack
F40D JSR &F631 ;search for file
F410 JSR &F6B4 ;check protection bit of block status and respond
F413 PLP ;get back flags
F414 LDX #&FF ;X=&FF increment to 0 on next instruction
F416 INX ;X=X+1
F417 LDA &03B2,X ;get file name and
F41A STA &03A7,X ;store as BGET filename
F41D BNE &F416 ;until end of filename
F41F LDA #&01 ;A=1 to show file open
F421 JSR &F344 ;set status bits from A
F424 LDA &02EA ;CFS currently resident file block length lo
F427 ORA &02EB ;CFS currently resident file block length hi
F42A BNE &F42F ;if block length is 0
F42C JSR &F342 ;set CFS status bit 3 (EOF reached)
;else
F42F LDA #&01 ;A=1
F431 ORA &0247 ;filing system flag 0=CFS 2=RFS
F434 BNE &F46F ;and exit after restoring registers
******************* open an output file***********************************
F436 TXA ;A=X
F437 BNE &F43C ;if X=0 then zero length filename so
F439 JMP &EA8F ;Bad String error
F43C LDX #&FF ;X=&FF
F43E INX ;X=X+1
;copy sought filename to header block
F43F LDA &03D2,X ;sought filename
F442 STA &0380,X ;BPUT file header block
F445 BNE &F43E ;until A=0 end of filename
F447 LDA #&FF ;A=&FF
F449 LDX #&08 ;X=8
F44B STA &038B,X ;set 38C/93 to &FF
F44E DEX ;X=X-1
F44F BNE &F44B ;
F451 TXA ;A=X=0
F452 LDX #&14 ;X=14
F454 STA &0380,X ;BPUT file header block
F457 INX ;X=X+1
F458 CPX #&1E ;this zeros 394/D
F45A BNE &F454 ;
F45C ROL &0397 ;
F45F JSR &FB27 ;Set cassette optionsinto (BB),set C7=6
;claim serial system for cassette
F462 JSR &F934 ;prompt to start recording
F465 JSR &FAF2 ;enable second processor and reset serial system
F468 LDA #&02 ;A=2
F46A JSR &F344 ;set status bits from A
F46D LDA #&02 ;A=2
F46F STA &BC ;file status or temporary store
F471 PLA ;get back A
F472 TAY ;Y=A
F473 PLA ;get back A
F474 TAX ;X=A
F475 LDA &BC ;file status or temporary store
F477 RTS ;return
;
F478 LDA #&02 ;A=2 clearing all but bit 1 of status byte
F47A AND &E2 ;CFS status byte, with output file open
F47C BEQ &F477 ;if file not open then exit
F47E LDA #&00 ;else A=0
F480 STA &0397 ;setting block length to current value of BPUT offset
F483 LDA #&80 ;A=&80
F485 LDX &039D ;get BPUT buffer ofset
F488 STX &0396 ;setting block length to current value of BPUT offset
F48B STA &0398 ;mark current block as last
F48E JSR &F496 ;save block to tape
F491 LDA #&FD ;A=&FD
F493 JMP &F33D ;CFS status =CFS status AND A
*********** SAVE BLOCK TO TAPE ********************************************
F496 JSR &FB1A ;claim serial system and set OPTions
F499 LDX #&11 ;X=11
F49B LDA &038C,X ;copy header block from 38C-39D
F49E STA &03BE,X ;to 3BE/DF
F4A1 DEX ;X=X-1
F4A2 BPL &F49B ;
;X=&FF
F4A4 STX &B2 ;current load address high word
F4A6 STX &B3 ;current load address high word
F4A8 INX ;X=X+1, (X=0)
F4A9 STX &B0 ;current load address lo byte set to &00
F4AB LDA #&09 ;A=9 to set current load address at &900
F4AD STA &B1 ;current load address
F4AF LDX #&7F ;X=&7F
F4B1 JSR &FB81 ;copy from 301/C+X to 3D2/C sought filename
F4B4 STA &03DF ;copy of last read block flag
F4B7 JSR &FB8E ;switch Motor On
F4BA JSR &FBE2 ;set up CFS for write operation
F4BD JSR &F7EC ;write block to Tape
F4C0 INC &0394 ;block number lo
F4C3 BNE &F4C8 ;
F4C5 INC &0395 ;block number hi
F4C8 RTS ;return
*************************************************************************
* *
* *
* OSBGET get a byte from a file *
* *
* *
*************************************************************************
;on ENTRY Y contains channel number
;on EXIT X and Y are preserved C=0 indicates valid character
; A contains character (or error) A=&FE End Of File
;push X and Y
F4C9 TXA ;A=X
F4CA PHA ;save A on stack
F4CB TYA ;A=Y
F4CC PHA ;save A on stack
F4CD LDA #&01 ;A=1
F4CF JSR &FB9C ;check conditions for OSBGET are OK
F4D2 LDA &E2 ;CFS status byte
F4D4 ASL ;shift bit 7 into carry (EOF warning given)
F4D5 BCS &F523 ;if carry set F523
F4D7 ASL ;shift bit 6 into carry
F4D8 BCC &F4E3 ;if clear EOF not reached F4E3
F4DA LDA #&80 ;else A=&80 setting bit 7 of status byte EOF warning
F4DC JSR &F344 ;set status bits from A
F4DF LDA #&FE ;A=&FE
F4E1 BCS &F51B ;if carry set F51B
F4E3 LDX &039E ;BGET buffer offset for next byte
F4E6 INX ;X=X+1
F4E7 CPX &02EA ;CFS currently resident file block length lo
F4EA BNE &F516 ;read a byte
;else
F4EC BIT &02EC ;block flag of currently resident block
F4EF BMI &F513 ;if bit 7=1 this is the last block so F513 else
F4F1 LDA &02ED ;last character of currently resident block
F4F4 PHA ;save A on stack
F4F5 JSR &FB1A ;claim serial system and set OPTions
F4F8 PHP ;save flags on stack
F4F9 JSR &F6AC ;read in a new block
F4FC PLP ;get back flags
F4FD PLA ;get back A
F4FE STA &BC ;file status or temporary store
F500 CLC ;clear carry flag
F501 BIT &02EC ;block flag of currently resident block
F504 BPL &F51D ;if not last block (bit 7=0)
F506 LDA &02EA ;CFS currently resident file block length lo
F509 ORA &02EB ;CFS currently resident file block length hi
F50C BNE &F51D ;if block size not 0 F51D else
F50E JSR &F342 ;set CFS status bit 6 (EOF reached)
F511 BNE &F51D ;goto F51D
F513 JSR &F342 ;set CFS status bit 6 (EOF reached)
F516 DEX ;X=X-1
F517 CLC ;clear carry flag
F518 LDA &0A00,X ;read byte from cassette buffer
F51B STA &BC ;file status or temporary store
F51D INC &039E ;BGET buffer offset for next byte
F520 JMP &F471 ;exit via F471
F523 BRK ;
F524 DB &DF ;error number
F525 DB 'EOF' ;
F528 BRK ;
*************************************************************************
* *
* *
* OSBPUT WRITE A BYTE TO FILE *
* *
* *
*************************************************************************
;ON ENTRY Y contains channel number A contains byte to be written
F529 STA &C4 ;store A in temorary store
F52B TXA ;and stack X and Y
F52C PHA ;save on stack
F52D TYA ;A=Y
F52E PHA ;save on stack
F52F LDA #&02 ;A=2
F531 JSR &FB9C ;check conditions necessary for OSBPUT are OK
F534 LDX &039D ;BPUT buffer offset for next byte
F537 LDA &C4 ;get back original value of A
F539 STA &0900,X ;Cassette buffer
F53C INX ;X=X+1
F53D BNE &F545 ;if not 0 F545, otherwise buffer is full so
F53F JSR &F496 ;save block to tape
F542 JSR &FAF2 ;enable second processor and reset serial system
F545 INC &039D ;BPUT buffer offset for next byte
F548 LDA &C4 ;get back A
F54A JMP &F46F ;and exit
*************************************************************************
* *
* *
* OSBYTE 139 Select file options *
* *
* *
*************************************************************************
;ON ENTRY Y contains option value X contains option No. see *OPT X,Y
;this applies largely to CFS LOAD SAVE CAT and RUN
;X=1 is message switch
; Y=0 no messages
; Y=1 short messages
; Y=2 gives detailed information on load and execution addresses
;X=2 is error handling
; Y=0 ignore errors
; Y=1 prompt for a retry
; Y=2 abort operation
;X=3 is interblock gap for BPUT# and PRINT#
; Y=0-127 set gap in 1/10ths Second
; Y > 127 use default values
F54D TXA ;A=X
F54E BEQ &F57E ;if A=0 F57E
F550 CPX #&03 ;if X=3
F552 BEQ &F573 ;F573 to set interblock gap
F554 CPY #&03 ;else if Y>2 then BAD COMMAND error
F556 BCS &F55E ;
F558 DEX ;X=X-1
F559 BEQ &F561 ;i.e. if X=1 F561 message control
F55B DEX ;X=X-1
F55C BEQ &F568 ;i.e. if X=2 F568 error response
F55E JMP &E310 ;else E310 to issue Bad Command error
*********** message control *********************************************
F561 LDA #&33 ;to set lower two bits of each nybble as mask
F563 INY ;Y=Y+1
F564 INY ;Y=Y+1
F565 INY ;Y=Y+1
F566 BNE &F56A ;goto F56A
*********** error response *********************************************
F568 LDA #&CC ;setting top two bits of each nybble as mask
F56A INY ;Y=Y+1
F56B AND &E3 ;clear lower two bits of each nybble
F56D ORA &F581,Y ;or with table value
F570 STA &E3 ;store it in &E3
F572 RTS ;return
;setting of &E3
;
;lower nybble sets LOAD options
;upper sets SAVE options
;0000 Ignore errors, no messages
;0001 Abort if error, no messages
;0010 Retry after error, no messages
;1000 Ignore error short messages
;1001 Abort if error short messages
;1010 Retry after error short messages
;1100 Ignore error long messages
;1101 Abort if error long messages
;1110 Retry after error long messages
***********set interblock gap *******************************************
F573 TYA ;A=Y
F574 BMI &F578 ;if Y>127 use default values
F576 BNE &F57A ;if Y<>0 skip next instruction
F578 LDA #&19 ;else A=&19
F57A STA &03D1 ;sequential block gap
F57D RTS ;return
;
F57E TAY ;Y=A
F57F BEQ &F56D ;jump to F56D
*********** DEFAULT OPT VALUES TABLE ************************************
F581 DB &A1 ;%1010 0001
F582 DB &00 ;%0000 0000
F583 DB &22 ;%0010 0010
F584 DB &11 ;%0001 0001
F585 DB &00 ;%0000 0000
F586 DB &88 ;%1000 1000
F587 DB &CC ;%1100 1100
F588 DEC &C0 ;filing system buffer flag
F58A LDA &0247 ;filing system flag 0=CFS 2=RFS
F58D BEQ &F596 ;if CFS F596
F58F JSR &EE51 ;read RFS data rom or Phrom
F592 TAY ;Y=A
F593 CLC ;clear carry flag
F594 BCC &F5B0 ;jump to F5B0
F596 LDA &FE08 ;ACIA status register
F599 PHA ;save A on stack
F59A AND #&02 ;clear all but bits 0,1 A=(0-3)
F59C BEQ &F5A9 ;if 0 F5A9 transmit data register full or RDR empty
F59E LDY &CA ;
F5A0 BEQ &F5A9 ;
F5A2 PLA ;get back A
F5A3 LDA &BD ;character temporary storage
F5A5 STA &FE09 ;ACIA transmit data register
F5A8 RTS ;return
;
F5A9 LDY &FE09 ;read ACIA recieve data register
F5AC PLA ;get back A
F5AD LSR ;bit 2 to carry (data carrier detect)
F5AE LSR ;
F5AF LSR ;
F5B0 LDX &C2 ;progress flag
F5B2 BEQ &F61D ;if &C2=0 exit
F5B4 DEX ;X=X-1
F5B5 BNE &F5BD ;if &C2>1 then F5BD
F5B7 BCC &F61D ;else if carrier tone from cassette detected exit
F5B9 LDY #&02 ;Y=2
F5BB BNE &F61B ;
F5BD DEX ;X=X-1
F5BE BNE &F5D3 ;if &C2>2
F5C0 BCS &F61D ;if carrier tone from cassette not detected exit
F5C2 TYA ;A=Y
F5C3 JSR &FB78 ;set (BE/C0) to 0
F5C6 LDY #&03 ;Y=3
F5C8 CMP #&2A ;is A= to synchronising byte &2A?
F5CA BEQ &F61B ;if so F61B
F5CC JSR &FB50 ;control cassette system
F5CF LDY #&01 ;Y=1
F5D1 BNE &F61B ;goto F61B
F5D3 DEX ;X=X-1
F5D4 BNE &F5E2 ;if &C2>3
F5D6 BCS &F5DC ;
F5D8 STY &BD ;get character read into Y
F5DA BEQ &F61D ;if 0 exit via F61D
F5DC LDA #&80 ;else A=&80
F5DE STA &C0 ;filing system buffer flag
F5E0 BNE &F61D ;and exit
F5E2 DEX ;X=X-1
F5E3 BNE &F60E ;if &C2>4 F60E
F5E5 BCS &F616 ;if carry set F616
F5E7 TYA ;A=Y
F5E8 JSR &F7B0 ;perform CRC
F5EB LDY &BC ;file status or temporary store
F5ED INC &BC ;file status or temporary store
F5EF BIT &BD ;if bit 7 set this is the last byte read
F5F1 BMI &F600 ;so F600
F5F3 JSR &FBD3 ;check if second processor file test tube prescence
F5F6 BEQ &F5FD ;if return with A=0 F5FD
F5F8 STX &FEE5 ;Tube FIFO3
F5FB BNE &F600 ;
F5FD TXA ;A=X restore value
F5FE STA (&B0),Y ;store to current load address
F600 INY ;Y=Y+1
F601 CPY &03C8 ;block length
F604 BNE &F61D ;exit
F606 LDA #&01 ;A=1
F608 STA &BC ;file status or temporary store
F60A LDY #&05 ;Y=5
F60C BNE &F61B ;exit
F60E TYA ;A=Y
F60F JSR &F7B0 ;perform CRC
F612 DEC &BC ;file status or temporary store
F614 BPL &F61D ;exit
F616 JSR &FB46 ;reset ACIA
F619 LDY #&00 ;Y=0
F61B STY &C2 ;progress flag
F61D RTS ;return
*************************************************************************
* *
* FSCV xx - check for end of file *
* *
*************************************************************************
;
F61E PHA ;save A on stack
F61F TYA ;A=Y
F620 PHA ;save Y on stack
F621 TXA ;A=X to put X into Y
F622 TAY ;Y=A
F623 LDA #&03 ;A=3
F625 JSR &FB9C ;confirm file is open
F628 LDA &E2 ;CFS status byte
F62A AND #&40 ;
F62C TAX ;X=A
F62D PLA ;get back A
F62E TAY ;Y=A
F62F PLA ;get back A
F630 RTS ;return
;
F631 LDA #&00 ;A=0
F633 STA &B4 ;current block no. lo
F635 STA &B5 ;current block no. hi
F637 LDA &B4 ;current block no. lo
F639 PHA ;save A on stack
F63A STA &B6 ;next block no. lo
F63C LDA &B5 ;current block no. hi
F63E PHA ;save A on stack
F63F STA &B7 ;next block no. hi
F641 JSR &FA46 ;print message following call
F644 DB 'Searching';
F64C DB &0D ;newline
F64E BRK ;
F64F LDA #&FF ;A=&FF
F651 JSR &F348 ;read data from CFS/RFS
F654 PLA ;get back A
F655 STA &B5 ;current block no. hi
F657 PLA ;get back A
F658 STA &B4 ;current block no. lo
F65A LDA &B6 ;next block no. lo
F65C ORA &B7 ;next block no. hi
F65E BNE &F66D ;
F660 STA &B4 ;current block no. lo
F662 STA &B5 ;current block no. hi
F664 LDA &C1 ;checksum result
F666 BNE &F66D ;
F668 LDX #&B1 ;current load address
F66A JSR &FB81 ;copy from 301/C+X to 3D2/C sought filename
F66D LDA &0247 ;filing system flag 0=CFS 2=RFS
F670 BEQ &F685 ;if cassette F685
F672 BVS &F685 ;
F674 BRK ;
F675 DB &D6 ;Error number
F676 DB 'File Not found'
F684 BRK ;
F685 LDY #&FF ;Y=&FF
F687 STY &03DF ;copy of last read block flag
F68A RTS ;return
;
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/F68B b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/F68B new file mode 100644 index 0000000..1f8ba97 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/F68B @@ -0,0 +1 @@ +******** CLOSE EXEC FILE **********************************************
F68B LDA #&00 ;A=0
*************************************************************************
* *
* *EXEC *
* *
*************************************************************************
F68D PHP ;save flags on stack
F68E STY &E6 ;&E6=Y
F690 LDY &0256 ;EXEC file handle
F693 STA &0256 ;EXEC file handle
F696 BEQ &F69B ;if not 0 close file via OSFIND
F698 JSR OSFIND ;
F69B LDY &E6 ;else Y= original Y
F69D PLP ;get back flags
F69E BEQ &F6AB ;if A=0 on entry exit else
F6A0 LDA #&40 ;A=&40
F6A2 JSR OSFIND ;to open an input file
F6A5 TAY ;Y=A
F6A6 BEQ &F674 ;If Y=0 'File not found' else store
F6A8 STA &0256 ;EXEC file handle
F6AB RTS ;return
******* read a block *************************************************
F6AC LDX #&A6 ;X=&A6
F6AE JSR &FB81 ;copy from 301/C+X to 3D2/C sought filename
F6B1 JSR &F77B ;read block header
F6B4 LDA &03CA ;block flag
F6B7 LSR ;A=A/2 bit 0 into carry to check for locked file
F6B8 BCC &F6BD ;if not set then skip next instruction
F6BA JMP &F1F6 ;'locked' file routine
F6BD LDA &03DD ;Expected BGET file block number lo
F6C0 STA &B4 ; current block no. lo
F6C2 LDA &03DE ;expected BGET file block number hi
F6C5 STA &B5 ;current block no. hi
F6C7 LDA #&00 ;A=0
F6C9 STA &B0 ;current load address
F6CB LDA #&0A ;A=&A setting current load address to the CFS/RFS
F6CD STA &B1 ;current load address buffer at &A00
F6CF LDA #&FF ;A=&FF to set other 2 bytes
F6D1 STA &B2 ;current load address high word
F6D3 STA &B3 ;current load address high word
F6D5 JSR &F7D5 ;reset flags
F6D8 JSR &F9B4 ;load file from tape
F6DB BNE &F702 ;if return non zero F702 else
F6DD LDA &0AFF ;get last character from input buffer
F6E0 STA &02ED ;last character currently resident block
F6E3 JSR &FB69 ;inc. current block no.
F6E6 STX &03DD ;expected BGET file block number lo
F6E9 STY &03DE ;expected BGET file block number hi
F6EC LDX #&02 ;X=2
F6EE LDA &03C8,X ;read bytes from block flag/block length
F6F1 STA &02EA,X ;store into current values of above
F6F4 DEX ;X=X-1
F6F5 BPL &F6EE ;until X=-1 (&FF)
F6F7 BIT &02EC ;block flag of currently resident block
F6FA BPL &F6FF ;
F6FC JSR &F249 ;print newline if needed
F6FF JMP &FAF2 ;enable second processor and reset serial system
F702 JSR &F637 ;search for a specified block
F705 BNE &F6B4 ;if NE check for locked condition else
F707 CMP #&2A ;is it Synchronising byte &2A?
F709 BEQ &F742 ;if so F742
F70B CMP #&23 ;else is it &23 (header substitute in ROM files)
F70D BNE &F71E ;if not BAD ROM error
F70F INC &03C6 ;block number
F712 BNE &F717 ;
F714 INC &03C7 ;block number hi
F717 LDX #&FF ;X=&FF
F719 BIT &D9B7 ;to set V & M
F71C BNE &F773 ;and jump (ALWAYS!!) to F773
F71E LDA #&F7 ;clear bit 3 of RFS status (current CAT status)
F720 JSR &F33D ;RFS status =RFS status AND A
F723 BRK ;and cause error
F724 DB &D7 ;error number
F725 DB 'Bad Rom'
F72C BRK ;
**********: pick up a header ********************************************
F72D LDY &FF ;get ESCAPE flag
F72F JSR &FB90 ;switch Motor on
F732 LDA #&01 ;A=1
F734 STA &C2 ;progress flag
F736 JSR &FB50 ;control serial system
F739 JSR &F995 ;confirm ESC not set and CFS not executing
F73C LDA #&03 ;A=3
F73E CMP &C2 ;progress flag
F740 BNE &F739 ;back until &C2=3
F742 LDY #&00 ;Y=0
F744 JSR &FB7C ;zero checksum bytes
F747 JSR &F797 ;get character from file and do CRC
F74A BVC &F766 ;if V clear on exit F766
F74C STA &03B2,Y ;else store
F74F BEQ &F757 ;or if A=0 F757
F751 INY ;Y=Y+1
F752 CPY #&0B ;if Y<>&B
F754 BNE &F747 ;go back for next character
F756 DEY ;Y=Y-1
F757 LDX #&0C ;X=12
F759 JSR &F797 ;get character from file and do CRC
F75C BVC &F766 ;if V clear on exit F766
F75E STA &03B2,X ;else store byte
F761 INX ;X=X+1
F762 CPX #&1F ;if X<>31
F764 BNE &F759 ;goto F759
F766 TYA ;A=Y
F767 TAX ;X=A
F768 LDA #&00 ;A=0
F76A STA &03B2,Y ;store it
F76D LDA &BE ;CRC workspace
F76F ORA &BF ;CRC workspace
F771 STA &C1 ;Checksum result
F773 JSR &FB78 ;set (BE/C0) to 0
F776 STY &C2 ;progress flag
F778 TXA ;A=X
F779 BNE &F7D4 ;
F77B LDA &0247 ;filing system flag 0=CFS 2=RFS
F77E BEQ &F72D ;if cassette F72D
F780 JSR &EE51 ;read RFS data rom or Phrom
F783 CMP #&2B ;is it ROM file terminator?
F785 BNE &F707 ;if not F707
********* terminator found **********************************************
F787 LDA #&08 ;A=8 isolating bit 3 CAT status
F789 AND &E2 ;CFS status byte
F78B BEQ &F790 ;if clera skip next instruction
F78D JSR &F24D ;print CR if CFS not operational
F790 JSR &EE18 ;get byte from data Rom
F793 BCC &F780 ;if carry set F780
F795 CLV ;clear overflow flag
F796 RTS ;return
**************** get character from file and do CRC *******************
;
F797 LDA &0247 ;filing system flag 0=CFS 2=RFS
F79A BEQ &F7AD ;if cassette F7AD
F79C TXA ;A=X to save X and Y
F79D PHA ;save X on stack
F79E TYA ;A=Y
F79F PHA ;save Y on stack
F7A0 JSR &EE51 ;read RFS data rom or Phrom
F7A3 STA &BD ;put it in temporary storage
F7A5 LDA #&FF ;A=&FF
F7A7 STA &C0 ;filing system buffer flag
F7A9 PLA ;get back Y
F7AA TAY ;Y=A
F7AB PLA ;get back X
F7AC TAX ;X=A
F7AD JSR &F884 ;check for Escape and loop till bit 7 of FS buffer
;flag=1
************************** perform CRC **********************************
F7B0 PHP ;save flags on stack
F7B1 PHA ;save A on stack
F7B2 SEC ;set carry flag
F7B3 ROR &CB ;CRC Bit counter
F7B5 EOR &BF ;CRC workspace
F7B7 STA &BF ;CRC workspace
F7B9 LDA &BF ;CRC workspace
F7BB ROL ;A=A*2 C=bit 7
F7BC BCC &F7CA ;
F7BE ROR ;A=A/2
F7BF EOR #&08 ;
F7C1 STA &BF ;CRC workspace
F7C3 LDA &BE ;CRC workspace
F7C5 EOR #&10 ;
F7C7 STA &BE ;CRC workspace
F7C9 SEC ;set carry flag
F7CA ROL &BE ;CRC workspace
F7CC ROL &BF ;CRC workspace
F7CE LSR &CB ;CRC Bit counter
F7D0 BNE &F7B9 ;
F7D2 PLA ;get back A
F7D3 PLP ;get back flags
F7D4 RTS ;return
;
F7D5 LDA #&00 ;A=0
F7D7 STA &BD ;&BD=character temporary storage buffer=0
F7D9 LDX #&00 ;X=0
F7DB STX &BC ;file status or temporary store
F7DD BVC &F7E9 ;
F7DF LDA &03C8 ;block length
F7E2 ORA &03C9 ;block length hi
F7E5 BEQ &F7E9 ;if 0 F7E9
F7E7 LDX #&04 ;else X=4
F7E9 STX &C2 ;filename length/progress flag
F7EB RTS ;return
*************** SAVE A BLOCK ********************************************
F7EC PHP ;save flags on stack
F7ED LDX #&03 ;X=3
F7EF LDA #&00 ;A=0
F7F1 STA &03CB,X ;clear 03CB/E (RFS EOF+1?)
F7F4 DEX ;X=X-1
F7F5 BPL &F7F1 ;
F7F7 LDA &03C6 ;block number
F7FA ORA &03C7 ;block number hi
F7FD BNE &F804 ;if block =0 F804 else
F7FF JSR &F892 ;generate a 5 second delay
F802 BEQ &F807 ;goto F807
F804 JSR &F896 ;generate delay set by interblock gap
F807 LDA #&2A ;A=&2A
F809 STA &BD ;store it in temporary file
F80B JSR &FB78 ;set (BE/C0) to 0
F80E JSR &FB4A ;set ACIA control register
F811 JSR &F884 ;check for Escape and loop till bit 7 of FS buffer
;flag=1
F814 DEY ;Y=Y-1
F815 INY ;Y=Y+1
F816 LDA &03D2,Y ;move sought filename
F819 STA &03B2,Y ;into filename block
F81C JSR &F875 ;transfer byte to CFS and do CRC
F81F BNE &F815 ;if filename not complet then do it again
******: deal with rest of header ****************************************
F821 LDX #&0C ;X=12
F823 LDA &03B2,X ;get filename byte
F826 JSR &F875 ;transfer byte to CFS and do CRC
F829 INX ;X=X+1
F82A CPX #&1D ;until X=29
F82C BNE &F823 ;
F82E JSR &F87B ;save checksum to TAPE reset buffer flag
F831 LDA &03C8 ;block length
F834 ORA &03C9 ;block length hi
F837 BEQ &F855 ;if 0 F855
F839 LDY #&00 ;else Y=0
F83B JSR &FB7C ;zero checksum bytes
F83E LDA (&B0),Y ;get a data byte
F840 JSR &FBD3 ;check if second processor file test tube prescence
F843 BEQ &F848 ;if not F848 else
F845 LDX &FEE5 ;Tube FIFO3
F848 TXA ;A=X
F849 JSR &F875 ;transfer byte to CFS and do CRC
F84C INY ;Y=Y+1
F84D CPY &03C8 ;block length
F850 BNE &F83E ;
F852 JSR &F87B ;save checksum to TAPE reset buffer flag
F855 JSR &F884 ;check for Escape and loop till bit 7 of FS buffer
;flag=1
F858 JSR &F884 ;check for Escape and loop till bit 7 of FS buffer
;flag=1
F85B JSR &FB46 ;reset ACIA
F85E LDA #&01 ;A=1
F860 JSR &F898 ;generate 0.1 * A second delay
F863 PLP ;get back flags
F864 JSR &F8B9 ;update block flag, PRINT filename (& address if reqd)
F867 BIT &03CA ;block flag
F86A BPL &F874 ;is this last block (bit 7 set)?
F86C PHP ;save flags on stack
F86D JSR &F892 ;generate a 5 second delay
F870 JSR &F246 ;sound bell and abort
F873 PLP ;get back flags
F874 RTS ;return
****************** transfer byte to CFS and do CRC **********************
;
F875 JSR &F882 ;save byte to buffer, transfer to CFS & reset flag
F878 JMP &F7B0 ;perform CRC
***************** save checksum to TAPE reset buffer flag ****************
F87B LDA &BF ;CRC workspace
F87D JSR &F882 ;save byte to buffer, transfer to CFS & reset flag
F880 LDA &BE ;CRC workspace
************** save byte to buffer, transfer to CFS & reset flag ********
F882 STA &BD ;store A in temporary buffer
***** check for Escape and loop untill bit 7 of FS buffer flag=1 ***********
F884 JSR &F995 ;confirm ESC not set and CFS not executing
F887 BIT &C0 ;filing system buffer flag
F889 BPL &F884 ;loop until bit 7 of &C0 is set
F88B LDA #&00 ;A=0
F88D STA &C0 ;filing system buffer flag
F88F LDA &BD ;get temporary store byte
F891 RTS ;return
;
****************** generate a 5 second delay ***************************
F892 LDA #&32 ;A=50
F894 BNE &F898 ;generate delay 100ms *A (5 seconds)
*************** generate delay set by interblock gap ********************
F896 LDA &C7 ;get current interblock flag
*************** generate delay ******************************************
F898 LDX #&05 ;X=5
F89A STA &0240 ;CFS timeout counter
F89D JSR &F995 ;confirm ESC not set and CFS not executing
F8A0 BIT &0240 ;CFS timeout counter (decremented each 20ms)
F8A3 BPL &F89D ;if +ve F89D
F8A5 DEX ;X=X-1
F8A6 BNE &F89A ;
F8A8 RTS ;return
;
************: generate screen reports ***********************************
F8A9 LDA &03C6 ;block number
F8AC ORA &03C7 ;block number hi
F8AF BEQ &F8B6 ;if 0 F8B6
F8B1 BIT &03DF ;copy of last read block flag
F8B4 BPL &F8B9 ;update block flag, PRINT filename (& address if reqd)
F8B6 JSR &F249 ;print newline if needed
************** update block flag, PRINT filename (& address if reqd) ****
F8B9 LDY #&00 ;Y=0
F8BB STY &BA ;current block flag
F8BD LDA &03CA ;block flag
F8C0 STA &03DF ;copy of last read block flag
F8C3 JSR &E7DC ;check if free to print message
F8C6 BEQ &F933 ;if A=0 on return Cassette system is busy
F8C8 LDA #&0D ;else A=&0D :carriage return
F8CA JSR OSWRCH ;print it (note no linefeed as it's via OSWRCH)
F8CD LDA &03B2,Y ;get byte from filename
F8D0 BEQ &F8E2 ;if 0 filename is ended
F8D2 CMP #&20 ;if <SPACE
F8D4 BCC &F8DA ;F8DA
F8D6 CMP #&7F ;if less than DELETE
F8D8 BCC &F8DC ;its a printable character for F8DC else
*******************Control characters in RFS/CFS filename ******************
F8DA LDA #&3F ;else A='?'
F8DC JSR OSWRCH ;and print it
F8DF INY ;Y=Y+1
F8E0 BNE &F8CD ;back to get rest of filename
***************** end of filename ***************************************
F8E2 LDA &0247 ;filing system flag 0=CFS 2=RFS
F8E5 BEQ &F8EB ;if cassette F8EB
F8E7 BIT &BB ;test current OPTions
F8E9 BVC &F933 ;if bit 6 clear no,long messages needed F933
F8EB JSR &F991 ;print a space
F8EE INY ;Y=Y+1
F8EF CPY #&0B ;if Y<11 then
F8F1 BCC &F8E2 ;loop again to fill out filename with spaces
F8F3 LDA &03C6 ;block number
F8F6 TAX ;X=A
F8F7 JSR &F97A ;print ASCII equivalent of hex byte
F8FA BIT &03CA ;block flag
F8FD BPL &F933 ;if not end of file return
F8FF TXA ;A=X
F900 CLC ;clear carry flag
F901 ADC &03C9 ;block length hi
F904 STA &CD ;file length counter hi
F906 JSR &F975 ;print space + ASCII equivalent of hex byte
F909 LDA &03C8 ;block length
F90C STA &CC ;file length counter lo
F90E JSR &F97A ;print ASCII equivalent of hex byte
F911 BIT &BB ;current OPTions
F913 BVC &F933 ;if bit 6 clear no long messages required so F933
F915 LDX #&04 ;X=4
F917 JSR &F991 ;print a space
F91A DEX ;X=X-1
F91B BNE &F917 ;loop to print 4 spaces
F91D LDX #&0F ;X=&0F to point to load address
F91F JSR &F927 ;print 4 bytes from CFS block header
F922 JSR &F991 ;print a space
F925 LDX #&13 ;X=&13 point to Execution address
************** print 4 bytes from CFS block header **********************
F927 LDY #&04 ;loop pointer
F929 LDA &03B2,X ;block header
F92C JSR &F97A ;print ASCII equivalent of hex byte
F92F DEX ;X=X-1
F930 DEY ;Y=Y-1
F931 BNE &F929 ;
F933 RTS ;return
;
*********** print prompt for SAVE on TAPE *******************************
F934 LDA &0247 ;filing system flag 0=CFS 2=RFS
F937 BEQ &F93C ;if cassette F93C
F939 JMP &E310 ;else 'Bad Command error message'
F93C JSR &FB8E ;switch Motor On
F93F JSR &FBE2 ;set up CFS for write operation
F942 JSR &E7DC ;check if free to print message
F945 BEQ &F933 ;if not exit else
F947 JSR &FA46 ; print message following call
F94A DB 'RECORD then RETURN';
F95C BRK ;
F95D JSR &F995 ;confirm CFS not operating, nor ESCAPE flag set
************ wait for RETURN key to be pressed **************************
F960 JSR OSRDCH ;wait for keypress
F963 CMP #&0D ;is it &0D (RETURN)
F965 BNE &F95D ;no then do it again
F967 JMP OSNEWL ;output Carriage RETURN and LINE FEED
************* increment current load address ****************************
F96A INC &B1 ;current load address
F96C BNE &F974 ;
F96E INC &B2 ;current load address high word
F970 BNE &F974 ;
F972 INC &B3 ;current load address high word
F974 RTS ;return
;
************* print a space + ASCII equivalent of hex byte **************
F975 PHA ;save A on stack
F976 JSR &F991 ;print a space
F979 PLA ;get back A
************** print ASCII equivalent of hex byte **********************
F97A PHA ;save A on stack
F97B LSR ;/16 to put high nybble in lo
F97C LSR ;
F97D LSR ;
F97E LSR ;
F97F JSR &F983 ;print its ASCII equivalent
F982 PLA ;get back A
F983 CLC ;clear carry flag
F984 AND #&0F ;clear high nybble
F986 ADC #&30 ;Add &30 to convert 0-9 to ASCII A-F to : ; < = > ?
F988 CMP #&3A ;if A< ASC(':')
F98A BCC &F98E ;goto F98E
F98C ADC #&06 ;else add 7 to convert : ; < = > ? to A B C D E F
F98E JMP OSWRCH ;print character and return
******************** print a space *************************************
F991 LDA #&20 ;A=' '
F993 BNE &F98E ;goto F98E to print it
******************** confirm CFS not operating, nor ESCAPE flag set *****
F995 PHP ;save flags on stack
F996 BIT &EB ;CFS Active flag
F998 BMI &F99E ;
F99A BIT &FF ;if ESCAPE condition
F99C BMI &F9A0 ;goto F9A0
F99E PLP ;get back flags
F99F RTS ;return
;
F9A0 JSR &F33B ;close input file
F9A3 JSR &FAF2 ;enable second processor and reset serial system
F9A6 LDA #&7E ;A=&7E (126) Acknowledge ESCAPE
F9A8 JSR OSBYTE ;OSBYTE Call
F9AB BRK ;
F9AC DB &11 ;error 17
F9AD DB 'Escape' ;
F9B3 BRK ;
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/F9B4 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/F9B4 new file mode 100644 index 0000000..77fe206 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/F9B4 @@ -0,0 +1 @@ +OS SERIES 10
LAST PART
GEOFF COX
****************************** LOAD *************************************
F9B4 TYA ;A=Y
F9B5 BEQ &F9C4 ;
F9B7 JSR &FA46 ; print message following call
F9BA DB &0D ;
F9BB DB 'Loading';
F9C2 DB &0D ;
F9C3 BRK ;
F9C5 STA &BA ;current block flag
F9C6 LDX #&FF ;X=&FF
F9C8 LDA &C1 ;Checksum result
F9CA BNE &F9D9 ;if not 0 F9D9
F9CC JSR &FA72 ;else check filename header block matches searched
;filename if this returns NE then no match
F9CF PHP ;save flags on stack
F9D0 LDX #&FF ;X=&FF
F9D2 LDY #&99 ;Y=&99
F9D4 LDA #&FA ;A=&FA this set Y/A to point to 'File?' FA99
F9D6 PLP ;get back flags
F9D7 BNE &F9F5 ;report a query unexpected file name
F9D9 LDY #&8E ;making Y/A point to 'Data' FA8E for CRC error
F9DB LDA &C1 ;Checksum result
F9DD BEQ &F9E3 ;if 0 F9E3
F9DF LDA #&FA ;A=&FA
F9E1 BNE &F9F5 ;jump to F9F5
F9E3 LDA &03C6 ;block number
F9E6 CMP &B4 ;current block no. lo
F9E8 BNE &F9F1 ;if not eual F9F1
F9EA LDA &03C7 ;block number hi
F9ED CMP &B5 ;current block no. hi
F9EF BEQ &FA04 ;if equal FA04
F9F1 LDY #&A4 ;Y=&A4
F9F3 LDA #&FA ;A=&FA point to 'Block?' error unexpected block no.
;at this point an error HAS occurred
F9F5 PHA ;save A on stack
F9F6 TYA ;A=Y
F9F7 PHA ;save Y on stack
F9F8 TXA ;A=X
F9F9 PHA ;save X on stack
F9FA JSR &F8B6 ;print CR if indicated by current block flag
F9FD PLA ;get back A
F9FE TAX ;X=A
F9FF PLA ;get back A
FA00 TAY ;Y=A
FA01 PLA ;get back A
FA02 BNE &FA18 ;jump to FA18
FA04 TXA ;A=X
FA05 PHA ;save A on stack
FA06 JSR &F8A9 ;report
FA09 JSR &FAD6 ;check loading progress, read another byte
FA0C PLA ;get back A
FA0D TAX ;X=A
FA0E LDA &BE ;CRC workspace
FA10 ORA &BF ;CRC workspace
FA12 BEQ &FA8D ;
FA14 LDY #&8E ;Y=&8E
FA16 LDA #&FA ;A=&FA FA8E points to 'Data?'
FA18 DEC &BA ;current block flag
FA1A PHA ;save A on stack
FA1B BIT &EB ;CFS Active flag
FA1D BMI &FA2C ;if active FA2C
FA1F TXA ;A=X
FA20 AND &0247 ;filing system flag 0=CFS 2=RFS
FA23 BNE &FA2C ;
FA25 TXA ;A=X
FA26 AND #&11 ;
FA28 AND &BB ;current OPTions
FA2A BEQ &FA3C ;ignore errors
FA2C PLA ;get back A
FA2D STA &B9 ;store A on &B9
FA2F STY &B8 ;store Y on &B8
FA31 JSR &F68B ;do *EXEC 0 to tidy up
FA34 LSR &EB ;halve CFS Active flag to clear bit 7
FA36 JSR &FAE8 ;bell, reset ACIA & motor
FA39 JMP (&00B8) ;display selected error report
FA3C PLA ;get back A
FA3D INY ;Y=Y+1
FA3E BNE &FA43 ;
FA40 CLC ;clear carry flag
FA41 ADC #&01 ;Add 1
FA43 PHA ;save A on stack
FA44 TYA ;A=Y
FA45 PHA ;save Y on stack
FA46 JSR &E7DC ;check if free to print message
FA49 TAY ;Y=A
FA4A PLA ;get back A
FA4B STA &B8 ;&B8=8
FA4D PLA ;get back A
FA4E STA &B9 ;&B9=A
FA50 TYA ;A=Y
FA51 PHP ;save flags on stack
FA52 INC &B8 ;
FA54 BNE &FA58 ;
FA56 INC &B9 ;
FA58 LDY #&00 ;Y=0
FA5A LDA (&B8),Y ;get byte
FA5C BEQ &FA68 ;if 0 Fa68
FA5E PLP ;get back flags
FA5F PHP ;save flags on stack
FA60 BEQ &FA52 ;if 0 FA52 to get next character
FA62 JSR OSASCI ;else print
FA65 JMP &FA52 ;and do it again
FA68 PLP ;get back flags
FA69 INC &B8 ;increment pointers
FA6B BNE &FA6F ;
FA6D INC &B9 ;
FA6F JMP (&00B8) ;and print error message so no error condition
;occcurs
************ compare filenames ******************************************
FA72 LDX #&FF ;X=&FF inx will mean X=0
FA74 INX ;X=X+1
FA75 LDA &03D2,X ;sought filename byte
FA78 BNE &FA81 ;if not 0 FA81
FA7A TXA ;else A=X
FA7B BEQ &FA80 ;if X=0 A=0 exit
FA7D LDA &03B2,X ;else A=filename byte
FA80 RTS ;return
;
FA81 JSR &E4E3 ;set carry if byte in A is not upper case Alpha
FA84 EOR &03B2,X ;compare with filename
FA87 BCS &FA8B ;if carry set FA8B
FA89 AND #&DF ;else convert to upper case
FA8B BEQ &FA74 ;and if A=0 filename characters match so do it again
FA8D RTS ;return
;
FA8E BRK ;
FA8F DB &D8 ;error number
FA90 DB 'Data' ;
FA96 BRK ;
FA97 BNE &FAAE ;
FA99 BRK ;
FA9A DB &DB ;error number
FA9B DB 'File?' ;
FAA1 BRK ;
FAA2 BNE &FAAE ;
FAA4 BRK ;
FAA5 DB &DA ;error number
FAA6 DB 'Block?'
FAAD BRK ;
FAAE LDA &BA ;current block flag
FAB0 BEQ &FAD3 ;if 0 FAD3 else
FAB2 TXA ;A=X
FAB3 BEQ &FAD3 ;If X=0 FAD3
FAB5 LDA #&22 ;A=&22
FAB7 BIT &BB ;current OPTions checking bits 1 and 5
FAB9 BEQ &FAD3 ;if neither set no retry so FAD3 else
FABB JSR &FB46 ;reset ACIA
FABE TAY ;Y=A
FABF JSR &FA4A ;print following message
FAC2 DB &0D ;Carriage RETURN
FAC3 DB &07 ;BEEP
FAC4 DB 'Rewind Tape' ;
FACF DW &0D0D ;two more newlines
FAD1 BRK ;
FAD2 RTS ;return
;
FAD3 JSR &F24D ;print CR if CFS not operational
FAD6 LDA &C2 ;filename length/progress flag
FAD8 BEQ &FAD2 ;if 0 return else
FADA JSR &F995 ;confirm ESC not set and CFS not executing
FADD LDA &0247 ;filing system flag 0=CFS 2=RFS
FAE0 BEQ &FAD6 ;if CFS FAD6
FAE2 JSR &F588 ;else set up ACIA etc
FAE5 JMP &FAD6 ;and loop back again
********** sound bell, reset ACIA, motor off ****************************
FAE8 JSR &E7DC ;check if free to print message
FAEB BEQ &FAF2 ;enable second processor and reset serial system
FAED LDA #&07 ;beep
FAEF JSR OSWRCH ;
FAF2 LDA #&80 ;
FAF4 JSR &FBBD ;enable 2nd proc. if present and set up osfile block
FAF7 LDX #&00 ;
FAF9 JSR &FB95 ;switch on motor
FAFC PHP ;save flags on stack
FAFD SEI ;prevent IRQ interrupts
FAFE LDA &0282 ;get serial ULA control register setting
FB01 STA &FE10 ;write to serial ULA control register setting
FB04 LDA #&00 ;A=0
FB06 STA &EA ;store A RS423 timeout counter
FB08 BEQ &FB0B ;jump FB0B
FB0A PHP ;save flags on stacksave flags
FB0B JSR &FB46 ;release ACIA (by &FE08=3)
FB0E LDA &0250 ;get last setting of ACIA
FB11 JMP &E189 ;set ACIA and &250 from A before exit
FB14 PLP ;get back flags
FB15 BIT &FF ;if bit 7of ESCAPE flag not set
FB17 BPL &FB31 ;then FB31
FB19 RTS ;else return as unserviced ESCAPE is pending
*************************************************************************
* *
* Claim serial system for sequential Access *
* *
*************************************************************************
FB1A LDA &E3 ;get cassette filing system options byte
;high nybble used for LOAD & SAVE operations
;low nybble used for sequential access
;0000 Ignore errors, no messages
;0001 Abort if error, no messages
;0010 Retry after error, no messages
;1000 Ignore error short messages
;1001 Abort if error short messages
;1010 Retry after error short messages
;1100 Ignore error long messages
;1101 Abort if error long messages
;1110 Retry after error long messages
FB1C ASL ;move low nybble into high nybble
FB1D ASL ;
FB1E ASL ;
FB1F ASL ;
FB20 STA &BB ;current OPTions save into &BB
FB22 LDA &03D1 ;get sequential block gap
FB25 BNE &FB2F ;goto to &FB2F
*************************************************************************
* *
* claim serial system for cassette etc. *
* *
*************************************************************************
FB27 LDA &E3 ;get cassette filing system options byte
;high nybble used for LOAD & SAVE operations
;low nybble used for sequential access
;0000 Ignore errors, no messages
;0001 Abort if error, no messages
;0010 Retry after error, no messages
;1000 Ignore error short messages
;1001 Abort if error short messages
;1010 Retry after error short messages
;1100 Ignore error long messages
;1101 Abort if error long messages
;1110 Retry after error long messages
FB29 AND #&F0 ;clear low nybble
FB2B STA &BB ;as current OPTions
FB2D LDA #&06 ;set current interblock gap
FB2F STA &C7 ;to 6
FB31 CLI ;allow interrupts
FB32 PHP ;save flags on stack
FB33 SEI ;prevent interrupts
FB34 BIT &024F ;check if RS423 is busy
FB37 BPL &FB14 ;if not FB14
FB39 LDA &EA ;see if RS423 has timed out
FB3B BMI &FB14 ;if not FB14
FB3D LDA #&01 ;else load RS423 timeout counter with
FB3F STA &EA ;1 to indicate that cassette has 6850
FB41 JSR &FB46 ;reset ACIA with &FE80=3
FB44 PLP ;get back flags
FB45 RTS ;return
;
FB46 LDA #&03 ;A=3
FB48 BNE &FB65 ;and exit after resetting ACIA
********************** set ACIA control register **********************
FB4A LDA #&30 ;set current ACIA control register
FB4C STA &CA ;to &30
FB4E BNE &FB63 ;and goto FB63
;if bit 7=0 motor off 1=motor on
***************** control cassette system *******************************
FB50 LDA #&05 ;set &FE10 to 5
FB52 STA &FE10 ;setting a transmit baud rate of 300,motor off
FB55 LDX #&FF ;
FB57 DEX ;delay loop
FB58 BNE &FB57 ;
FB5A STX &CA ;&CA=0
FB5C LDA #&85 ;Turn motor on and keep baud rate at 300 recieve
FB5E STA &FE10 ;19200 transmit
FB61 LDA #&D0 ;A=&D0
FB63 ORA &C6 ;
FB65 STA &FE08 ;set up ACIA control register
FB68 RTS ;returnand return
;
FB69 LDX &03C6 ;block number
FB6C LDY &03C7 ;block number hi
FB6F INX ;X=X+1
FB70 STX &B4 ;current block no. lo
FB72 BNE &FB75 ;
FB74 INY ;Y=Y+1
FB75 STY &B5 ;current block no. hi
FB77 RTS ;return
;
FB78 LDY #&00 ;
FB7A STY &C0 ;filing system buffer flag
*****************set (zero) checksum bytes ******************************
FB7C STY &BE ;CRC workspace
FB7E STY &BF ;CRC workspace
FB80 RTS ;return
;
*********** copy sought filename routine ********************************
FB81 LDY #&FF ;Y=&FF
FB83 INY ;Y=Y+1
FB84 INX ;X=X+1
FB85 LDA &0300,X ;
FB88 STA &03D2,Y ;sought filename
FB8B BNE &FB83 ;until end of filename (0)
FB8D RTS ;return
;
FB8E LDY #&00 ;Y=0
********************** switch Motor on **********************************
FB90 CLI ;allow IRQ interrupts
FB91 LDX #&01 ;X=1
FB93 STY &C3 ;store Y as current file handle
********************: control motor ************************************
FB95 LDA #&89 ;do osbyte 137
FB97 LDY &C3 ;get back file handle (preserved thru osbyte)
FB99 JMP OSBYTE ;turn on motor
****************** confirm file is open ********************************
FB9C STA &BC ;file status or temporary store
FB9E TYA ;A=Y
FB9F EOR &0247 ;filing system flag 0=CFS 2=RFS
FBA2 TAY ;Y=A
FBA3 LDA &E2 ;CFS status byte
FBA5 AND &BC ;file status or temporary store
FBA7 LSR ;A=A/2
FBA8 DEY ;Y=Y-1
FBA9 BEQ &FBAF ;
FBAB LSR ;A=A/2
FBAC DEY ;Y=Y-1
FBAD BNE &FBB1 ;
FBAF BCS &FBFE ;
FBB1 BRK ;
FBB2 DB &DE ;error number
FBB3 DB 'Channel' ;
FBBA BRK ;
************* read from second processor ********************************
FBBB LDA #&01 ;A=1
FBBD JSR &FBD3 ;check if second processor file test tube prescence
FBC0 BEQ &FBFE ;if not exit
FBC2 TXA ;A=X
FBC3 LDX #&B0 ;current load address
FBC5 LDY #&00 ;Y=00
FBC7 PHA ;save A on stack
FBC8 LDA #&C0 ;filing system buffer flag
FBCA JSR &0406 ;and out to TUBE
FBCD BCC &FBCA ;
FBCF PLA ;get back A
FBD0 JMP &0406 ;
*************** check if second processor file test tube prescence ******
FBD3 TAX ;X=A
FBD4 LDA &B2 ;current load address high word
FBD6 AND &B3 ;current load address high word
FBD8 CMP #&FF ;
FBDA BEQ &FBE1 ;if &FF then its for base processor
FBDC LDA &027A ;&FF if tube present
FBDF AND #&80 ;to set bit 7 alone
FBE1 RTS ;return
;
******** control ACIA and Motor *****************************************
FBE2 LDA #&85 ;A=&85
FBE4 STA &FE10 ;write to serial ULA control register setting
FBE7 JSR &FB46 ;reset ACIA
FBEA LDA #&10 ;A=16
FBEC JSR &FB63 ;set ACIA to CFS baud rate
FBEF JSR &F995 ;confirm ESC not set and CFS not executing
FBF2 LDA &FE08 ;read ACIA status register
FBF5 AND #&02 ;clear all but bit 1
FBF7 BEQ &FBEF ;if clear FBEF
FBF9 LDA #&AA ;else A=&AA
FBFB STA &FE09 ;transmit data register
FBFE RTS ;return
;
FBFF BRK ;
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/FC00 b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/FC00 new file mode 100644 index 0000000..177d500 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/FC00 @@ -0,0 +1 @@ +************** FRED 1MHz Bus memory-mapped I/O **************************
FC00 ;test hardware
FC10-13 ;teletext
FC14-1F ;Prestel
FC20-27 ;IEEE interface
FC30 ;
FC40-47 ;winchester disc interface
FC50 ;
FC60 ;
FC70 ;
FC80 ;
FC90 ;
FCA0 ;
FCB0 ;
FCC0 ;
FCD0 ;
FCE0 ;
FCF0 ;
FCFF ;paging register for JIM expansion memory
************** JIM 1MHz Bus memory-expansion page ***********************
FD00-FF ;
FDFE ;Ecosoak Vector
************** SHEILA MOS memory-mapped I/O ***************************
;DEVICE WRITE READ
FE00 ;6845 CRTC address register
FE01 ;6845 CRTC register file
FE02 ;Border colour border colour
FE03 ;
FE04 ;
FE05 ;
FE06 ;
FE07 ;
FE08 ;6850 ACIA control register status register
FE09 ;6850 ACIA transmit data recieve data
FE0A ;
FE0B ;
FE0C ;
FE0D ;
FE0E ;
FE0F ;
FE10 ;SERIAL ULA control register
FE11 ;
FE12 ;
FE13 ;
FE14 ;
FE15 ;
FE16 ;
FE17 ;
FE18 ;68B54 ADLC Disable interrupts Econet station ID
FE19 ;
FE1A ;
FE1B ;
FE1C ;
FE1D ;
FE1E ;
FE1F ;
FE20 ;Video ULA control register
FE21 ;Video ULA palette register palette register
FE22 ;
FE23 ;
FE24 ;
FE25 ;
FE26 ;
FE27 ;
FE28 ;
FE29 ;
FE2A ;
FE2B ;
FE2C ;
FE2D ;
FE2E ;
FE2F ;
FE30 ;ROM latch paged ROM ID write only
FE31 ;ALTAIR RAM protect
FE32 ;
FE33 ;
FE34 ;Shadow RAM B+ only note different OS
FE35 ;
FE36 ;
FE37 ;
FE38 ;
FE39 ;
FE3A ;
FE3B ;
FE3C ;
FE3D ;
FE3E ;
FE3F ;
FE40 ;MOS 6522 VIA Output Register B Input Register B
FE41 ;MOS 6522 VIA Output Register A Input Register A
FE42 ;MOS 6522 VIA data direction register B
FE43 ;MOS 6522 VIA data direction register A
FE44 ;MOS 6522 VIA T1C-L latches T1 low Order counter
FE45 ;MOS 6522 VIA T1C-H counter
FE46 ;MOS 6522 VIA T1L-L low order latches
FE47 ;MOS 6522 VIA T1L-H high order latches
FE48 ;MOS 6522 VIA T2C-L latches T2C-L lo order counter
FE49 ;MOS 6522 VIA T2C-H T2 high order counter
FE4A ;MOS 6522 VIA shift register
FE4B ;MOS 6522 VIA auxilliary control register ACR
FE4C ;MOS 6522 VIA Peripheral control register PCR
FE4D ;MOS 6522 VIA Interrupt flag register IFR
FE4E ;MOS 6522 VIA Interrupt enable register IER
FE4F ;MOS 6522 VIA ORB/IRB but no handshake
FE50 ;
FE51 ;
FE52 ;
FE53 ;
FE54 ;
FE55 ;
FE56 ;
FE57 ;
FE58 ;
FE59 ;
FE5A ;
FE5B ;
FE5C ;
FE5D ;
FE5E ;
FE5F ;
FE60 ;USER 6522 VIA Output Register B Input Register B
FE61 ;USER 6522 VIA Output Register A Input Register A
FE62 ;USER 6522 VIA data direction register B
FE63 ;USER 6522 VIA data direction register A
FE64 ;USER 6522 VIA T1C-L latches T1 low Order counter
FE65 ;USER 6522 VIA T1C-H counter
FE66 ;USER 6522 VIA T1L-L low order latches
FE67 ;USER 6522 VIA T1L-H high order latches
FE68 ;USER 6522 VIA T2C-L latches T2C-L lo order counter
FE69 ;USER 6522 VIA T2C-H T2 high order counter
FE6A ;USER 6522 VIA shift register
FE6B ;USER 6522 VIA auxilliary control register ACR
FE6C ;USER 6522 VIA Peripheral control register PCR
FE6D ;USER 6522 VIA Interrupt flag register IFR
FE6E ;USER 6522 VIA Interrupt enable register IER
FE6F ;USER 6522 VIA ORB/IRB but no handshake
FE70 ;
FE71 ;
FE72 ;
FE73 ;
FE74 ;
FE75 ;
FE76 ;
FE77 ;
FE78 ;
FE79 ;
FE7A ;
FE7B ;
FE7C ;
FE7D ;
FE7E ;
FE7F ;
FE80 ;8271 FDC command register status register
FE81 ;8271 FDC parameter register result register
FE82 ;8271 FDC reset register
FE83 ;8271 FDC illegal illegal
FE84 ;8271 FDC data data
FE85 ;
FE86 ;
FE87 ;
FE88 ;
FE89 ;
FE8A ;
FE8B ;
FE8C ;
FE8D ;
FE8E ;
FE8F ;
FE90 ;
FE91 ;
FE92 ;
FE93 ;
FE94 ;
FE95 ;
FE96 ;
FE97 ;
FE98 ;
FE99 ;
FE9A ;
FE9B ;
FE9C ;
FE9D ;
FE9E ;
FE9F ;
FEA0 ;68B54 ADLC control register 1 status register 1
FEA1 ;68B54 ADLC control register 2/3 status register 2/3
FEA2 ;68B54 ADLC Tx FIFO (frame continue) Rx FIFO
FEA3 ;68B54 ADLC Tx FIFO (frame terminate) Rx FIFO
FEA4 ;
FEA5 ;
FEA6 ;
FEA7 ;
FEA8 ;
FEA9 ;
FEAA ;
FEAB ;
FEAC ;
FEAD ;
FEAE ;
FEAF ;
FEB0 ;
FEB1 ;
FEB2 ;
FEB3 ;
FEB4 ;
FEB5 ;
FEB6 ;
FEB7 ;
FEB8 ;
FEB9 ;
FEBA ;
FEBB ;
FEBC ;
FEBD ;
FEBE ;
FEBF ;
FEC0 ;7002 ADC data latch A/D start status
FEC1 ;7002 ADC hi data byte
FEC2 ;7002 ADC lo data byte
FEC3 ;
FEC4 ;
FEC5 ;
FEC6 ;
FEC7 ;
FEC8 ;
FEC9 ;
FECA ;
FECB ;
FECC ;
FECD ;
FECE ;
FECF ;
FED0 ;
FED1 ;
FED2 ;
FED3 ;
FED4 ;
FED5 ;
FED6 ;
FED7 ;
FED8 ;
FED9 ;
FEDA ;
FEDB ;
FEDC ;
FEDD ;
FEDE ;
FEDF ;
FEE0 ;TUBE FIFO1 status register
FEE1 ;TUBE FIFO1
FEE2 ;TUBE FIFO2 status register
FEE3 ;TUBE FIFO2
FEE4 ;TUBE FIFO3 status register
FEE5 ;TUBE FIFO3
FEE6 ;TUBE FIFO4 status register
FEE7 ;TUBE FIFO4
FEE8 ;
FEE9 ;
FEEA ;
FEEB ;
FEEC ;
FEED ;
FEEE ;
FEEF ;
FEF0 ;
FEF1 ;
FEF2 ;
FEF3 ;
FEF4 ;
FEF5 ;
FEF6 ;
FEF7 ;
FEF8 ;
FEF9 ;
FEFA ;
FEFB ;
FEFC ;
FEFD ;
FEFE ;
FEFF ;
********** EXTENDED VECTOR ENTRY POINTS**********************************
;vectors are pointed to &F000 +vector No. vectors may then be directed thru
;a three byte vector table whose XY address is given by osbyte A8, X=0, Y=&FF
;this is set up as lo-hi byte in ROM and ROM number
FF00 JSR &FF51 ;E USERV
FF03 JSR &FF51 ;E BRKV
FF06 JSR &FF51 ;E IRQ1V
FF09 JSR &FF51 ;E IRQ2V
FF0C JSR &FF51 ;E CLIV
FF0F JSR &FF51 ;E BYTEV
FF12 JSR &FF51 ;E WORDV
FF15 JSR &FF51 ;E WRCHV
FF18 JSR &FF51 ;E RDCHV
FF1B JSR &FF51 ;E FILEV
FF1E JSR &FF51 ;E ARGSV
FF21 JSR &FF51 ;E BGETV
FF24 JSR &FF51 ;E BPUTV
FF27 JSR &FF51 ;E GBPBV
FF2A JSR &FF51 ;E FINDV
FF2D JSR &FF51 ;E FSCV
FF30 JSR &FF51 ;E EVENTV
FF33 JSR &FF51 ;E UPTV
FF36 JSR &FF51 ;E NETV
FF39 JSR &FF51 ;E VDUV
FF3C JSR &FF51 ;E KEYV
FF3F JSR &FF51 ;E INSV
FF42 JSR &FF51 ;E REMV
FF45 JSR &FF51 ;E CNPV
FF48 JSR &FF51 ;E IND1V
FF4B JSR &FF51 ;E IND2V
FF4E JSR &FF51 ;E IND3V
;at this point the stack will hold 4 bytes (at least)
;S 0,1 extended vector address
;S 2,3 address of calling routine
;A,X,Y,P will be as at entry
FF51 PHA ;save A on stack
FF52 PHA ;save A on stack
FF53 PHA ;save A on stack
FF54 PHA ;save A on stack
FF55 PHA ;save A on stack
FF56 PHP ;save flags on stack
FF57 PHA ;save A on stack
FF58 TXA ;A=X
FF59 PHA ;save X on stack
FF5A TYA ;A=Y
FF5B PHA ;save Y on stack
FF5C TSX ;get stack pointer into X (&F2 or less)
FF5D LDA #&FF ;A=&FF
FF5F STA &0108,X ;A
FF62 LDA #&88 ;
FF64 STA &0107,X ;
FF67 LDY &010A,X ;this is VECTOR number*3+2!!
FF6A LDA &0D9D,Y ;lo byte of action address
FF6D STA &0105,X ;store it on stack
FF70 LDA &0D9E,Y ;get hi byte
FF73 STA &0106,X ;store it on stack
;at this point stack has YXAP and action address
;followed by return address and 5 more bytes
FF76 LDA &F4 ;
FF78 STA &0109,X ;store original ROM number below this
FF7B LDA &0D9F,Y ;get new rom number
FF7E STA &F4 ;store it as ram copy
FF80 STA &FE30 ;and switch ti that ROM
FF83 PLA ;get back A
FF84 TAY ;Y=A
FF85 PLA ;get back A
FF86 TAX ;X=A
FF87 PLA ;get back A
FF88 RTI ;get back flags and jump to ROM vectored entry
;leaving return address and 5 more bytes on stack
************ return address from ROM indirection ************************
;at this point stack comprises original ROM number,return from JSR &FF51,
;return from original call the return from FF51 is garbage so;
FF89 PHP ;save flags on stack
FF8A PHA ;save A on stack
FF8B TXA ;A=X
FF8C PHA ;save X on stack
FF8D TSX ; (&F7 or less)
FF8E LDA &0102,X ;STORE A AND P OVER
FF91 STA &0105,X ;return address from (JSR &FF51)
FF94 LDA &0103,X ;hiding garbage by duplicating A and X just saved
FF97 STA &0106,X ;
;now we have
;flags,
;A,
;X,
;Rom no.,
;A,
;flags,
;and original return address on stack
;so
FF9A PLA ;get back X
FF9B TAX ;X=A
FF9C PLA ;get back A lose next two bytes
FF9D PLA ;get back A lose
FF9E PLA ;get back A rom number
FF9F STA &F4 ;store it
FFA1 STA &FE30 ;and set it
FFA4 PLA ;get back A
FFA5 PLP ;get back flags
FFA6 RTS ;return and exit pulling original return address
;from stack
;FFA6 is also default input for CFS OSBPGB, VDUV, IND1V,IND2V,IND3V
;as these functions are not implemented by the OS but may be used
;by software or other filing systems or ROMs
*************************************************************************
* *
* OSBYTE &9D FAST BPUT *
* *
*************************************************************************
FFA7 TXA ;A=X
FFA8 BCS &FFD4 ;carry always set, jump to BPUT
*************************************************************************
* *
* OSBYTE &92 READ A BYTE FROM FRED *
* *
************************************************************************* ;
FFAA LDY &FC00,X ;read a byte from FRED area
FFAD RTS ;return
*************************************************************************
* *
* OSBYTE &94 READ A BYTE FROM JIM *
* *
************************************************************************* ;
;
FFAE LDY &FD00,X ;read a byte from JIM area
FFB1 RTS ;return
*************************************************************************
* *
* OSBYTE &96 READ A BYTE FROM SHEILA *
* *
************************************************************************* ;
;
FFB2 LDY &FE00,X ;read a byte from SHEILA memory mapped I/O area
FFB5 RTS ;return
*********** DEFAULT VECTOR TABLE ****************************************
FFB6 DB 36 ;length of look up table in bytes
FFB7 DB 40 ;low byte of address of this table
FFB8 DB D9 ;high byte of address of this table
**************************************************************************
**************************************************************************
** **
** OPERATING SYSTEM FUNCTION CALLS **
** **
**************************************************************************
**************************************************************************
FFB9 JMP &DC0B ;OSRDRM get a byte from sideways ROM
FFBC JMP &C4C0 ;VDUCHR VDU character output
FFBF JMP &E494 ;OSEVEN generate an EVENT
FFC2 JMP &EA1E ;GSINIT initialise OS string
FFC5 JMP &EA2F ;GSREAD read character from input stream
FFC8 JMP &DEC5 ;NVRDCH non vectored OSRDCH
FFCB JMP &E0A4 ;NVWRCH non vectored OSWRCH
FFCE JMP (&021C) ;OSFIND open or close a file
FFD1 JMP (&021A) ;OSGBPB transfer block to or from a file
FFD4 JMP (&0218) ;OSBPUT save a byte to file
FFD7 JMP (&0216) ;OSBGET get a byte from file
FFDA JMP (&0214) ;OSARGS read or write file arguments
FFDD JMP (&0212) ;OSFILE read or write a file
FFE0 JMP (&0210) ;OSRDCH get a byte from current input stream
FFE3 CMP #&0D ;OSASCI output a byte to VDU stream expanding
FFE5 BNE &FFEE ; carriage returns (&0D) to LF/CR (&0A,&0D)
FFE7 LDA #&0A ;OSNEWL output a CR/LF to VDU stream
FFE9 JSR OSWRCH ;Outputs A followed by CR to VDU stream
FFEC LDA #&0D ;OSWRCR output a CR to VDU stream
FFEE JMP (&020E) ;OSWRCH output a character to the VDU stream
FFF1 JMP (&020C) ;OSWORD perform operation using parameter table
FFF4 JMP (&020A) ;OSBYTE perform operation with single bytes
FFF7 JMP (&0208) ;OSCLI pass string to command line interpreter
*************************************************************************
* *
* 6502 Vectors *
* *
*************************************************************************
FFFA DW &0D00 ;NMI address
FFFC DW &D9CD ;RESET address
FFFE DW &DC1C ;IRQ address
That's it the end of the series and the end of Micronet.
See you on the new system or in the paper mags.
Geoff
\ No newline at end of file diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/Microbase b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/Microbase new file mode 100644 index 0000000..3251a42 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/Microbase @@ -0,0 +1,1682 @@ +BBC MICROBASE SERIES +BBC 6502 Machine Code by Geoff Cox +---------------------------------- +This series was first published on Micronet +between April and October 1991 + +The BBC Micro Operating System +Part One: The moving electron writes +------------------------------------ +In the last series we reviewed the basics of machine code programming +using the 6502. You will have noticed that not too many examples of +programming were given. This is because there are two levels of +programming on any machine, machine level and operating system level. + +Operating Systems +----------------- +An operating system is basically a group of routines that sit between +the user and the electronics of the computer. To illustrate what an +operating system does we have to turn briefly from the path of the +series. + +We'll imagine that you want to write the letter A on the screen of +your monitor. First we have to work out the shape of the character and +slice it horizontally into eight sections, one for each of eight +screen scanning lines on the monitor. + +Now we need to detect when the frame synchronising pulse for the +monitor is sent by the computer. Next we need to count the line +synchronising pulses to find the one corresponding to the start of the +first line of the character. + +Then we must time from this pulse to the start of the first line of +the character, turn on the appropriate electron guns in the monitor +and turn them off at the correct time for the end of the of the +character. Finally we have a few microseconds to do it all again for +the next line. That's more or less what happens fifty times a second +on your monitor screen. + +Mapped Screens +-------------- +This makes even the easiest task very complex. We can make life easier +by storing a picture or map of the screen in memory and writing the +character shape to the appropriate map locations. + +The map can then be scanned in synchronisation with the electron beam +on the monitor. This can either be via a clever piece of electronics +or a software routine. + +To illustrate the BBC map, type the following program on any 6502- +based BBC without screen RAM shadowing. + +10 MODE 0 +20 ?&7D00=65 + +You should see two little white dots towards the bottom right of the +screen. Now two dots are not the letter A so if we want to write A we +have to designthe character and write it to the map. This program does +just that. + +10 MODE 0 +20 FOR A=&7D00 TO &7D07 +30 READ B +40 ?A=B +50 NEXT +60 DATA &3C, &66, &66, &7E +70 DATA &66, &66, &66, &00 + +The sharp-eyed among you will have spotted something a little odd +here. The screen seems to be arranged in blocks of eight bytes in this +mode. Don't worry about this - it simply makes character table design +simpler. + +Character Tables +---------------- +We can make life even easier by designing a set of characters and +putting them in an area of memory where they can be looked up. In the +BBC B this area is in ROM starting at &C000. + +A quick diversion here. If we have to have a series of character +designs in memory it helps to have a standard method of accessing +them. + +The standard character ordering is called ASCII. A space has ASCII +number 32 and this is the first "printable" character in the set. The +last is 127 (Delete). There are eight bytes in each character matrix +so the design for any character is at &C000+(8*(ASCII - 32)). + +This program examines the ROM character table and shows how characters +are arranged. + +10 MODE 0 +20 PRINT "CHARACTER ?" +30 A$=GET$ +40 PRINT A$ +50 START=(8(ASC(A$)-32))+&C000 +60 FIN=START+7 +70 FOR BYTE=START TO FIN +80 PEEK=?BYTE +90 PROC_BIN +100 PRINT~BYTE;TAB(15);~?BYTE;TAB(20); +110 NEXT +120 END +130 DEFPROC_BIN +140 A$="" +150 FOR BIT=7 TO 0 STEP-1 +160 X=(PEEK AND 2^BIT) +170 IF X>1 THEN A$=A$+"" ELSE A$=A$+"." +180 NEXT +190 ENDPROC + +As you will often want to write characters on the screen it makes a +lot of sense to have a little routine to take a character from a +register and print it on the screen. + +The routine will look up a character in the table and print it to the +appropriate position on the screen. There will also need to be a +record of the cursor position on the screen. + +Routines for printing and moving a cursor on the screen will also be +useful. You could, of course, write all of these routines yourself as +part of every program but as the computer manufacturer has to provide +them in order to tell you the machine is working he usually leaves an +access point for you to use the routines yourself. + +Incidentally if you rewrite the first program but change line 10 to +read MODE 7 you will see a letter A on the screen. + +This is an example of clever electronics. A chip on the BBC board +contains a character generator. Instead of the character design being +stored in the screen map the character's ASCII value is stored. This +is read by the electronics and used to generate characters directly on +the screen. This allows a 40 x 80 text and block graphics screen to be +generated in just 1K of RAM. + +Using the Operating System +-------------------------- +The screen handling routines and several others make up an operating +system. In the BBC micro the series of routines that write a character +on the screen can be accessed though a point called OSWRCH at &FFFE. + +So instead of having to design characters, time lines and do all of +the other things, you can output a letter A to the screen simply +using: + +LDA #65 +JSR &FFEE ;OSWRCH + +and leave the operating system to do the rest. + + +BBC 6502 Machine Code +Part Two: In the beginning +-------------------------- +Last week we looked at the reasons for an operating system and how it +can simplify the programmer's task. Unfortunately you will not always +be able to use the operating system. There may not be a suitable +routine or it may be too slow. In these cases you have to write to the +device itself. So to continue our look at machine code we need to +examine programming with device handling and the operating system. + +This series will attempt to kill two birds with one stone by taking +avery close look at Acorn's OS 1.20 used on Model Bs. + +This changed little for the B+ and Master so while the routines may be +in a slightly different place the basic system will be the same. The +Master uses 65C02 code which has a few extra instructions so there may +be some differences in the length of the code. + +What you will need +------------------ +A disassembler or machine code monitor that can handle 6502 or 65C02 +codes. If If you don't have either you can use: + +PRINT ~?address + +to get the hexadecimal codes which you can then look up in the back of +the BBC User Guide to get the relevant command. + +Suitable Monitors are EXMON, BBC Monitor or the SYSTEM monitor. (I use +"Maxim" - Ed.) If you have a single- stepping monitor like one of +these, you will be able to trace some of the routines for yourself. + +For this series we will use standard 6502 mnemonics except that DB and +DW will be used to show byte assignments rather than EQUS, EQUW and +EQUB. This is because the disassembler I am using produces these codes +and it's a lot easier to follow than convoluted BBC-type statements. + +First things first +------------------ +Remember that an operating system is not a program in the usual sense. +Normal programs have a defined entry and exit routines. An operating +system can have a large number of entry and exit points as well as +interlocking routines. So to examine the operating system we need a +starting point. + +The 6502 regards memory as a series of 256-byte pages 0 to &FF (255). +Any address can be considered to be a page number plus an offset +within the page. Both figures can be represented by a single byte. So +address &FF01 is on Page &FF offset 01. The concept of offsets is very +useful if you ever get involved in 80n86 programming. + +The BBC Manual gives a series of system entry points on page FF. Most +of these are indirected through Page 2 and as we cannot guarantee what +the contents of Page 2 should be (the vectors can be and are changed) +these are useless as starting points. This leaves three sensible entry +points. + +6502 Vectors +FFFA DW &0D00 ;NMI address +FFFC DW &D9CD ;RESET address +FFFE DW &DC1C ;IRQ address + +The NMI address is in RAM so no joy there, but the other two look +fine. The best is RESET as this is where the machine starts when it is +turned on or BREAK is pressed. In the case of Model B and OS 1.20 that +address is &D9CD, so what happens? + +In the beginning +---------------- +Reset can be effected by turning on the computer or pressing BREAK. If +it is a power-up then the system VIA and processor are reset +electronically. + +If this is a power on situation then nothing has been set up. The +first thing that happens when power is turned on is that the 6522 +VIAs, the processor and the floppy disc controller are reset. This is +done by means of one of three printed circuit tracks. The tracks are +RSTA, RST and NOTRESET. + +RSTA is only connected to the system 6522 Versatile Interface adaptor +(VIA). This operates through a little resistor/capacitor circuit that +only works when the power is turned on. The effect of this is that the +6522 System VIA Interrupt Enable Register (IER) bits 0 to 6 will be +clear (0) only if the reset is caused by a power on condition. + +If the Reset is caused by BREAK being pressed then the machine must +have been on and therefore one or more of the System VIA IER bits will +be set (to 1). If one or more bits are set then bit 7 of the VIA will +also be set. This is used to determine the type of Reset. So let's +look at the operating system more closely. + +D9CD LDA #&40 ;set NMI first instruction to RTI +D9CF STA &0D00 ;NMI RAM start + +RESET is the ultimate Act of God as far as the machine is concerned. +Anything could be happening so the operating system has to clean up +the system as its first act. + +These first instructions just make sure that if a disc is running no +more information will be read or written from or to the disc. This +illustrates why you shouldn't press BREAK when a disc is being +accessed! + +The next section sets up the stack: + ++ +D9D2 SEI ;disable interrupts just in case +D9D3 CLD ;clear decimal flag +D9D4 LDX #&FF ;reset stack to where it should be +D9D6 TXS ;(&1FF) + +Next find out if a power-up reset or a BREAK press by examining the +System VIA IER register. + +D9D7 LDA &FE4E ;read interrupt enable register of the system VIA +D9DA ASL ;shift bit 7 into carry +D9DB PHA ;save what's left +D9DC BEQ &D9E7 ;if Power up A=0 so go to D9E7 to clear memory + +That's probably enough for this time. Don't worry! I don't intend to +do a complete disassembly of the operating system in this series but +we will follow through the power-on sequence to the end because a lot +of interesting things happen at this time. + +We'll take a look at D9E7 and the next routine in this sequence (D9DE) +in the next part. + + +BBC 6502 Machine Code +Part Three: Cleaning up the mess +-------------------------------- +In the last part we looked at what happens when you press BREAK or +switch on the machine. We'll now continue with a look at an +undocumented (at least officially) routine. + +The byte at &258 can be used to contain information about what the +machine should do if BREAK is pressed. FX200,n is used to set this +byte. If n=2 or n=3 then the memory must be cleared. This is often +used in program protection. + +D9DE LDA &0258 ;else if BREAK pressed read BREAK Action flags (set by FX200,n) +D9E1 LSR ;divide by 2 +D9E2 CMP #&01 ;if &0258 <> 2 or 3 +D9E4 BNE &DA03 ;then Goto &DA03 +D9E6 LSR ;divide A by 2 again (A=0 if FX200,2/3 else A=n/4 + +Pages 4-&7F are cleared by a simple loop if &258=2 or 3 or it is a +power on reset. Look out for the clever way of avoiding problems on +16K machines. + +D9E7 LDX #&04 ;get page to start clearance from (4) +D9E9 STX &01 ;store it in ZP 01 +D9EB STA &00 ;store A at 00 +D9ED TAY ;and in Y to set loop counter + ;LOOP STARTS +D9EE STA (&00),Y ;clear RAM +D9F0 CMP &01 ;until page address (in &01) =0 +D9F2 BEQ &D9FD ; +D9F4 INY ;increment pointer +D9F5 BNE &D9EE ;if not zero loop round again +D9F7 INY ;else increment again (Y=1) this avoids overwriting the RTI + ;instruction at &D00 +D9F8 INX ;increment X +D9F9 INC &01 ;increment &01 +D9FB BPL &D9EE ;loop until Page (in 01)=&80 then exit + +Note that RAM addressing for 16K loops around to &4000=&00 hence the +checking of &01 for 00. This avoids overwriting zero page on BREAK +which would cause the machine to crash! + +D9FD STX &028E ;writes marker for available RAM 40 =16K,80=32 +DA00 STX &0284 ;write soft key consistency flag + +This routine shows the basic structure of a loop. Those of you who +program in BASIC will recognise it as a very simple structure: + +10 A=A+1 +20 IF A<20 GOTO 10 + +The loop uses zero page addressing with the target address in 00 and +01 (Page) and the index in Y. + +The loop is exited when the value in 01 becomes negative. Remember +that all values between 0 and &7F are considered to be positive, so +the BPL instruction can be used to exit the loop at page &80, the +first negative number. This is the first of the useful loop techniques +we'll see in this series. + +Notice that the first byte of each page is left unchanged. This is +useful if you want information to survive a BREAK of this type. This +clearing of memory is not normally carried out. + +Next week we'll have a look at the normal RESET path. + +BBC 6502 Machine Code +Part Four: Cleaning up even more mess +------------------------------------- +As we saw last week, a normal warm reset avoids the memory clearance +and proceeds to set up the System VIA. + +DA03 LDX #&0F ;set PORT B data direction register to output on bits + ;0-3 and input bits 4-7 +DA05 STX &FE42 ; + +The next bit is a little more complicated and is intimately bound up +with hardware. The function is to set up the addressable latch IC 32 +for peripherals via PORT B. + +The latch value is written by writing the value to &FE40 bits 0 to 2 +and either a 1 or 0 to bit 3. + +Writing the value + 8 therefore writes a 1 to the latched address, +otherwise a 0 is written. + +Value Peripheral Effect ++ 0 8 + +0 Sound chip Enabled Disabled + Speech Chip +1 (RS) Low High +2 (WS) Low High +2 (WS) Low High +3 Keyboard + Write Disabled Enabled +4 C0 address + modifier Low High +5 C1 address + modifier Low High +6 Caps LED On Off +7 Shift LED On Off + +C0 and C1 are involved with hardware scroll screen address. + + ;X=&F on entry +DA08 DEX ;loop start +DA09 STX &FE40 ;Write latch IC32 +DA0C CPX #&09 ;Is it 9? +DA0E BCS &DA08 ;If not go back and do it again + ;X=8 at this point + ;Caps Lock On, SHIFT Lock undetermined + ;Keyboard Autoscan on + ;Sound disabled (may still sound) + +Next the keyboard is scanned to determine the values of the keyboard +links and whether a Ctrl-Break has been performed. + +Remember that although we have spent a lot of time reading this, we +are probably less than 200 microseconds after BREAK was pressed. + +The check for Ctrl-Break is effectively looking for simultaneous +keypresses. + +DA10 INX ;X=9 +DA11 TXA ;A=X +DA12 JSR &F02A ;Interrogate keyboard +DA15 CPX #&80 ;for keyboard links 9-2 and CTRL key (1) +DA17 ROR &FC ;rotate MSB into bit 7 of &FC + +DA19 TAX ;Get back value of X for loop +DA1A DEX ;Decrement it +DA1B BNE &DA11 ;and if >0 do loop again + ;On exit if Carry set link 3 is made + ;link 2 = bit 0 of &FC and so on + ;If CTRL pressed bit 7 of &FC=1 X=0 +DA1D STX &028D ;Clear last BREAK flag +DA20 ROL &FC ;CTRL is now in carry &FC is keyboard links +DA22 JSR &EEEB ;Set LEDs + ;Carry set on entry is in bit 7 of A on exit +DA25 ROR ;Get carry back into carry flag + +To review what the operating system has done so far, about 400 +microseconds after a BREAK press or about 2 milliseconds from a power +on. Memory may have been cleared, NMIs have been short circuited, IRQs +disabled. The keyboard has been scanned for made links and for Ctrl +being pressed. + +We have also located two important and undocumented subroutines: &F02A +to scan the keyboard and &EEEB to set the keyboard LEDs. + +The F02A routine scans for the key whose code is in X being pressed: + +F02A LDY #&03 ;Stop Auto scan +F02C STY &FE40 ;by writing to system VIA +F02F LDY #&7F ;Set bits 0 to 6 of port A to input on bit 7. + ;Output on bits 0 to 6 +F031 STY &FE43 ; +F034 STX &FE4F ;Write X to Port A system VIA (key to check) +F037 LDX &FE4F ;Read back &80 if key pressed (M set) +F03A RTS ;And return + +The routine at &EEEB switches on the selected keyboard lights. + +EEEB PHP ;Save flags +EEEC LDA &025A ;Read keyboard status + ;Bit 7=1 shift enabled + ;Bit 6=1 control pressed + ;Bit 5 =0 shift lock + ;Bit 4 =0 Caps lock + ;Bit 3 =1 shift pressed +EEEF LSR ;Shift Caps bit into bit 3 +EEF0 AND #&18 ;Mask out all but 4 and 3 +EEF2 ORA #&06 ;Returns 6 if caps lock OFF &E if on. + ;Remember add 8 to the value for the addressable + ;latch to send a 1. +EEF4 STA &FE40 ;Turn on or off caps light if required +EEF7 LSR ;Bring shift bit into bit 3 +EEF8 ORA #&07 ; +EEFA STA &FE40 ;Turn on or off shift lock light +EEFD JSR &F12E ;Set keyboard counter +EF00 PLA ;Get back flags into A +EF01 RTS ;Return + +In this part we've had a look at subroutines using JSR and RTS, the +machine code equivalent of GOSUB, PROC or FN. Subroutines are often +used in machine code to perform such frequently needed functions as +scanning a keyboard or turning on and off lights. + +We've also discovered that the byte at &25A contains the keyboard +status. Try changing it for yourself. You can therefore use OR and AND +to set the shift and Caps lock status of the machine for a particular +program. + +Next week we'll examine setting up the default vector table in memory. + +BBC 6502 Machine Code +Part Five: Vectors Victor +------------------------- +The next stage is to set up the vectors on page 2. + +DA26 LDX #&9C ; +DA28 LDY #&8D ; +DA2A PLA ;Get back A from &D9DB +DA2B BEQ &DA36 ;If A=0 power up reset so go to DA36 with X=&9C + ;Y=&8D +DA2D LDY #&7E ;else let Y=&7E +DA2F BCC &DA42 ;and if not CTRL- BREAK go to DA42 for a WARM RESET +DA31 LDY #&87 ;else Y=&87 COLD RESET +DA33 INC &028D ;&28D=1 +DA36 INC &028D ;&28D=&28D+1 +DA39 LDA &FC ;Get keyboard links set +DA3B EOR #&FF ;Invert +DA3D STA &028F ;and store at &28F +DA40 LDX #&90 ;X=&90 + +What we have done is to set up the high water marks for the reset of +vectors. + +&28D=0 Warm reset, X=&9C, Y=&7E +&28D=1 Power up , X=&90, Y=&8D +&28D=2 Cold reset, X=&9C, Y=&87 + +DA42 LDA #&00 ;A=0 +DA44 CPX #&CE ;zero &200+X to &2CD +DA46 BCC &DA4A ; +DA48 LDA #&FF ;then set &2CE to &2FF to &FF +DA4A STA &0200,X ; +DA4D INX ; +DA4E BNE &DA44 ; + ;A=&FF X=0 + +This is another IF-GOTO loop, but in this case it is a double function +loop. The test at DA44 to DA46 means that A is 0 only for values of X +between the high water mark and &CD. Above this value A is set to &FF +by the instruction at &DA48. This saves a few bytes of space, +essential when writing a tightly-filled ROM. + +The next instructions set up the printer port. The only reason for +doing this now is to save two bytes. A must be &FF at this point so it +is used to set up the User VIA for outputs as the printer port. + +DA50 STA &FE63 ;Set port A of user VIA to all outputs (printer out) +DA53 TXA ;A=0 +DA54 LDX #&E2 ;X=&E2 + +START OF LOOP +DA56 STA &00,X ;set zero page addresses &E2 to &FF to zero +DA58 INX ; +DA59 BNE &DA56 ;X=0 + +Now set up the vectors in page 2 from the table at &D940: + +DA5B LDA &D93F,Y ;copy data from &D93F+Y +DA5E STA &01FF,Y ;to &1FF+Y +DA61 DEY ;until +DA62 BNE &DA5B ;1FF+Y=&200 + +Note that this is a decrementing loop which, for loops ending when an +index register reaches zero, is faster and shorter because no compare +is needed. More space saved! + +Now the RS423 port is set up via a subroutine affecting the ACIA. +(Asynchronous Communications Interface Adaptor) + +DA64 LDA #&62 ;A=&62 +DA66 STA &ED ;store in &ED +DA68 JSR &FB0A ;set up ACIA ;X=0 + +Now Acorn clears the interrupt and enable registers of both VIAs. + +DA6B LDA #&7F ;bit 7 is 0! +DA6D INX ; +DA6E STA &FE4D,X ; +DA71 STA &FE6D,X ; +DA74 DEX ; +DA75 BPL &DA6E ; + ;This loop only has two passes as X=0 on entry. +DA77 CLI ;Briefly allow interrupts to clear anything + ;pending +DA78 SEI ;Disallow again NB: all VIA IRQs are disabled +DA79 BIT &FC ;If bit 6=1 then JSR &F055 as there must be a + ;hardware interrupt! +DA7B BVC &DA80 ;else DA80 +DA7D JSR &F055 ; + +What have we here? Another undocumented routine. If bit 6 of &FC is +set there must have been a hardware interrupt when the SEI occurred. + +From the circuit diagram the only place that this IRQ could have come +from is the 1MHz bus - let's have a look at the routine at &F055. + +F055 JMP (&FDFE) ;Jim paged entry vector + +So we jump to some piece of hardware on the 1MHz bus. This would +probably be a ROM which would take over the system at power on and +Break. This has some very interesting applications. It was designed by +Acorn to provide a crude Econet facility to allow a batch of machines +to be functionally tested without the need to install a full Econet +kit. + +Next week we shall examine the VIA bus. + +BBC 6502 Machine Code +Part Six: The VIA bus +--------------------- +The next interesting routine we find in the BBC operating system is +the one that sets up the system VIA interrupts. It is located at +&DA80. Refer to the manual for the meanings of Sheila addresses. + +DA80 LDX #&F2 ;Enable interrupts 1,4,5,6 of system VIA +DA82 STX &FE4E ; + ;0 Keyboard enabled as needed + ;1 Frame sync pulse + ;4 End of A/D conversion + ;5 T2 counter (for speech) + ;6 T1 counter (10 mSec intervals) + +DA85 LDX #&04 ;set system VIA PCR +DA87 STX &FE4C ; + ;CA1 Interrupt on negative edge (Frame sync) + ;CA2 Handshake output for keyboard + ;CB1 Interrupt on negative edge (end of conversion) + ;CB2 Negative edge (Light pen strobe) +DA8A LDA #&60 ;Set system VIA ACR +DA8C STA &FE4B ; + ;Disable latching + ;Disable shift register + ;T1 counter continuous interrupts + ;T2 counter timed interrupt + +DA8F LDA #&0E ;Set system VIA T1 counter (low) +DA91 STA &FE46 ; + ;This becomes effective when T1 hi set +DA94 STA &FE6C ;Set user VIA PCR + ;CA1 interrupt on -ve edge (Printer Acknowledge) +DA80 LDX #&F2 ;enable interrupts + ;CA2 High output (printer strobe) + ;CB1 Interrupt on -ve edge (user port) + ;CB2 Negative edge (user port) +DA97 STA &FEC0 ;Set up A/D converter Bits 0 and 1 determine + ;channel selected + ;If Bit 3=0 it is set for an 8-bit conversion. + ;If bit 3=1 12-bit conversion. + +Now although the machine now knows how much RAM it has it still +doesn't know if it's a Model A or Model B, so it does not know if a +user VIA is present at &FE60-FE6F. + +The next routine tests for the presence of a user VIA. The system +timers are then set up to interrupt every 10mSec. Sound channels are +cleared and the serial ULA is set up. Then the function keys are +reset. + +Now we need a catalogue of sideways ROMS. This is not a catalogue in +the conventional sense as the ROM title is always at the same place in +the ROM itself and can be read from there. It is a catalogue of the +ROM types and positions. + +There is a ROM latch at &FE30. Writing a number between 0 and 15 to +this switches the corresponding ROM into the area between &8000 and +&BFFF. A short subroutine does this and maintains a copy of the +current ROM in zero page at location &F4. + + ;on entry X=required ROM number +DC16 STX &F4 ;RAM copy of ROM latch +DC18 STX &FE30 ;Write to ROM latch +DC1B RTS ;and return + +You should use this subroutine if you want to switch ROMs. Now we can +look at the ROM cataloguing routines; + +A ROM is considered to be valid if it contains a string identical to +astring at location &DF0C in the Operating System ROM. + +DF0C DB ')C(' ; +DF0F DB 0 ; + +The location of this string is pointed to by an offset byte located at +&8007. + +;X=0 on entry +DABD JSR &DC16 ;Set up ROM latch and RAM copy to X +DAC0 LDX #&03 ;Set X to point to offset in table +DA80 LDX #&F2 ;Enable interrupts +DAC2 LDY &8007 ;Get copyright offset from ROM +DAC5 LDA &8000,Y ;Get first byte +DAC8 CMP &DF0C,X ;Compare it with table byte +DACB BNE &DAFB ;If not the same then goto DAFB +DACD INY ;Point to next byte +DACE DEX ;(s) +DACF BPL &DAC5 ;and if still +ve go back to check next byte. + ;This point is reached if 4 bytes indicate + ;valid ROM + +Next the first 1K of each ROM is checked against higher priority ROMs +to ensure that there are no matches. If a match is found, the lower +priority ROM is ignored. + +A ROM type byte is located at &8006. A catalogue of these bytes is +held at &2A1-&2B0. If bit 7 of this byte is 0 then the ROM is BASIC. +The position of this ROM is stored at &24B. + +Now the ROMs are catalogued it is time to set up the speech system and +screen. More about that next week. + +BBC 6502 Machine Code +Part Seven: Talk to me +---------------------- +The operating system start-up routines next checks the SPEECH system. +At this point the X register is set to 16 (&10) by previous routines. + +This is one of the reasons why this routine is inserted here. Setting +X to the required value would use two more bytes. This is not much +space but it can make the difference between all of the OS fitting +into a single ROM and a complete hardware or software redesign. + +DB11 BIT &FE40 ;If bit 7 low then we have speech system fitted +DB14 BMI &DB27 ;else goto DB27 for screen set up routine. +DB16 DEC &027B ;(027B)=&FF a RAM flag that indicates that a speech + ;chip is present. +DB19 LDY #&FF ;Y=&FF +DB1B JSR &EE7F ;Initialise speech generator +DB1E DEX ;via this +DB1F BNE &DB19 ;loop + +Now X = 0 so: + +DB21 STX &FE48 ;Set T2 timer for speech +DB24 STX &FE49 ; + +Screen set-up +------------- +X=0 on entry to this routine which gets the default screen mode and +then goes off to the screen setup routine. + +DB27 LDA &028F ;Get back start up options (mode) +DB2A JSR &C300 ;then jump to initialise screen. + +One of the things that I wondered when I got a BBC was how the RESET +key could possibly act as a soft key. As we all know BREAK acts as +soft key 10. But the keyboard buffer is cleared by the Reset. Tucked +away is the five-byte routine that makes the BREAK key act as soft +key 10. + +Soft keys work by inserting a byte greater than 127 into the keyboard +buffer. &CA is the code for key 10. + +DB2D LDY #&CA ;Y=&CA +DB2F JSR &E4F1 ;to enter this value in the keyboard buffer + +Simple isn't it? You can use the routine yourself although further +investigation will show that E4F1 is part of an OSbyte call. Remember +that the keyboard buffer is buffer 0. + +E4F1 LDX #&00 ;X=0 keyboard buffer + +************************************** +* * +* OSBYTE 153 Put byte in input * +* Buffer checking for ESCAPE * +* * +************************************** + +On entry X = buffer number which is either 0 or 1. If it's 0 then the +keyboard buffer is selected. If it's 1 then it is the RS423 buffer. + +Notice that the JSR to EF41 ensures that ONLY the keyboard buffer can +be selected. Once again we are looking at coding economy, in this case +with a specific keyboard buffer entry routine. Y contains the +character to be written. + +E4F3 TXA ;A=buffer number +E4F4 AND &0245 ;and with RS423 mode (0 treat as keyboard 1 ignore + ;Escapes no events no soft keys) +E4F7 BNE &E4AF ;so if RS423 buffer AND RS423 in normal mode (1) E4AF + ; +E4F9 TYA ;else Y=A character to write +E4FA EOR &026C ;compare with current escape ASCII code (0=match) +E4FD ORA &0275 ;or with current ESCAPE status (0=ESC, 1=ASCII) +E500 BNE &E4A8 ;if ASCII or no match E4A8 to enter byte in buffer +E502 LDA &0258 ;else get ESCAPE / BREAK action byte +E505 ROR ;Rotate to get ESCAPE bit into carry +E506 TYA ;get character back in A +E507 BCS &E513 ;and if escape disabled exit with carry clear +E509 LDY #&06 ;else signal EVENT 6 Escape pressed +E50B JSR &E494 ; +E50E BCC &E513 ;if event handles ESCAPE then exit with carry clear +E510 JSR &E674 ;else set ESCAPE flag +E513 CLC ;clear carry +E514 RTS ;and exit + +This routine will normally be accessed by assembly language +programmers by OSbyte 138 which calls EF43. + +BBC 6502 Machine Code +Part Eight: Breaker Break +------------------------- +One of the 'secret' features of the BBC Micro OS 1.20 when it was +arrived was the BREAK intercept. This is a useful method of taking +over the machine and is sometimes used by ROM software. + +There are two entry points, entered with the carry flag reset to 0 and +set to 1 respectively. The first call comes before sideways ROM calls. + +Enter BREAK intercept with Carry Clear + +DB32 JSR &EAD9 ;check to see if BOOT address is set up if so + ;JMP to it + +The address &287 is written by OSbyte 247 and the jump addresses in +&288 and &289 by OSbytes 248 and 249. The machine code for JMP is &4C. + +EAD9 LDA &0287 ;get BREAK vector code +EADC EOR #&4C ;produces 0 if JP (4C) not in &287 +EADE BNE &EAF3 ;if not goto EAF3 +EAE0 JMP &0287 ;else jump to use BREAK code +EAF3 RTS ;Return + +The RTS at the end of another routine is used because it saves code. + +Frequently you will find machine code routines where a lot of branches +go to a single RTS for just this reason. If you are writing your own +code remember that the RTS must be within range of the branch. One of +the most common assembler errors is a branch out of range that in turn +causes more errors when you add an extra RTS. + +Obviously at this point the machine could be totally in your control. +You can return control to the OS with an RTS or just continue on your +merry way. + +Remember that the sideways ROMs don't have any workspace yet and you +can't really run BASIC or any other language as the workspace will not +exist. But, assuming that you don't want to do any of this, let's go +back to the OS routines after testing for BREAK intercept. + +DB35 JSR &F140 ;set up cassette options +DB38 LDA #&81 ;test for tube to FIFO buffer 1 +DB3A STA &FEE0 ; +DB3D LDA &FEE0 ; +DB40 ROR ;put bit 0 into carry +DB41 BCC &DB4D ;if no tube then DB4D +DB43 LDX #&FF ;else +DB45 JSR &F168 ;issue ROM service call &FF to initialise TUBE system +DB48 BNE &DB4D ;if not 0 on exit (tube not initialised) DB4D +DB4A DEC &027A ;else set tube flag to show its active + +Now the Tube is flagged as active, or not as the case may be. We +continue next week, with the setup routines for the sideways ROMs. + +BBC 6502 Machine Code +Part Nine: A ROM with a view +----------------------------- +Now we nearly have a working system, we are, perhaps, 400 milliseconds +into the Power up routine. Now is the time to set up all of those nice +sideways ROMs we catalogued earlier. + +First we set up workspace and hence the value of BASIC's PAGE +variable. The call to ROMs is made via F168. This is available to the +programmer as OSBYTE 143. + +A ROM can have a number between 0 and 15 and will have two entry +points - a Service entry at &8003 and a Language entry at &8000. If +the ROM does not contain language code it will not have a language +entry. + +ROMs are paged into main memory by writing the ROM number to a latch +at &FE30. Hardware could be arranged to allow 256 ROMs although the +operating system does not support this. + +The Break Intercept code could be used to make drastic hardware +modifications like this. + +************************************** +* * +* OSBYTE 143 * +* Pass service commands * +* to sideways ROMs * +* * +************************************** + ;on entry X=command number +F168 LDA &F4 ;get current ROM number +F16A PHA ;store it +F16B TXA ;command in A +F16C LDX #&0F ;set X=15 + +The next bit of code is a countdown loop to send the command code to +each enabled ROM in turn. The Map at &2A1 is used to decide which ROMs +are active. Note the use of a countdown loop. This gives code economy +and explains why the highest ROM number has priority. + +F16E INC &02A1,X ;read bit 7 on ROM map (no ROM has type 254 &FE) +F171 DEC &02A1,X ; +F174 BPL &F183 ;if not set (+ve result) +F176 STX &F4 ;else store ROM number in &F4 +F178 STX &FE30 ;switch in paged ROM +F17B JSR &8003 ;and jump to service entry +F17E TAX ;on exit put A in X +F17F BEQ &F186 ;if 0 (command recognised by ROM) reset ROMs & exit +F181 LDX &F4 ;else point to next lower ROM +F183 DEX ; +F184 BPL &F16E ;and go round loop again +F186 PLA ;get back original ROM number +F187 STA &F4 ;store it in RAM copy +F189 STA &FE30 ;select original page +F18C TXA ;put X back in A +F18D RTS ;and return + +Couldn't be easier! So we can now return to the main body of the +routine. + +DB4D LDY #&0E ;set current value of PAGE +DB4F LDX #&01 ;issue call to claim absolute workspace +DB51 JSR &F168 ;via F168 +DB54 LDX #&02 ;send private workspace claim call +DB56 JSR &F168 ;via F168 + +OSHWM is OS High Water Mark. The highest address used by the operating +system. + +DB59 STY &0243 ;set primary OSHWM +DB5C STY &0244 ;set current OSHWM +DB5F LDX #&FE ;issue call for Tube to explode character set etc. +DB61 LDY &027A ;Y=FF if tube present else Y=0 +DB64 JSR &F168 ;and make call via F168 + +We now have the machine set up to enter a language, all the filing +systems have been set up and the sideways ROMs activated. + +Next week we finally start the screen messages. + +BBC 6502 Machine Code +Part Ten: Stringing it along +----------------------------- +The next routine shows why the Machine start up message is not always +seen on third-party kit. + +DB67 AND &0267 ;if A=&FE and bit 7 of 0267 is set then continue +DB6A BPL &DB87 ;else ignore start up message +DB6C LDY #&02 ;output to screen +DB6E JSR &DEA9 ;'BBC Computer ' message + +Looking at the routine in DEA9 we find a very useful string printing +routine. Remember that Y = 2 on entry. + +DEA9 LDA #&C3 ;point to start &C300 +DEAB STA &FE ;store it +DEAD LDA #&00 ;point to lo byte +DEAF STA &FD ;store it and start loop with Y=2 +DEB1 INY ;print character in string +DEB2 LDA (&FD),Y ;pointed to by &FD/E +Y +DEB4 JSR OSASCI ;print it expanding Carriage returns +DEB7 TAX ;store A in X +DEB8 BNE &DEB1 ;and loop again if not =0 +DEBA RTS ;else exit + +Here is the string delimited by BRK. The code for BRK is 00. Y is 3 +when the first character is read so its address is &C303. + +C303 DB 13 ;Carriage Return +C304 DB 'BBC Computer ' +C311 BRK + +Notice that the routine uses TAX to set the zero flag which marks the +end of the string. This is a useful tip. + +The next part of the Operating system deals with printing correct +messages on the screen. + +DB71 LDA &028D ;0=warm reset, If a cold reset continue +DB74 BEQ &DB82 ; +DB76 LDY #&16 ;by checking length of RAM +DB78 BIT &028E ; +DB7B BMI &DB7F ;and either +DB7D LDY #&11 ; +DB7F JSR &DEA9 ;finishing message with '16K' or '32K' +DB82 LDY #&1B ;and two new lines +DB84 JSR &DEA9 ; + +Notice that Y is used to pick the appropriate message. + +C312 DB '16K' +C315 DB 7 ;Bell +C316 BRK +C317 DB '32K' +C31A DB 7 ;Bell +C31B BRK +C31C DB 08,0D,0D + +Notice the BBC Beep at this point indicates that nearly all set up +procedures have been finished. + +The hum is generated by the Sound channel which is reset as part of +the start routine. Hence the HUM-BEEP start up. If the machine does +not start properly the sound signals give a strong clue to the nature +of the problem. Having got this far the OS gives us another chance to +take control. + +Enter BREAK INTERCEPT ROUTINE WITH CARRY SET (call 1) + +DB87 SEC ; +DB88 JSR &EAD9 ;look for break intercept jump + ;SEE EARLIER PART + +Next we set up the keyboard lights + +DB8B JSR &E9D9 ;set up LEDs in accordance with keyboard status + +This is another 'undocumented' OSBYTE call. + +************************************** +* * +* OSBYTE &76 (118) * +* SET LEDs to Keyboard Status * +* * +************************************** +;osbyte entry with carry set +E9D9 PHP ;PUSH P +E9DA SEI ;DISABLE INTERRUPTS +E9DB LDA #&40 ;switch on CAPS and SHIFT lock lights +E9DD JSR &E9EA ;via subroutine +E9E0 BMI &E9E7 ;if ESCAPE exists (M set) E9E7 +E9E2 CLC ;else clear V and C +E9E3 CLV ;before calling main keyboard routine to +E9E4 JSR &F068 ;switch on lights as required +E9E7 PLP ;get back flags +E9E8 ROL ;and rotate carry into bit 0 +E9E9 RTS ;Return to calling routine + ; +* Turn on keyboard lights and +* Test Escape flag + ; +E9EA BCC &E9F5 ;if carry clear +E9EC LDY #&07 ;switch on shift lock light +E9EE STY &FE40 ; +E9F1 DEY ;Y=6 +E9F2 STY &FE40 ;switch on Caps lock light +E9F5 BIT &FF ;set minus flag if bit 7 of &00FF is set indicating +E9F7 RTS ;that ESCAPE condition exists, then return + +The Keyboard routine continues via the KEYV. This is a little long to +include here so we'll leave it until a later part. So back to the +Start up routine next week with the cassette system. + +BBC 6502 Machine Code +Part Eleven: Language! +---------------------- +Having got the keyboard nicely set up the machine proceeds to +initialise a filing system and run a !BOOT file if one exists. The +start up options are already read from the keyboard links. + +DB8E PHP ;save flags +DB8F PLA ;and get back in A +DB90 LSR ;zero bits 4-7 and bits 0-2 bit 4 which was bit 7 +DB91 LSR ;may be set +DB92 LSR ; +DB93 LSR ; +DB94 EOR &028F ;EOR with start up options which may or may not +DB97 AND #&08 ;invert bit 4 +DB99 TAY ;Y=A +DB9A LDX #&03 ;make initialisation call, if Y=0 on entry +DB9C JSR &F168 ;RUN, EXEC or LOAD !BOOT file from a filing system. +DB9F BEQ &DBBE ;if a ROM accepts this call then DBBE +DBA1 TYA ;else put Y in A +DBA2 BNE &DBB8 ;if Y<>0 DBB8 +DBA4 LDA #&8D ;else set up standard cassette baud rates +DBA6 JSR &F135 ;via &F135 which is OSBYTE 140. +DBA9 LDX #&D2 ; +DBAB LDY #&EA ; +DBAD DEC &0267 ;decrement ignore start up message flag +DBB0 JSR OSCLI ;and execute /!BOOT +DBB3 INC &0267 ;restore start up message flag +DBB6 BNE &DBBE ;if not zero then DBBE +DBB8 LDA #&00 ;else A=0 +DBBA TAX ;X=0 +DBBB JSR &F137 ;set tape speed via OSBYTE 140. + +We now have an active filing system. The next job is to preserve the +current language on soft RESET. + +DBBE LDA &028D ;get last RESET Type +DBC1 BNE &DBC8 ;if not soft reset DBC8 +DBC3 LDX &028C ;else get current language ROM address +DBC6 BPL &DBE6 ;if +ve (language available) then skip search + ;routine +For a cold break we search for the language with the highest priority. + +DBC8 LDX #&0F ;set pointer to highest available ROM +DBCA LDA &02A1,X ;get ROM type from map +DBCD ROL ;put hi-bit into carry, bit 6 into bit 7 +DBCE BMI &DBE6 ;if bit 7 set then ROM has a language entry so DBE6 +DBD0 DEX ;else search for language until X=&ff + +Check for Tube if no language found. + +DBD1 BPL &DBCA ;check if tube present +DBD3 LDA #&00 ;if bit 7 of tube flag is set BMI succeeds +DBD5 BIT &027A ;and TUBE is connected else +DBD8 BMI &DC08 ;make error + +No language error + +DBDA BRK ; +DBDB DB &F9 ;error number +DBDC DB 'Language?' ;message +DBE5 BRK ; + +This might seem odd as BRK is handled by the current language BRK +handler, but we don't have a language! We need to investigate further +in another part. + +DBE6 CLC ; + +OSBYTE 142 enter Language ROM at &8000 X=ROM number. Carry is set if +this is an OSBYTE call and clear if this is an initialisation routine. + +DBE7 PHP ;save flags +DBE8 STX &028C ;put X in current ROM page +DBEB JSR &DC16 ;select that ROM +DBEE LDA #&80 ;A=128 +DBF0 LDY #&08 ;Y=8 +DBF2 JSR &DEAB ;display text string held in ROM at &8008,Y +DBF5 STY &FD ;save Y on exit (end of language string) +DBF7 JSR OSNEWL ;two line feeds +DBFA JSR OSNEWL ;are output +DBFD PLP ;then get back flags +DBFE LDA #&01 ;A=1 required for language entry +DC00 BIT &027A ;check if tube exists +DC03 BMI &DC08 ;and goto DC08 if it does +DC05 JMP &8000 ;else enter language at &8000 + +TUBE FOUND enter tube software + +DC08 JMP &0400 ;enter tube environment + +The Tube initialisation would have read the language across to the +TUBE usually but it could be loaded by a !BOOT file from the filing +system initialisation. + +The operating system now stops general control of the system and hands +this to the language which looks after command lines etc. The OS +however still handles the screen, keyboard and much else. + +Notice how every possible eventuality was taken into account during +the initialisation routine. This is one of the things that made the +Beeb a very powerful machine. + +Next week we'll have a look at the Interrupt code. + +BBC 6502 Machine Code +Part Twelve: Pardon me! +----------------------- +We finished the last part at the point where the operating systems +power up routine handed over control to the language. We'll write our +own language later in the series but for now let's dive into another +entry point. + +When the processor's IRQ pin (4) goes low (0V) the processor finishes +off the current instruction and then goes off to run some microcode of +its own. This checks that the RDY (2) pin is high and that the +interrupt flag in the status register is 0 (not set). If it is set the +interrupt is ignored and the processor goes to the next instruction. +This continues when the IRQ pin is low. + +If the flag is clear then the processor stores the program counter and +status register on the stack and sets the interrupt flag. The 6502 +then gets the address stored in &FFFE and &FFFF and executes this +instruction next. + +If a BRK instruction is found in executing code then the processor +performs exactly the same actions except that it does not check the +status register for the interrupt flag, it does set a flag in the +status register, the BRK flag. + +The main entry point for IRQ (and BRK) for OS 1.20 is &DC51. + +MAIN IRQ Entry point + +;ON ENTRY STACK contains STATUS REGISTER,PCH,PCL +DC1C STA &FC ;save A +DC1E PLA ;get back status (flags) +DC1F PHA ;and save again +DC20 AND #&10 ;check if BRK flag set +DC22 BNE &DC27 ;if so goto DC27 +DC24 JMP (&0204) ;else JUMP through IRQ1V + +That's pretty straightforward so far. As you can see IRQ1V allows you +to put your own hardware at a higher priority than anything else in +the machine. + +You can also write your own hardware interrupt handler if you wish. +This is the flexibility that made the BBC machine so remarkably +successful among knowledgeable users. + +Let's look at the BRK handler now. + +* BRK handling routine * +DC27 TXA ;save X on stack +DC28 PHA ; +DC29 TSX ;get status pointer +DC2A LDA &0103,X ;get Program Counter low byte +DC2D CLD ; +DC2E SEC ;set carry +DC2F SBC #&01 ;subtract 2 (1+carry) +DC31 STA &FD ;and store it in &FD +DC33 LDA &0104,X ;get hi byte +DC36 SBC #&00 ;subtract 1 if necessary +DC38 STA &FE ;and store in &FE +DC3A LDA &F4 ;get currently active ROM +DC3C STA &024A ;and store it in &24A +DC3F STX &F0 ;store stack pointer in &F0 +DC41 LDX #&06 ;and issue ROM service call 6 +DC43 JSR &F168 ;(User BRK) to ROMs + ;now &FD/E points to byte after BRK + ;ROMS may use BRK for their own purposes + ;and many do! + +It's interesting to see what happens with the ROM handler. This is +also an entry point for OSBYTE 143 so you can use this in your own +code. + +* OSBYTE 143 * +*Pass service commands to sideways ROMs * + ;on entry X=command number +F168 LDA &F4 ;get current ROM number +F16A PHA ;store it +F16B TXA ;command in A +F16C LDX #&0F ;set X=15 + ;send commands loop +F16E INC &02A1,X ;read bit 7 on ROM map (no ROM has + ;type 254 &FE) +F171 DEC &02A1,X ; +F174 BPL &F183 ;if not set (+ve result) +F176 STX &F4 ;else store ROM number in &F4 +F178 STX &FE30 ;switch in paged ROM +F17B JSR &8003 ;and jump to service entry +F17E TAX ;on exit put A in X +F17F BEQ &F186 ;if 0 (command recognised by ROM) + ;reset ROMs & exit +F181 LDX &F4 ;else point to next lower ROM +F183 DEX ; +F184 BPL &F16E ;and go round loop again +F186 PLA ;get back original ROM number +F187 STA &F4 ;store it in RAM copy +F189 STA &FE30 ;select original page +F18C TXA ;put X back in A +F18D RTS ;and return + +Useful little routine that. So back to the BRK handler. + +DC46 LDX &028C ;get current language +DC49 JSR &DC16 ;and activate it +DC4C PLA ;get back original value of X +DC4D TAX ; +DC4E LDA &FC ;get back original value of A +DC50 CLI ;allow interrupts +DC51 JMP (&0202) ;and JUMP via BRKV (normally into current language) + +Next week we'll carry on by taking a look at the BRK handler. + +BBC 6502 Machine Code +Part Thirteen: Give us a BRK +---------------------------- +BRK is usually handled by the default language (or by a Sideways ROM). +However, it may be that you are running a machine code program before +a current language is set up or perhaps your language doesn't handle +BRK (it should but you never know). + +That's when a default BRK handler takes over. + +* DEFAULT BRK HANDLER * + +DC54 LDY #&00 ;Y=0 to point to byte after BRK +DC56 JSR &DEB1 ;print message + +Let's have a look at the print routine. Remember that the error- +handling layout is: + +BRK +Error Number (1 byte) +Message +BRK + +Y plus the address in &FD &FE points to the error message on entry. + +DEB1 INY ;point to first ;character in string +DEB2 LDA (&FD),Y +DEB4 JSR OSASCI ;print it + ;expanding + ;Carriage + ;returns +DEB7 TAX ;store A in X to change flags +DEB8 BNE &DEB1 ;and loop again if not =0 +DEBA RTS ;else exit + +A standard print routine, nothing out of the ordinary but nice and +compact. + +You can use this in your own print routines by changing the zero page +values. Back to the default BRK handler and an interesting bit of +code. + +DC59 LDA &0267 ;if BIT 0 set and DISK EXEC error +DC5C ROR ;occurs +DC5D BCS &DC5D ;hang up machine! + +Nasty! But the machine has to be in a pretty unusual configuration for +this to happen. Mind you, setting 0267 then doing a JSR to DC59 would +confuse the average user. + +DC5F JSR OSNEWL ;else print two newlines +DC62 JSR OSNEWL ; +DC65 JMP &DBB8 ;and set tape speed before entering the current + ;language +DBB8 LDA #&00 ;else A=0 +DBBA TAX ;X=0 +DBBB JSR &F137 ;set tape speed via OSBYTE 141. + +There's the end of the BRK handling code. As I said before this is +generally handled by the default language but you can arrange for your +own code or a Sideways ROM to handle it. + +Next week we'll return to the interrupt system with a look at the +default entry point for IRQ1. + +BBC 6502 Machine Code +Part Fourteen: The story so far... +---------------------------------- +We left the interrupt-handling routine just after it had gone off to +the IRQ1V vector. If you don't change the vector the code continues +from DC93. + +One very important thing to remember about an interrupt-driven machine +like the BBC is that the interrupt flag is not set for too long. If it +is the machine could crash. This means that interrupt routines are +short and snappy. + +* Main IRQ Handling routines, default IRQIV destination * + +DC93 CLD ;clear decimal flag +DC94 LDA &FC ;get original value of A +DC96 PHA ;save it +DC97 TXA ;save X +DC98 PHA ; +DC99 TYA ;and Y +DC9A PHA ;on the stack + ;note the pre-CMOS code! +DC9B LDA #&DE ;A=&DE +DC9D PHA ;store it +DC9E LDA #&81 ;save &81 +DCA0 PHA ;store it (a RTS will now jump to DE82) + +This is quite a useful technique as we will see later. If we now use +JMP to go to an OS routine we can ensure that the routine, which ends +with an RTS, causes execution to go to a specified point. + +This saves a lot of code as it can be arranged that the first device +found that called the interrupt will be the only one handled. This, in +turn, saves time! + +We now poll the hardware looking for who caused it. The first routine +deals with the serial/tape system. + +DCA1 CLV ;clear V flag +DCA2 LDA &FE08 ;get value of status register of ACIA +DCA5 BVS &DCA9 ;if this was source then DCA9 to process +DCA7 BPL &DD06 ;else if no interrupt requested DD06 +DCA9 LDX &EA ;read RS423 timeout counter +DCAB DEX ;decrement it +DCAC BMI &DCDE ;and if <0 DCDE +DCAE BVS &DCDD ;else if >&40 DCDD (RTS to DE82) +DCB0 JMP &F588 ;else read ACIA via F588 + ;RTS ends routine!! +DCB3 LDY &FE09 ;read ACIA data +DCB6 ROL ; +DCB7 ASL ; +DCB8 TAX ;X=A +DCB9 TYA ;A=Y +DCBA LDY #&07 ;Y=07 +DCBC JMP &E494 ;check and service EVENT 7 RS423 error +DCBF LDX #&02 ;read RS423 output buffer +DCC1 JSR &E460 ; +DCC4 BCC &DCD6 ;if C=0 buffer is not empty goto DCD6 +DCC6 LDA &0285 ;else read printer destination +DCC9 CMP #&02 ;is it serial printer?? +DCCB BNE &DC68 ;if not DC68 +DCCD INX ;else X=3 +DCCE JSR &E460 ;read printer buffer +DCD1 ROR &02D2 ;rotate to pass carry into bit 7 +DCD4 BMI &DC68 ;if set then DC68 +DCD6 STA &FE09 ;pass either printer or RS423 data to ACIA +DCD9 LDA #&E7 ;set timeout counter to stored value +DCDB STA &EA ; +DCDD RTS ;and exit (to DE82) + + ;A contains ACIA status +DCDE AND &0278 ;AND with ACIA bit mask (normally FF) +DCE1 LSR ;rotate right to put bit 0 in carry +DCE2 BCC &DCEB ;if carry clear receive register not full so DCEB +DCE4 BVS &DCEB ;if V is set then DCEB +DCE6 LDY &0250 ;else Y=ACIA control setting +DCE9 BMI &DC7D ;if bit 7 set receive interrupt is enabled so DC7D + +DCEB LSR ;put BIT 2 of ACIA status into +DCEC ROR ;carry if set then Data Carrier Detected applies +DCED BCS &DCB3 ;jump to DCB3 + +DCEF BMI &DCBF ;if original bit 1 is set TDR is empty so DCBF +DCF1 BVS &DCDD ;if V is set then exit to DE82 + +DCF3 LDX #&05 ;X=5 +DCF5 JSR &F168 ;issue ROM call 5 'unrecognised ;interrupt' + +We've seen this ROM service routine call before. + +DCF8 BEQ &DCDD ;if a ROM recognises it then exit to DE82 +DCFA PLA ;otherwise get back DE82 address from stack +DCFB PLA ; +DCFC PLA ;and get back X, Y and A +DCFD TAY ; +DCFE PLA ; +DCFF TAX ; +DD00 PLA ; +DD01 STA &FC ;&FC=A +DD03 JMP (&0206) ;and offer to the user via IRQ2V + +That was a little convoluted, to say the least. Next week we look at how the +VIAs are dealt with. + +BBC 6502 Machine Code +Part Fifteen: Hardware VIA interrupts +------------------------------------- +After deciding that it wasn't the ACIA that caused the interrupt, the +VIAs are the next port of inquisition. + +* VIA INTERRUPTS ROUTINES * + +DD06 LDA &FE4D ;read system VIA interrupt flag register +DD09 BPL &DD47 ;if bit 7=0 the VIA has not caused interrupt goto DD47 + +DD0B AND &0279 ;mask with VIA bit mask +DD0E AND &FE4E ;and interrupt enable register +DD11 ROR ;rotate right twice to ;check for IRQ 1 (frame sync) + +DD12 ROR ; +DD13 BCC &DD69 ;if carry clear then no IRQ 1, else IRQ 1 means + ;interrupt request 1. This is different from the + ;vector IRQ1. + +DD15 DEC &0240 ;decrement vertical sync counter +DD18 LDA &EA ;A=RS423 Timeout counter +DD1A BPL &DD1E ;if +ve then DD1E +DD1C INC &EA ;else increment it +DD1E LDA &0251 ;load flash character counter +DD21 BEQ &DD3D ;if 0 then flash system is not in use, ignore it +DD23 DEC &0251 ;else decrement counter +DD26 BNE &DD3D ;and if not 0 go on past reset routine + +This routine resets the flashing character system. + +DD28 LDX &0252 ;get mark period count in X +DD2B LDA &0248 ;current VIDEO ULA control setting in A +DD2E LSR ;shift bit 0 into C to ;check if first colour +DD2F BCC &DD34 ;is effective if so C=0. Jump to DD34 +DD31 LDX &0253 ;else get space period count in X +DD34 ROL ;restore bit +DD35 EOR #&01 ;and invert it +DD37 JSR &EA00 ;then change colour + +DD3A STX &0251 ;&0251=X resetting the counter + +DD3D LDY #&04 ;Y=4 and call E494 to check and implement vertical +DD3F JSR &E494 ;sync event (4) if necessary +DD42 LDA #&02 ;A=2 +DD44 JMP &DE6E ;clear interrupt 1 and exit + +Remember the RTS routine last time? + +* PRINTER INTERRUPT USER VIA 1 * + +DD47 LDA &FE6D ;Check USER VIA interrupt flags register +DD4A BPL &DCF3 ;if +ve USER VIA did not call interrupt +DD4C AND &0277 ;else check for USER IRQ 1 printer interrupt. +DD4F AND &FE6E ; +DD52 ROR ; +DD53 ROR ; +DD54 BCC &DCF3 ;if bit 1=0 then no ;interrupt 1 so DCF3 +DD56 LDY &0285 ;else get printer type +DD59 DEY ;decrement +DD5A BNE &DCF3 ;if not parallel then :CF3 +DD5C LDA #&02 ;reset interrupt 1 flag +DD5E STA &FE6D ; +DD61 STA &FE6E ;disable interrupt 1 +DD64 LDX #&03 ;and output data to parallel printer +DD66 JMP &E13A ;and exit via RTS + +* SYSTEM INTERRUPT 5 Speech * + +DD69 ROL ;get bit 5 into bit 7 +DD6A ROL ; +DD6B ROL ; +DD6C ROL ; +DD6D BPL &DDCA ;if not set this is not ;a speech interrupt so DDCA +DD6F LDA #&20 ; +DD71 LDX #&00 ; +DD73 STA &FE4D ; +DD76 STX &FE49 ;and zero high byte of Timer t2 +DD79 LDX #&08 ;&FB=8 +DD7B STX &FB ; +DD7D JSR &E45B ;and examine buffer 8 +DD80 ROR &02D7 ;shift carry into bit 7 +DD83 BMI &DDC9 ;and if set buffer is empty so exit +DD85 TAY ;else Y=A +DD86 BEQ &DD8D ; +DD88 JSR &EE6D ;control speech chip +DD8B BMI &DDC9 ;if negative exit +DD8D JSR &E460 ;else get a byte from buffer +DD90 STA &F5 ;store it to indicate speech or file ROM +DD92 JSR &E460 ;get another byte +DD95 STA &F7 ;store it +DD97 JSR &E460 ;and another +DD9A STA &F6 ;giving address to be accessed in paged ROM +DD9C LDY &F5 ;Y=&F5 +DD9E BEQ &DDBB ;and if =0 then DDBB +DDA0 BPL &DDB8 ;else if +ve DDB8 +DDA2 BIT &F5 ;if bit 6 of F5 =1 (&F5)>&40 +DDA4 BVS &DDAB ;then DDAB +DDA6 JSR &EEBB ;else continue for more speech processing +DDA9 BVC &DDB2 ;if bit 6 clear then DDB2 +DDAB ASL &F6 ;else double address in &F6/7 +DDAD ROL &F7 ; +DDAF JSR &EE3B ;and call EE3B +DDB2 LDY &0261 ;get speech enable/disable flag into Y +DDB5 JMP &EE7F ;and JMP to EE7F + +DDB8 JSR &EE7F ;Call EE7F +DDBB LDY &F6 ;get address pointer in Y +DDBD JSR &EE7F ; +DDC0 LDY &F7 ;get address pointer high in Y +DDC2 JSR &EE7F ; +DDC5 LSR &FB ; +DDC7 BNE &DD7D ; +DDC9 RTS ;and exit + +Next week we continue with a look at the remaining System Interrupts. + +BBC 6502 Machine Code +Part Sixteen: Timers and Keyboard Interrupts +-------------------------------------------- +The last part showed how the BBC Micro handles some of the system +interrupt calls. Most of these are pretty routine so we won't continue +with an interminable list. + +The next interesting routines concern how the timers and keyboard +interrupts are handled. + +* SYSTEM INTERRUPT 6 10mS Clock * + +DDCA BCC &DE47 ;bit 6 is in carry so if clear there is no 6 so go + ;on to DE47 +DDCC LDA #&40 ;Clear interrupt 6 +DDCE STA &FE4D ; + +This is the start of the update timers routine, This is interesting +because of the way that the timer information is stored. It's very +clever. There are two timer stores, &292-6 and &297-B. These are +updated by adding 1 to the current timer and storing the result in the +other, the direction of transfer being changed each time of update. + +This ensures that at least one timer is valid at any call as the +current timer only is read. Other methods would cause inaccuracies if +a timer was read while being updated. + +DDD1 LDA &0283 ;get current system clock store pointer (5,or 10) +DDD4 TAX ;put A in X +DDD5 EOR #&0F ;and invert lo nybble (5becomes 10 and vv) +DDD7 PHA ;store A +DDD8 TAY ;put A in Y. Carry is always set at this point +DDD9 LDA &0291,X ;get timer value +DDDC ADC #&00 ;update it +DDDE STA &0291,Y ;store result in alternate +DDE1 DEX ;decrement X +DDE2 BEQ &DDE7 ;if 0 exit +DDE4 DEY ;else decrement Y +DDE5 BNE &DDD9 ;and go back and do next byte +DDE7 PLA ;get back A +DDE8 STA &0283 ;and store back in clock pointer (ie. inverse + ;previous contents) +DDEB LDX #&05 ;set loop pointer for countdown timer +DDED INC &029B,X ;increment byte and +DDF0 BNE &DDFA ;if not 0 then DDFA +DDF2 DEX ;else decrement pointer +DDF3 BNE &DDED ;and if not 0 do it again +DDF5 LDY #&05 ;process EVENT 5 interrupt timer +DDF7 JSR &E494 ; +DDFA LDA &02B1 ;get byte of inkey countdown timer +DDFD BNE &DE07 ;if not 0 then DE07 +DDFF LDA &02B2 ;else get next byte +DE02 BEQ &DE0A ;if 0 DE0A +DE04 DEC &02B2 ;decrement 2B2 +DE07 DEC &02B1 ;and 2B1 +DE0A BIT &02CE ;read bit 7 of envelope processing byte +DE0D BPL &DE1A ;if 0 then DE1A +DE0F INC &02CE ;else increment to 0 +DE12 CLI ;allow interrupts +DE13 JSR &EB47 ;and do routine sound processes +DE16 SEI ;bar interrupts +DE17 DEC &02CE ;DEC envelope processing byte back to 0 +DE1A BIT &02D7 ;read speech buffer busy flag +DE1D BMI &DE2B ;if set speech buffer is empty, skip routine +DE1F JSR &EE6D ;update speech system variables +DE22 EOR #&A0 ; +DE24 CMP #&60 ; +DE26 BCC &DE2B ;if result >=&60 DE2B +DE28 JSR &DD79 ;else more speech work +DE2B BIT &D9B7 ;set V and C +DE2E JSR &DCA2 ;check if ACIA needs attention +DE31 LDA &EC ;check if key has been pressed +DE33 ORA &ED ; +DE35 AND &0242 ;(this is 0 if keyboard is to be ignored, else + ;&FF) +DE38 BEQ &DE3E ;if 0 ignore keyboard +DE3A SEC ;else set carry +DE3B JSR &F065 ;and call keyboard +DE3E JSR &E19B ;check for data in use defined printer channel +DE41 BIT &FEC0 ;if ADC bit 6 is set ADC is not busy +DE44 BVS &DE4A ;so DE4A +DE46 RTS ;else return + +* SYSTEM INTERRUPT 4 ADC end of conversion * + +DE47 ROL ;put original bit 4 from FE4D into bit 7 of A +DE48 BPL &DE72 ;if not set DE72 +DE4A LDX &024C ;else get current ADC channel +DE4D BEQ &DE6C ;if 0 DE6C +DE4F LDA &FEC2 ;read low data byte +DE52 STA &02B5,X ;store it in &2B6,7,8 or 9 +DE55 LDA &FEC1 ;get high data byte +DE58 STA &02B9,X ;and store it in hi byte +DE5B STX &02BE ;store in Analogue system flag marking last channel +DE5E LDY #&03 ;handle event 3 conversion complete +DE60 JSR &E494 ; +DE63 DEX ;decrement X +DE64 BNE &DE69 ;if X=0 +DE66 LDX &024D ;get highest ADC channel present +DE69 JSR &DE8F ;and start new conversion +DE6C LDA #&10 ;reset interrupt 4 +DE6E STA &FE4D ; +DE71 RTS ;and return + +* SYSTEM INTERRUPT 0 Keyboard * + +DE72 ROL ;get original bit 0 in bit 7 position +DE73 ROL ; +DE74 ROL ; +DE75 ROL ; +DE76 BPL &DE7F ;if bit 7 clear not a keyboard interrupt +DE78 JSR &F065 ;else scan keyboard +DE7B LDA #&01 ;A=1 +DE7D BNE &DE6E ;and off to reset interrupt and exit +DE7F JMP &DCF3 ;and again a subroutine to exit. + +Now we come to the point you've all been waiting for. This mystery +RTSreturns all subroutines to &DE82. + +************** exit routine +DE82 PLA ;restore registers +DE83 TAY ; +DE84 PLA ; +DE85 TAX ; +DE86 PLA ; +DE87 STA &FC ;store A + +* IRQ2V default entry * + +DE89 LDA &FC ;get back original value of A +DE8B RTI ;and return to calling routine. + +NEXT WEEK: OSBYTE entry. + +BBC 6502 Machine Code +Part Seventeen: The BBC Operating System +---------------------------------------- +We've been examining the BBC operating system in some detail over the +last few weeks. Unfortunately the demise of Micronet means that we +cannot finish completely, as we hoped. So we've put together the next +twenty weeks' articles in the form of a completely commented +disassembly of OS 1.20. + +This is an excellent example of BBC programming and is full of tips. + +Just to remind you of the main points of the software. Entry points +are pointed to by a jump table in the last six bytes of the ROM. + +The font characters are located from &C000 to &C2FF. + +OK, so here it is all commented and ready for you to peruse. + +Ed says: I have uploaded the series of disassembly articles as ten + short TSW files. Look on Micronet on 700100239 (before it's + too late!) + + *********** THE END ********** + diff --git a/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/index.html b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/index.html new file mode 100644 index 0000000..fe01700 --- /dev/null +++ b/docs/os12/mdfs.net/Docs/Comp/BBC/OS1-20/index.html @@ -0,0 +1,80 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> +<HTML><HEAD> +<META http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> +<META name="MSSmartTagsPreventParsing" content="True"> +<META name="Author" content="Jonathan Graham Harston"> +<TITLE>BBC OS 1.20 - BBC FAQ</TITLE> +</HEAD> + +<BODY> +<TABLE width="100%"> +<TR bgcolor="#eeeeaa"><th colspan="2"><font size="+3">BBC OS 1.20 DISASSEMBLY</font></th> +<TR bgcolor="#ffff66"><TD><SMALL><A href="../" +target="_top">BBC</A>-><B>OS1-20</B> +</SMALL><TD align="right"> +<SMALL><A href="http://google.co.uk/custom?domains=mdfs.net&sitesearch=mdfs.net">Search</A> +</SMALL></TABLE><P> + +These files were originally abritarily chopped up into approximately +18K chunks just for ease of editing. I have rearranged them up into +more logical function chunks. I am going through them and updating, +correcting and clarifying the comments. + +<P><TT> +<A href="C000" TYPE="text/plain">C000</A> +Default character set.<BR> +<A href="C300" TYPE="text/plain">C300</A> +VDU startup entry and tables.<BR> +<A href="C4C0" TYPE="text/plain">C4C0</A> +VDU Part 1: Main Routine. Control character dispatch,<BR> + VDU 1,14,2,21,3,15,4,5,8, scroll text window, VDU 11,9,10,28.<BR> +<A href="C735" TYPE="text/plain">C735</A> +VDU Part 2: Read pixel, read pallette, +VDU 12,30,31,13,16,17,18,20,19<BR> + write pallette, VDU 22,23,cursor control, CRTC control, VDU 25,26.<BR> +<A href="CA39" TYPE="text/plain">CA39</A> +VDU Part 3: VDU 24,29,127,paged mode,initialisation,<BR> + read character, clear screen, *FX20, block cursor.<BR> +<A href="CDED" TYPE="text/plain">CDED</A> +VDU Part 4: Scroll, clear, move graphics cursor, plot routines,<BR> + plot a point.<BR> +<A href="D10D" TYPE="text/plain">D10D</A> VDU Part 5<BR> +<A href="D4BF" TYPE="text/plain">D4BF</A> VDU Part 6<BR> +<A href="D940" TYPE="text/plain">D940</A> +System Startup. Default vectors, RESET code, find ROMs and BASIC,<BR> + initialise ROMs, enter a language.<BR> +<A href="DC1C" TYPE="text/plain">DC1C</A> Main IRQ Routines.<BR> +<A href="DF0C" TYPE="text/plain">DF0C</A> OSCLI and OSWRCH dispatch.<BR> +<A href="E20E" TYPE="text/plain">E20E</A> +*SAVE, *LOAD, *SPOOL, *KEY, *FX.<BR> +<A href="E435" TYPE="text/plain">E435</A> +Buffer handling, Event handling.<BR> +<A href="E6B0" TYPE="text/plain">E6B0</A> +OSBYTE/OSWORD dispatch table, FX9/10, FX2, FX13/14, FX16, INKEY,<BR> + ADVAL, OSBYTE handler, OSWORD handler, OSWORD 5/6, FX0.<BR> +<A href="E887" TYPE="text/plain">E887</A> +Sound system, SOUND, Speech, BELL, ENVELOPE,<br> + OSWORD 3,1,2,0,5 FX1,6,12,11,3,4,166+ FX19,160,18,118, GSTrans.<BR> +<A href="EAD9" TYPE="text/plain">EAD9</A> +BIV, *TV, Sound IRQs, Speech.<BR> +<A href="EEDA" TYPE="text/plain">EEDA</A> +Keyboard.<BR> +<A href="F135" TYPE="text/plain">F135</A> +ROM/Cassette filing system. ARGS, FSC, FILE, RUN, CAT. Pass service calls around ROMs<BR> +<A href="F3CA" TYPE="text/plain">F3CA</A> +ROM/Cassette filing system. Save data, FIND, BGET, BPUT, OPT, EOF.<BR> +<A href="F68B" TYPE="text/plain">F68B</A> +ROM/Cassette filing system. Read/write blocks, CRC checks.<BR> +<A href="F9B4" TYPE="text/plain">F9B4</A> +ROM/Cassette filing system. Load data, housekeeping.<BR> +<A href="FC00" TYPE="text/plain">FC00</A> +I/O locations, extended vector handler, MOS entry points.<BR> +<A href="Microbase" TYPE="text/plain">Microbase</A> +Introduction to the BBC Operating System.<BR> +</TT> + +<BR> +<table width="100%" bgcolor="#f0f0b0"><tr><th>This page last updated 11-Aug-2010</th></table> + +</BODY> +</HTML> diff --git a/docs/texas_instruments_sn76489an.pdf b/docs/texas_instruments_sn76489an.pdf Binary files differnew file mode 100644 index 0000000..2356bef --- /dev/null +++ b/docs/texas_instruments_sn76489an.pdf diff --git a/mmc/.gitignore b/mmc/.gitignore new file mode 100644 index 0000000..33091db --- /dev/null +++ b/mmc/.gitignore @@ -0,0 +1,6 @@ +*.ssd +*.dsdi +assemble +deinterleave +BEEB.MMB +disk.img diff --git a/mmc/Makefile b/mmc/Makefile new file mode 100644 index 0000000..049083d --- /dev/null +++ b/mmc/Makefile @@ -0,0 +1,30 @@ +DSDI=$(wildcard *.dsdi) +DSDI_SSD=${DSDI:%.dsdi=%-1.ssd} ${DSDI:%.dsdi=%-2.ssd} + +SSD=$(wildcard *.ssd) $(wildcard *.SSD) ${DSDI_SSD} + +DISK=/dev/mmcblk0p1 + + + +default: disk.img + mkdosfs -F 16 ${DISK} + mcopy -i ${DISK} disk.img ::BEEB.MMB + sync + +%-1.ssd:%.dsdi deinterleave + ./deinterleave $< $@ ${@:%-1.ssd=%-2.ssd} + +%-2.ssd:%.dsdi deinterleave + ./deinterleave $< ${@:%-2.ssd=%-1.ssd} $@ + +disk.img:assemble ${SSD} + ./assemble ${SSD} > $@ + +assemble:assemble.c +deinterleave:deinterleave.c + +clean: + /bin/rm -f deinterleave assemble disk.img ${DSDI_SSD} + + diff --git a/mmc/assemble.c b/mmc/assemble.c new file mode 100644 index 0000000..05bf769 --- /dev/null +++ b/mmc/assemble.c @@ -0,0 +1,96 @@ +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <strings.h> + + + +char buf[204800]; + +int write_entry(int image,void *ptr) +{ +off_t o=(image+1)*16; +lseek(1,o,SEEK_SET); +write(1,ptr,16); +} + +int write_image(int image,void *ptr) +{ +off_t o=(image*204800)+8192; +lseek(1,o,SEEK_SET); +write(1,ptr,204800); +} + + +int main(int argc,char *argv[]) +{ +int image=0; +int fd,i; +uint8_t entry[16]; +char *ptr; + + +bzero(entry,sizeof(entry)); +entry[0]=0; +entry[1]=1; +entry[2]=2; +entry[3]=3; +lseek(1,0L,SEEK_SET); +write(1,entry,16); + + +for (argc--,argv++; argc;argc--,argv++) +{ + +bzero(buf,sizeof(buf)); +fd=open(*argv,O_RDONLY); +read(fd,buf,sizeof(buf)); +close(fd); + +ptr=strstr(*argv,".ssd"); +if (ptr) *ptr='\0'; +ptr=strstr(*argv,".SSD"); +if (ptr) *ptr='\0'; + +bzero(entry,sizeof(entry)); +strncpy(entry,*argv,12); + + +entry[12]=0; +entry[13]=0; +entry[14]=0; +entry[15]=0x0f; + +write_image(image,buf); +write_entry(image,entry); + +image++; +} + +bzero(buf,sizeof(buf)); +for (;image<511;++image) { + +bzero(entry,sizeof(entry)); +entry[15]=0xf0; +write_image(image,buf); +} + +} + + + + + + + + + + + + + + + + diff --git a/mmc/deinterleave.c b/mmc/deinterleave.c new file mode 100644 index 0000000..3e33d55 --- /dev/null +++ b/mmc/deinterleave.c @@ -0,0 +1,27 @@ +#include <stdio.h> + +int main(int argc,char *argv[]) +{ + FILE *in=fopen(argv[1],"r"); + FILE *o1=fopen(argv[2],"w"); + FILE *o2=fopen(argv[3],"w"); + char buf[2560]; + unsigned track; + + if (!in) return -1; + if (!o1) return -1; + if (!o2) return -1; + + for (track=0;track<80;++track) { + fread(buf,sizeof(buf),1,in); + fwrite(buf,sizeof(buf),1,o1); + fread(buf,sizeof(buf),1,in); + fwrite(buf,sizeof(buf),1,o2); + } + + fclose(o2); + fclose(o1); + fclose(in); + + return 0; +} diff --git a/roms/basic2.rom b/roms/basic2.rom Binary files differnew file mode 100644 index 0000000..b22ae98 --- /dev/null +++ b/roms/basic2.rom diff --git a/roms/dnfs.rom b/roms/dnfs.rom Binary files differnew file mode 100644 index 0000000..51b50a5 --- /dev/null +++ b/roms/dnfs.rom diff --git a/roms/empty.rom b/roms/empty.rom new file mode 100644 index 0000000..171fa2b --- /dev/null +++ b/roms/empty.rom @@ -0,0 +1 @@ +ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ
\ No newline at end of file diff --git a/roms/os12.rom b/roms/os12.rom Binary files differnew file mode 100644 index 0000000..3d4a294 --- /dev/null +++ b/roms/os12.rom diff --git a/roms/supermmc.rom b/roms/supermmc.rom Binary files differnew file mode 100644 index 0000000..9b4e952 --- /dev/null +++ b/roms/supermmc.rom |