mirror of
https://github.com/mist-devel/mist-board.git
synced 2026-02-04 07:13:01 +00:00
[BBC] Planetoid, Snapper fixed, and other m6522 improvements. Clocks improvements.
This commit is contained in:
@@ -88,6 +88,7 @@ wire io_fred;
|
||||
wire io_jim;
|
||||
wire io_sheila;
|
||||
|
||||
// SHEILA
|
||||
wire crtc_enable;
|
||||
wire acia_enable;
|
||||
wire serproc_enable;
|
||||
@@ -645,6 +646,11 @@ assign sound_di = sys_via_pa_out;
|
||||
|
||||
// Others (idle until missing bits implemented)
|
||||
assign sys_via_pb_in[7:4] = { 2'b11, !joy_but[1], !joy_but[0] };
|
||||
assign sys_via_pb_in[3:0] = sys_via_pb_out[3:0];
|
||||
|
||||
// Fixes Planetoid, Snapper etc
|
||||
assign user_via_pa_in = user_via_pa_out;
|
||||
assign user_via_pb_in = user_via_pb_out;
|
||||
|
||||
|
||||
assign MEM_ADR = cpu_a[15:0];
|
||||
|
||||
103
cores/bbc/rtl/clocks.v
Normal file → Executable file
103
cores/bbc/rtl/clocks.v
Normal file → Executable file
@@ -1,5 +1,5 @@
|
||||
`timescale 1ns / 1ps
|
||||
/*
|
||||
`timescale 1ns / 1ps
|
||||
/*
|
||||
Copyright (c) 2012, Stephen J Leary
|
||||
All rights reserved.
|
||||
|
||||
@@ -24,35 +24,35 @@ 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.
|
||||
*/
|
||||
*/
|
||||
module clocks(
|
||||
|
||||
input clk_32m,
|
||||
|
||||
input clk_32m,
|
||||
input clk_24m,
|
||||
|
||||
input reset_n,
|
||||
|
||||
input reset_n,
|
||||
input mhz1_enable,
|
||||
|
||||
output wire mhz4_clken,
|
||||
output wire mhz2_clken,
|
||||
|
||||
output wire mhz4_clken,
|
||||
output wire mhz2_clken,
|
||||
output wire mhz1_clken,
|
||||
|
||||
output wire cpu_cycle,
|
||||
|
||||
output wire cpu_cycle,
|
||||
output wire cpu_clken,
|
||||
|
||||
output wire vid_clken,
|
||||
output wire ttxt_clken,
|
||||
output wire vid_clken,
|
||||
output wire ttxt_clken,
|
||||
output wire ttxt_clkenx2,
|
||||
|
||||
output wire tube_clken
|
||||
);
|
||||
|
||||
|
||||
output wire tube_clken
|
||||
);
|
||||
|
||||
reg [4:0] clken_counter;
|
||||
reg cpu_cycle_mask;
|
||||
|
||||
// SAA5050 needs a 6 MHz clock enable relative to a 24 MHz clock
|
||||
reg [1:0] ttxt_clken_counter;
|
||||
|
||||
reg [1:0] cpu_cycle_mask;
|
||||
|
||||
// SAA5050 needs a 6 MHz clock enable relative to a 24 MHz clock
|
||||
reg [1:0] ttxt_clken_counter;
|
||||
|
||||
// Clock enable generation - 32 MHz clock split into 32 cycles^M
|
||||
// CPU is on 0 and 16 (but can be masked by 1 MHz bus accesses)^M
|
||||
// Video is on all odd cycles (16 MHz)^M
|
||||
@@ -61,16 +61,16 @@ assign vid_clken = clken_counter[0]; // & ~vsync_latch & ~hsync_latch;
|
||||
// 1,3,5...^M
|
||||
assign mhz4_clken = clken_counter[0] & clken_counter[1] & clken_counter[2];
|
||||
// 7/15/23/31^M
|
||||
assign mhz2_clken = mhz4_clken & clken_counter[3];
|
||||
// 1/17
|
||||
assign mhz2_clken = mhz4_clken & clken_counter[3];
|
||||
// 1/17
|
||||
assign tube_clken = clken_counter[0] & !clken_counter[1] & !clken_counter[2];
|
||||
// 15/31^M
|
||||
assign mhz1_clken = mhz2_clken & clken_counter[4];
|
||||
// 31^M
|
||||
assign cpu_cycle = ~(clken_counter[0] | clken_counter[1] | clken_counter[2] | clken_counter[3]);
|
||||
// 0/16^M
|
||||
assign cpu_clken = /* reset_n && */ cpu_cycle & ~cpu_cycle_mask;
|
||||
|
||||
assign cpu_clken = cpu_cycle & ~cpu_cycle_mask[1] & ~cpu_cycle_mask[0];
|
||||
|
||||
always @(posedge clk_32m)
|
||||
begin : clk_gen
|
||||
// if (reset_n === 1'b 0)
|
||||
@@ -81,43 +81,40 @@ always @(posedge clk_32m)
|
||||
// begin
|
||||
clken_counter <= clken_counter + 5'd1;
|
||||
// end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
always @(posedge clk_32m)
|
||||
begin : cycle_stretch
|
||||
if (reset_n === 1'b 0)
|
||||
begin
|
||||
cpu_cycle_mask <= 1'b 0;
|
||||
end
|
||||
else if (mhz2_clken === 1'b 1 )
|
||||
begin
|
||||
if ((mhz1_enable === 1'b 1) && (cpu_cycle_mask === 1'b 0))
|
||||
begin
|
||||
|
||||
// Block CPU cycles until 1 MHz cycle has completed
|
||||
cpu_cycle_mask <= 1'b 1;
|
||||
end
|
||||
if (mhz1_clken === 1'b 1)
|
||||
begin
|
||||
// CPU can run again
|
||||
// FIXME: This may not be correct in terms of CPU cycles, but it
|
||||
// should work
|
||||
cpu_cycle_mask <= 1'b 0;
|
||||
end
|
||||
if (reset_n === 1'b 0) begin
|
||||
cpu_cycle_mask <= 2'b 00;
|
||||
end
|
||||
else if (mhz2_clken === 1'b 1 ) begin
|
||||
if ((mhz1_enable === 1'b 1) && (cpu_cycle_mask === 2'b 00)) begin
|
||||
// Block CPU cycles until 1 MHz cycle has completed
|
||||
if (mhz1_clken === 1'b 0) begin
|
||||
cpu_cycle_mask <= 2'b 01;
|
||||
end else begin
|
||||
cpu_cycle_mask <= 2'b 10;
|
||||
end
|
||||
end
|
||||
if (cpu_cycle_mask !== 2'b 00) begin
|
||||
cpu_cycle_mask <= cpu_cycle_mask - 2'b 01;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk_24m)
|
||||
begin : ttxt_clk_gen
|
||||
if (reset_n === 1'b 0) begin
|
||||
ttxt_clken_counter <= {2{1'b 0}};
|
||||
end else begin
|
||||
end else begin
|
||||
ttxt_clken_counter <= ttxt_clken_counter + 1;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
// 6 MHz clock enable for SAA5050
|
||||
assign ttxt_clken = ttxt_clken_counter === 0 ? 1'b 1 : 1'b 0;
|
||||
assign ttxt_clkenx2 = !ttxt_clken_counter[0];
|
||||
|
||||
endmodule
|
||||
assign ttxt_clken = ttxt_clken_counter === 0 ? 1'b 1 : 1'b 0;
|
||||
assign ttxt_clkenx2 = !ttxt_clken_counter[0];
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -40,6 +40,9 @@
|
||||
//
|
||||
// Revision list
|
||||
//
|
||||
// version 004 fixes to PB7 T1 control and Mode 0 Shift Register operation
|
||||
// version 003 fix reset of T1/T2 IFR flags if T1/T2 is reload via reg5/reg9 from wolfgang (WoS)
|
||||
// Ported to numeric_std and simulation fix for signal initializations from arnim laeuger
|
||||
// version 002 fix from Mark McDougall, untested
|
||||
// version 001 initial release
|
||||
// not very sure about the shift register, documentation is a bit light.
|
||||
@@ -114,7 +117,7 @@ wire O_CB1;
|
||||
wire O_CB1_OE_L;
|
||||
reg O_CB2;
|
||||
reg O_CB2_OE_L;
|
||||
reg [1:0] phase;
|
||||
reg [1:0] phase = 2'b00;
|
||||
reg p2_h_t1;
|
||||
wire cs;
|
||||
|
||||
@@ -145,24 +148,24 @@ reg [7:0] load_data;
|
||||
// timer 1
|
||||
reg [15:0] t1c;
|
||||
reg t1c_active;
|
||||
wire t1c_done;
|
||||
reg t1c_done;
|
||||
reg t1_w_reset_int;
|
||||
reg t1_r_reset_int;
|
||||
reg t1_load_counter;
|
||||
wire t1_reload_counter;
|
||||
reg t1_reload_counter;
|
||||
reg t1_toggle;
|
||||
reg t1_irq;
|
||||
|
||||
// timer 2
|
||||
reg [15:0] t2c;
|
||||
reg t2c_active;
|
||||
wire t2c_done;
|
||||
reg t2c_done;
|
||||
reg t2_pb6;
|
||||
reg t2_pb6_t1;
|
||||
reg t2_w_reset_int;
|
||||
reg t2_r_reset_int;
|
||||
reg t2_load_counter;
|
||||
wire t2_reload_counter;
|
||||
reg t2_reload_counter;
|
||||
reg t2_irq;
|
||||
reg t2_sr_ena;
|
||||
|
||||
@@ -202,8 +205,6 @@ wire cb2_int;
|
||||
reg ca2_irq;
|
||||
reg cb2_irq;
|
||||
reg final_irq;
|
||||
wire p_timer1_done_done;
|
||||
wire p_timer2_done_done;
|
||||
reg p_timer2_ena;
|
||||
reg p_sr_dir_out;
|
||||
reg p_sr_ena;
|
||||
@@ -328,6 +329,7 @@ always @(posedge CLK) begin
|
||||
end
|
||||
|
||||
if (r_acr[7] === 1'b1) begin
|
||||
// DMB: Forgetting to clear B7 broke Acornsoft Planetoid
|
||||
if(t1_load_counter)
|
||||
r_orb[7] <= 1'b0; // writing T1C-H resets bit 7
|
||||
else if (t1_toggle === 1'b1)
|
||||
@@ -340,8 +342,12 @@ end
|
||||
|
||||
always @(posedge CLK) begin
|
||||
|
||||
//Fix incorrect power up values in timer latches
|
||||
if (RESET_L === 1'b 0) begin
|
||||
// The spec says, this is not reset.
|
||||
// Fact is that the 1541 VIA1 timer won't work,
|
||||
// as the firmware ONLY sets the r_t1l_h latch!!!!
|
||||
// DMB: These are observed power on values from the Beeb
|
||||
// DMB: Note, it's a little overzeleaous setting these on reset; that doesn't happen in reality
|
||||
r_t1l_l <= 8'h FE;
|
||||
r_t1l_h <= 8'h FF;
|
||||
r_t2l_l <= 8'h FE;
|
||||
@@ -419,20 +425,21 @@ assign O_DATA_OE_L = (cs === 1'b 1 & I_RW_L === 1'b 1) ? 1'b0 : 1'b1;
|
||||
|
||||
always @(posedge CLK) begin
|
||||
|
||||
if (ENA_4 === 1'b 1) begin
|
||||
if (ENA_4 === 1'b 1) begin
|
||||
|
||||
t1_r_reset_int <= 1'b0;
|
||||
t2_r_reset_int <= 1'b0;
|
||||
sr_read_ena <= 1'b0;
|
||||
r_irb_hs <= 1'b 0;
|
||||
r_ira_hs <= 1'b 0;
|
||||
O_DATA <= 8'h 00; // default
|
||||
|
||||
if (cs === 1'b 1 & I_RW_L === 1'b 1) begin
|
||||
case (I_RS)
|
||||
4'h 0: begin
|
||||
O_DATA <= r_irb & ~r_ddrb | r_orb & r_ddrb;
|
||||
// when x"0" => O_DATA <= r_irb; r_irb_hs <= '1';
|
||||
// fix from Mark McDougall, untested
|
||||
4'h 0: begin
|
||||
O_DATA <= r_irb & ~r_ddrb | r_orb & r_ddrb;
|
||||
r_irb_hs <= 1'b 1;
|
||||
end
|
||||
|
||||
@@ -505,7 +512,7 @@ always @(posedge CLK) begin
|
||||
|
||||
endcase
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
//
|
||||
@@ -781,10 +788,11 @@ always @(posedge CLK) begin
|
||||
end
|
||||
end
|
||||
|
||||
// data direction reg (ddr) 0 = input, 1 = output
|
||||
|
||||
assign O_PA = r_ora;
|
||||
assign O_PA_OE_L = ~r_ddra;
|
||||
|
||||
|
||||
assign O_PB_OE_L[6:0] = ~r_ddrb[6:0];
|
||||
// not clear if r_ddrb(7) must be 1 as well, an output if under t1 control
|
||||
assign O_PB_OE_L[7] = (r_acr[7] === 1'b 1) ? 1'b 0 : ~r_ddrb[7];
|
||||
@@ -795,11 +803,21 @@ assign O_PB[7:0] = r_orb[7:0];
|
||||
// Timer 1
|
||||
//
|
||||
|
||||
// data direction reg (ddr) 0 = input, 1 = output
|
||||
reg p_timer1_done_done;
|
||||
always @(posedge CLK) begin
|
||||
|
||||
if (ENA_4 === 1'b1) begin
|
||||
p_timer1_done_done = t1c == 16'h 0000;
|
||||
t1c_done <= p_timer1_done_done & phase == 2'b 11;
|
||||
if (phase === 2'b 11) begin
|
||||
t1_reload_counter <= p_timer1_done_done & r_acr[6] == 1'b1;
|
||||
end
|
||||
if (t1_load_counter ) begin
|
||||
t1c_done <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
assign p_timer1_done_done = t1c == 16'h 0000;
|
||||
assign t1c_done = p_timer1_done_done & phase == 2'b 11;
|
||||
assign t1_reload_counter = p_timer1_done_done & r_acr[6] == 1'b 1;
|
||||
|
||||
always @(posedge CLK) begin
|
||||
|
||||
@@ -819,18 +837,17 @@ always @(posedge CLK) begin
|
||||
t1c_active <= 1'b0;
|
||||
end
|
||||
|
||||
if (RESET_L === 1'b 0) begin
|
||||
t1c_active <= 1'b0;
|
||||
end
|
||||
|
||||
t1_toggle <= 1'b 0;
|
||||
|
||||
if (t1c_active & t1c_done) begin
|
||||
t1_toggle <= 1'b 1;
|
||||
t1_irq <= 1'b 1;
|
||||
end
|
||||
else if (RESET_L === 1'b 0 | t1_w_reset_int | t1_r_reset_int |
|
||||
clear_irq[6] === 1'b 1 ) begin
|
||||
else if (t1_w_reset_int | t1_r_reset_int | clear_irq[6] === 1'b 1 ) begin
|
||||
t1_irq <= 1'b 0;
|
||||
end
|
||||
|
||||
if (t1_load_counter) begin // irq reset on load!
|
||||
t1_irq <= 1'b 0;
|
||||
end
|
||||
end
|
||||
@@ -852,9 +869,20 @@ always @(posedge CLK) begin
|
||||
end
|
||||
end
|
||||
|
||||
assign p_timer2_done_done = t2c == 16'h 0000;
|
||||
assign t2c_done = p_timer2_done_done & phase == 2'b 11;
|
||||
assign t2_reload_counter = p_timer2_done_done;
|
||||
reg p_timer2_done_done;
|
||||
always @(posedge CLK) begin
|
||||
|
||||
if (ENA_4 === 1'b1) begin
|
||||
p_timer2_done_done = t2c == 16'h 0000;
|
||||
t2c_done <= p_timer2_done_done & phase == 2'b 11;
|
||||
if (phase === 2'b 11) begin
|
||||
t2_reload_counter <= p_timer2_done_done;
|
||||
end
|
||||
if (t2_load_counter ) begin // done reset on load!
|
||||
t2c_done <= 1'b0;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
always @(posedge CLK) begin
|
||||
@@ -893,17 +921,17 @@ always @(posedge CLK) begin
|
||||
t2c_active <= 1'b0;
|
||||
end
|
||||
|
||||
if (RESET_L === 1'b 0) begin
|
||||
t2c_active <= 1'b0;
|
||||
end
|
||||
|
||||
if (t2c_active & t2c_done) begin
|
||||
t2_irq <= 1'b 1;
|
||||
end
|
||||
else if (RESET_L === 1'b 0 | t2_w_reset_int | t2_r_reset_int |
|
||||
clear_irq[5] === 1'b 1 ) begin
|
||||
else if (t2_w_reset_int | t2_r_reset_int | clear_irq[5] === 1'b 1 ) begin
|
||||
t2_irq <= 1'b 0;
|
||||
end
|
||||
|
||||
if (t2_load_counter) begin // irq reset on load!
|
||||
t2_irq <= 1'b 0;
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1011,7 +1039,10 @@ always @(posedge CLK) begin
|
||||
// input
|
||||
if (sr_cnt[3] === 1'b 1 | p_sr_cb1_ip === 1'b 1) begin
|
||||
if (sr_strobe_rising) begin
|
||||
r_sr <= {r_sr[6:0], I_CB2};
|
||||
r_sr[0] <= I_CB2;
|
||||
end
|
||||
else if (sr_strobe_falling) begin
|
||||
r_sr[7:1] <= r_sr[6:0];
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1036,7 +1067,10 @@ always @(posedge CLK) begin
|
||||
|
||||
p_sr_sr_count_ena = sr_strobe_rising;
|
||||
|
||||
if (sr_write_ena | sr_read_ena) begin
|
||||
// DMB: reseting sr_count when not enabled cause the sr to
|
||||
// start running immediately it was enabled, which is incorrect
|
||||
// and broke the latest SmartSPI ROM on the BBC Micro
|
||||
if (p_sr_ena & (sr_write_ena | sr_read_ena)) begin
|
||||
|
||||
// some documentation says sr bit in IFR must be set as well ?
|
||||
sr_cnt <= 4'b 1000;
|
||||
|
||||
Reference in New Issue
Block a user