1
0
mirror of https://github.com/mist-devel/mist-board.git synced 2026-01-28 04:37:12 +00:00

[QL] qimi mouse support

This commit is contained in:
Till Harbaum
2015-08-19 15:48:02 +02:00
parent 75cfb2965e
commit e8adc3e78b
6 changed files with 245 additions and 33 deletions

View File

@@ -24,6 +24,8 @@ module mdv (
input clk, // 21mhz clock
input reset,
input reverse,
input sel,
// control bits
@@ -60,8 +62,6 @@ assign tx_empty = 1'b0;
// the part of ram which is unavailable to the 68k CPU (>16MB). It is then continously
// replayed from there at 200kbit/s
reg [7:0] mdv_sector /* synthesis noprune */;
reg [24:0] mdv_end /* synthesis noprune */;
// determine mdv image size after download
@@ -134,7 +134,6 @@ always @(posedge mdv_clk) begin
mdv_gap_cnt <= 10'd0; // count bytes until gap
mdv_gap_state <= 1'b1; // toggle header + data gap
mdv_gap_active <= 1'b1; // gap atm
mdv_sector <= 8'd0;
mdv_gap <= 1'b1;
end else begin
mdv_gap_cnt <= mdv_gap_cnt + 10'd1;
@@ -162,18 +161,17 @@ always @(posedge mdv_clk) begin
mdv_gap_active <= 1'b1; // now comes a gap
mdv_gap <= 1'b1;
// The sectors on cartridges are written in descending order
// The images seem to contain them in ascending order. So we
// have to replay them backwards for better performance
if(reverse) begin
// The sectors on cartridges are written in descending order
// Some images seem to contain them in ascending order. So we
// have to replay them backwards for better performance
if(mem_addr == BASE_ADDR + 343 - 1)
mem_addr <= mdv_end - 343 + 1;
else
mem_addr <= mem_addr - 2*343 + 1;
mdv_sector <= mdv_sector + 8'd1;
if(mem_addr == BASE_ADDR + 343 - 1)
mem_addr <= mdv_end - 343 + 1;
else
mem_addr <= mem_addr - 2*343 + 1;
end
end
end
end
end

150
cores/ql/qimi.v Normal file
View File

@@ -0,0 +1,150 @@
//
// qimi.v - Ql mouse Interface
//
// Sinclair QL for the MiST
// https://github.com/mist-devel
//
// Copyright (c) 2015 Till Harbaum <till@harbaum.org>
//
// This source file is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This source file is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
module qimi (
input clk,
input reset,
input cpu_sel,
input [1:0] cpu_addr, // a5, a1
output [7:0] cpu_data,
output reg irq,
// ps2 interface
input ps2_clk,
input ps2_data
);
// generate irq ack whenever cpu accesses 1bf9c
reg irq_ack;
always @(negedge clk) begin
irq_ack <= 1'b0;
if(cpu_sel && cpu_addr == 2'b11)
irq_ack <= 1'b1;
end
wire x_dir = !x_pos[9];
wire y_dir = !y_pos[9];
wire x_mov = (x_pos != 0);
wire y_mov = (y_pos != 0);
assign cpu_data =
(cpu_addr == 2'b00)?{2'b00,!b[0],!b[1],4'b0000}: // 1bf9c
(cpu_addr == 2'b10)?{2'b00,y_mov,x_dir,1'b0,x_mov,1'b0,y_dir }: // 1bfbc
8'h00;
// registers keeping state of current mouse state
reg [1:0] b;
reg [9:0] x_pos;
reg [9:0] y_pos;
wire [7:0] byte;
wire valid;
wire error;
reg [1:0] cnt;
reg sign_x, sign_y;
reg [7:0] x_reg;
// counter to limit irq rate to 2khz
reg [9:0] irq_holdoff;
always @(posedge clk) begin
if(reset) begin
x_pos <= 10'd0;
y_pos <= 10'd0;
cnt <= 2'd0;
irq <= 1'b0;
irq_holdoff <= 10'd0;
end else begin
// check if we have to fire another irq
if(irq_holdoff != 0) begin
irq_holdoff <= irq_holdoff - 10'd1;
if((irq_holdoff == 1) && (x_mov || y_mov))
irq <= 1'b1;
end
// ps2 decoder has received a valid byte
if(valid) begin
// count through all three data bytes
cnt <= cnt + 2'd1;
if(cnt == 0) begin
// bit 3 must be 1. Stay in state 0 otherwise
if(!byte[3]) cnt <= 2'd0;
b <= byte[1:0];
sign_x <= byte[4];
sign_y <= byte[5];
end else if(cnt == 1) begin
x_reg <= byte;
end else begin
// the ps2 packet contains a 9 bit value. We only use the upper
// 7. Otherwise the mouse would be too fast for our low resolution
x_pos <= x_pos + { {2{sign_x}}, x_reg};
y_pos <= y_pos + { {2{sign_y}}, byte};
cnt <= 2'd0;
if(irq_holdoff == 0)
irq_holdoff <= 10'd1;
end
end else begin
// one bit has been reported to host
if(irq_ack) begin
if(x_pos != 0) begin
if(x_pos[9]) x_pos <= x_pos + 10'd1;
else x_pos <= x_pos - 10'd1;
end
if(y_pos != 0) begin
if(y_pos[9]) y_pos <= y_pos + 10'd1;
else y_pos <= y_pos - 10'd1;
end
// clear irq
irq <= 1'b0;
// next irq after some time ...
irq_holdoff <= 10'd1000;
end
end
end
end
// the ps2 decoder has been taken from the zx spectrum core
ps2_intf ps2_mouse (
.CLK ( clk ),
.nRESET ( !reset ),
// PS/2 interface
.PS2_CLK ( ps2_clk ),
.PS2_DATA ( ps2_data ),
// Byte-wide data interface - only valid for one clock
// so must be latched externally if required
.DATA ( byte ),
.VALID ( valid ),
.ERROR ( error )
);
endmodule

View File

@@ -155,6 +155,7 @@ set_global_assignment -name FITTER_EFFORT "FAST FIT"
set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW"
set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
set_instance_assignment -name CURRENT_STRENGTH_NEW "MAXIMUM CURRENT" -to VGA_*
set_global_assignment -name VERILOG_FILE qimi.v
set_global_assignment -name VHDL_FILE "t49_rom-struct-a.vhd"
set_global_assignment -name VHDL_FILE "t48/rtl/vhdl/system/t49_rom-e.vhd"
set_global_assignment -name VHDL_FILE t48/rtl/vhdl/system/generic_ram_ena.vhd

View File

@@ -62,13 +62,14 @@ module ql (
parameter CONF_STR = {
"QL;;",
"F1,MDV;",
"O2,RAM,128k,640k;",
"O3,Video mode,PAL,NTSC;",
"O4,Scanlines,Off,On;",
"T5,Reset"
"O2,MDV direction,normal,reverse;",
"O3,RAM,128k,640k;",
"O4,Video mode,PAL,NTSC;",
"O5,Scanlines,Off,On;",
"T6,Reset"
};
parameter CONF_STR_LEN = 4+7+17+23+20+8;
parameter CONF_STR_LEN = 4+7+32+17+23+20+8;
// the status register is controlled by the on screen display (OSD)
wire [7:0] status;
@@ -78,6 +79,7 @@ wire [1:0] buttons;
wire [7:0] js0, js1;
wire ps2_kbd_clk, ps2_kbd_data;
wire ps2_mouse_clk, ps2_mouse_data;
// generate ps2_clock
wire ps2_clock = ps2_clk_div[6]; // ~20khz
@@ -104,6 +106,8 @@ user_io #(.STRLEN(CONF_STR_LEN)) user_io (
.ps2_clk ( ps2_clock ),
.ps2_kbd_clk ( ps2_kbd_clk ),
.ps2_kbd_data ( ps2_kbd_data ),
.ps2_mouse_clk ( ps2_mouse_clk ),
.ps2_mouse_data ( ps2_mouse_data ),
.status ( status )
);
@@ -242,9 +246,9 @@ zx8301 zx8301 (
.clk_video ( clk10 ),
.video_cycle ( video_cycle ),
.ntsc ( status[3] ),
.ntsc ( status[4] ),
.scandoubler ( !tv15khz ),
.scanlines ( status[4] ),
.scanlines ( status[5] ),
.clk_bus ( clk2 ),
.cpu_cs ( zx8301_cs ),
@@ -271,7 +275,7 @@ wire rom_download = dio_download && (dio_index == 0);
reg [11:0] reset_cnt;
wire reset = (reset_cnt != 0);
always @(posedge clk2) begin
if(buttons[1] || status[0] || status[5] || !pll_locked || rom_download)
if(buttons[1] || status[0] || status[6] || !pll_locked || rom_download)
reset_cnt <= 12'hfff;
else if(reset_cnt != 0)
reset_cnt <= reset_cnt - 1;
@@ -300,12 +304,13 @@ zx8302 zx8302 (
.clk_sys ( CLOCK_27[0] ),
.clk ( clk21 ),
.xint ( qimi_irq ),
.ipl ( cpu_ipl ),
.led ( LED ),
.audio ( audio ),
// CPU connection
.clk_bus ( clk2 ),
.clk_bus ( clk2 ),
.cpu_sel ( zx8302_sel ),
.cpu_wr ( cpu_wr ),
.cpu_addr ( zx8302_addr ),
@@ -329,11 +334,35 @@ zx8302 zx8302 (
.mdv_men ( mdv_men ),
.video_cycle ( video_cycle ),
.mdv_reverse ( status[2] ),
.mdv_download ( mdv_download ),
.mdv_dl_addr ( dio_addr )
);
// ---------------------------------------------------------------------------------
// --------------------------- QIMI compatible mouse -------------------------------
// ---------------------------------------------------------------------------------
// qimi is at 1bfxx
wire qimi_sel = cpu_io && (cpu_addr[13:8] == 6'b111111);
wire [7:0] qimi_data;
wire qimi_irq;
qimi qimi(
.reset ( reset ),
.clk ( clk2 ),
.cpu_sel ( qimi_sel ),
.cpu_addr ( { cpu_addr[5], cpu_addr[1] } ),
.cpu_data ( qimi_data ),
.irq ( qimi_irq ),
.ps2_clk ( ps2_mouse_clk ),
.ps2_data ( ps2_mouse_data )
);
// ---------------------------------------------------------------------------------
// -------------------------------------- CPU --------------------------------------
// ---------------------------------------------------------------------------------
@@ -341,13 +370,16 @@ zx8302 zx8302 (
// address decoding
wire cpu_io = ({cpu_addr[19:14], 2'b00} == 8'h18); // internal IO $18000-$1bffff
wire cpu_bram = (cpu_addr[19:17] == 3'b001); // 128k RAM at $20000
wire cpu_xram = status[2] && ((cpu_addr[19:18] == 2'b01) ||
wire cpu_xram = status[3] && ((cpu_addr[19:18] == 2'b01) ||
(cpu_addr[19:18] == 2'b10)); // 512k RAM at $40000 if enabled
wire cpu_ram = cpu_bram || cpu_xram; // any RAM
wire cpu_rom = (cpu_addr[19:16] == 4'h0); // 64k ROM at $0
wire cpu_mem = cpu_ram || cpu_rom; // any memory mapped to sdram
wire [15:0] io_dout = cpu_addr[6]?16'h0000:zx8302_dout;
wire [15:0] io_dout =
qimi_sel?{qimi_data, qimi_data}:
(!cpu_addr[6])?zx8302_dout:
16'h0000;
// demultiplex the various data sources
wire [15:0] cpu_din =

View File

@@ -3,4 +3,23 @@ QL for MIST
This is an implementation of the Sinclair QL for the MIST board.
It's based on the TG68K CPU core.
It's based on the TG68K CPU core and the t48 core for the IPC.
Features:
- tg68k
- 128k or 640k
- roughly twice the original speed
- zx8301
- all video modes incl. blinking
- scan doubler for VGA output (can be disabled)
- optional scan line effect
- zx8302
- IPC based on t48 using the original firmware
- audio
- keyboard
- PC keyboard shortcuts (backspace, ...)
- joysticks
- interrupt handling
- microdrive emulation
- qlay format
- qimi mouse

View File

@@ -28,7 +28,8 @@ module zx8302 (
// interrupts
output [1:0] ipl,
input xint,
// sdram interface for microdrive emulation
output [24:0] mdv_addr,
input [15:0] mdv_din,
@@ -39,7 +40,8 @@ module zx8302 (
// interface to watch MDV cartridge upload
input [24:0] mdv_dl_addr,
input mdv_download,
input mdv_reverse,
output led,
output audio,
@@ -129,8 +131,8 @@ wire [7:0] io_status = { zx8302_comdata_in, ipc_busy, 2'b00,
assign cpu_dout =
// 18000/18001 and 18002/18003
(cpu_addr == 2'b00)?rtc[46:31]:
(cpu_addr == 2'b01)?rtc[30:15]:
(cpu_addr == 2'b00)?rtc[47:32]:
(cpu_addr == 2'b01)?rtc[31:16]:
// 18020/18021 and 18022/18023
(cpu_addr == 2'b10)?{io_status, irq_pending}:
@@ -195,7 +197,7 @@ ipc ipc (
// ---------------------------------------------------------------------------------
wire [7:0] irq_pending = {1'b0, (mdv_sel == 0), clk64k,
1'b0, vsync_irq, 1'b0, 1'b0, gap_irq };
xint_irq, vsync_irq, 1'b0, 1'b0, gap_irq };
reg [2:0] irq_mask;
reg [4:0] irq_ack;
@@ -219,6 +221,14 @@ always @(posedge gap_irq_in or posedge gap_irq_reset) begin
else gap_irq <= 1'b1;
end
// toggling the mask will also trigger irqs ...
wire xint_irq_in = xint && irq_mask[2];
reg xint_irq;
wire xint_irq_reset = reset || irq_ack[4];
always @(posedge xint_irq_in or posedge xint_irq_reset) begin
if(xint_irq_reset) xint_irq <= 1'b0;
else xint_irq <= 1'b1;
end
// ---------------------------------------------------------------------------------
@@ -233,11 +243,13 @@ wire [7:0] mdv_byte;
assign led = !mdv_sel[0];
mdv mdv (
.clk ( clk ),
.clk ( clk ),
.reset ( init ),
.sel ( mdv_sel[0] ),
.reverse ( mdv_reverse ),
// control bits
.gap ( mdv_gap ),
.tx_empty ( mdv_tx_empty ),
@@ -267,9 +279,9 @@ always @(negedge mctrl[1])
// ---------------------------------------------------------------------------------
// PLL for the real time clock (rtc)
reg [46:0] rtc;
reg [47:0] rtc;
always @(posedge clk64k)
rtc <= rtc + 47'd1;
rtc <= rtc + 48'd1;
wire clk64k;
pll_rtc pll_rtc (