SamCoupe a test2

This commit is contained in:
antoniovillena 2016-04-28 14:17:52 +02:00
parent 5bf160631a
commit 9b683eb5f6
11 changed files with 17666 additions and 67 deletions

View File

@ -88,12 +88,19 @@ module asic (
VBPORCH +
TBORDER;
// Start of vertical sync, horizontal counter (last 4 scanlines)
parameter BEGINVSYNCH = HACTIVEREGION + RBORDER + HFPORCH + HSYNC + HBPORCH;
parameter BEGINVINTH = HACTIVEREGION + RBORDER + HFPORCH;
// Start and end of vertical retrace interrupt, horizontal counter
parameter BEGINVINTH = BEGINVSYNCH; //HACTIVEREGION + RBORDER + HFPORCH;
parameter ENDVINTH = (BEGINVINTH + 256)%HTOTAL;
// Start and end of vertical retrace interrupt, vertical counter
parameter BEGINVINTV = VACTIVEREGION + BBORDER + VFPORCH - 1;
parameter ENDVINTV = VACTIVEREGION + BBORDER + VFPORCH;
parameter ENDVINTH = (BEGINVINTH + 256)%HTOTAL;
parameter BEGINHINTH = HACTIVEREGION + RBORDER + HFPORCH;
// Start and end of raster interrupt, horizontal counter
parameter BEGINHINTH = HACTIVEREGION + RBORDER;
parameter ENDHINTH = (BEGINHINTH + 256)%HTOTAL;
parameter IOADDR_VMPR = 8'd252,
@ -103,7 +110,8 @@ module asic (
IOADDR_LINEINT = 8'd249,
IOADDR_STATUS = 8'd249,
IOADDR_BASECLUT = 8'd248,
IOADDR_ATTRIB = 8'd255;
IOADDR_ATTRIB = 8'd255,
IOADDR_HLPEN = 8'd248;
//////////////////////////////////////////////////////////////////////////
// IO regs
@ -122,7 +130,7 @@ module asic (
wire rom_in_section_d = lmpr[6];
wire write_protect_section_a = lmpr[7];
reg [7:0] hmpr = 8'h02; // port 251. Bit 7 is not used for now. R/W
reg [7:0] hmpr = 8'h00; // port 251. Bit 7 is not used for now. R/W
wire [4:0] high_page = hmpr[4:0];
wire [1:0] clut_mode_3_hi = hmpr[6:5];
@ -134,6 +142,9 @@ module asic (
reg [7:0] lineint = 8'hFF; // port 249 write only
reg [7:0] hpen = 8'h00;
reg [7:0] lpen = 8'h00;
reg [6:0] clut[0:15]; // Port xF8h where x=0..F
initial begin
clut[ 0] = 7'b000_0_000;
@ -171,6 +182,23 @@ module asic (
end
end
//////////////////////////////////////////////////////////////////////////
// HPEN and LPEN counters
always @(posedge clk) begin
if (hc[0] == 1'b0) begin
if (hc == HACTIVEREGION) begin
if (vc == VTOTAL-1)
hpen <= 8'h00;
else if (vc < VACTIVEREGION)
hpen <= hpen + 1;
end
if (hc < HACTIVEREGION)
lpen <= lpen + 1;
else
lpen <= 8'h00;
end
end
//////////////////////////////////////////////////////////////////////////
// Syncs and vertical retrace/raster line int generation
reg vint_n;
@ -189,18 +217,29 @@ module asic (
csync = ~csync;
if ( (vc == BEGINVINTV && hc >= BEGINVINTH) ||
(vc == ENDVINTV && hc < ENDVINTH) )
vint_n = 1'b0;
// if (vc == BEGINVINTV && hc >= BEGINVINTH)
vint_n = 1'b0;
if (lineint >= 8'd0 && lineint <= 8'd191) begin
// if (lineint == 8'd0) begin
// if (vc == VTOTAL-1 && hc >= BEGINHINTH ||
// vc == 9'd0 && hc < ENDHINTH)
// rint_n = 1'b0;
// end
// else begin
// if ({1'b0, lineint} == vc-1 && hc >= BEGINHINTH ||
// {1'b0, lineint} == vc && hc < ENDHINTH)
// rint_n = 1'b0;
// end
// end
if (lineint == 8'd0) begin
if (vc == VTOTAL-1 && hc >= BEGINHINTH ||
vc == 9'd0 && hc < ENDHINTH)
rint_n = 1'b0;
if (vc == VTOTAL-1 && hc >= BEGINHINTH)
rint_n = 1'b0;
end
else begin
if ({1'b0, lineint} == vc-1 && hc >= BEGINHINTH ||
{1'b0, lineint} == vc && hc < ENDHINTH)
rint_n = 1'b0;
if ({1'b0, lineint} == vc-1 && hc >= BEGINHINTH)
rint_n = 1'b0;
end
end
end
assign int_n = vint_n & rint_n;
@ -233,41 +272,47 @@ module asic (
//////////////////////////////////////////////////////////////////////////
// Contention signal (risk of)
reg contention;
reg mem_contention;
reg io_contention;
always @* begin
contention = 1'b0;
mem_contention = 1'b0;
if (hc[3:0]<4'd10)
io_contention = 1'b1;
else
io_contention = 1'b0;
if (fetching_pixels == 1'b1 && hc[3:0]<4'd10)
contention = 1'b1;
mem_contention = 1'b1;
else if (fetching_pixels == 1'b0 && (hc[3:0]==4'd0 ||
hc[3:0]==4'd1 ||
hc[3:0]==4'd8 ||
hc[3:0]==4'd9) )
contention = 1'b1;
mem_contention = 1'b1;
if (screen_mode == 2'b00 && hc[3:0]<4'd10 && hc[9:4]<6'd40)
contention = 1'b1;
mem_contention = 1'b1; // extra contention for MODE 1
end
assign asic_is_using_ram = contention & fetching_pixels;
assign asic_is_using_ram = mem_contention & fetching_pixels;
//////////////////////////////////////////////////////////////////////////
// WAIT signal with contention applied
always @* begin
wait_n = 1'b1;
if (cpuaddr<16'h4000 && rom_in_section_a==1'b1)
if (mreq_n == 1'b0 && cpuaddr<16'h4000 && rom_in_section_a==1'b1)
wait_n = 1'b1;
else if (cpuaddr>=16'hC000 && rom_in_section_d==1'b1)
else if (mreq_n == 1'b0 && cpuaddr>=16'hC000 && rom_in_section_d==1'b1)
wait_n = 1'b1;
else if (contention == 1'b1) begin
if (mreq_n == 1'b0)
wait_n = 1'b0;
else if (iorq_n == 1'b0)
if (rd_n == 1'b0 || wr_n == 1'b0)
wait_n = 1'b0;
end
else if (mem_contention == 1'b1 && mreq_n == 1'b0)
wait_n = 1'b0;
else if (io_contention == 1'b1 && iorq_n == 1'b0)
wait_n = 1'b0;
end
//////////////////////////////////////////////////////////////////////////
// VRAM address generation
reg [14:0] screen_offs = 15'h0000;
reg [4:0] screen_column = 5'h00;
always @* begin
if (screen_mode == 2'd0) begin
if (hc[2] == 1'b0)
@ -282,13 +327,11 @@ module asic (
vramaddr = {screen_page, 1'b1, screen_offs[12:0]};
end
else
vramaddr = {screen_page[4:0], 14'b00000000000000} + {3'b000, screen_offs};
vramaddr = {screen_page[4:1], screen_offs};
end
//////////////////////////////////////////////////////////////////////////
// FSM for fetching pixels from RAM and shift registers
reg [15:0] screen_offs = 16'h0000;
reg [4:0] screen_column = 5'h00;
reg [7:0] vram_byte1, vram_byte2, vram_byte3, vram_byte4;
reg [7:0] sregm12 = 8'h00;
reg [7:0] attrreg = 8'h00;
@ -300,7 +343,7 @@ module asic (
always @(posedge clk) begin
// a good time to reset pixel address counters and advance flash counter for modes 1 and 2
if (vc==(VTOTAL-1) && hc==(HTOTAL-1)) begin
screen_offs <= 16'h0000;
screen_offs <= 15'h0000;
screen_column <= 5'h00;
flash_counter <= flash_counter + 1;
end
@ -433,15 +476,14 @@ module asic (
// Write to IO ports from CPU
always @(posedge clk) begin
if (rst_n == 1'b0) begin
`ifdef SYNTH
`ifdef SYNTH
vmpr <= 8'h00;
`else
vmpr <= 8'b01100000;
`endif
lmpr <= 8'h00;
hmpr <= 8'h02;
hmpr <= 8'h00;
border <= 8'h00;
lineint <= 8'hFF;
end
else begin
if (iorq_n == 1'b0 && wr_n == 1'b0) begin
@ -481,6 +523,10 @@ module asic (
data_to_cpu = hmpr;
else if (cpuaddr[7:0] == IOADDR_LMPR)
data_to_cpu = lmpr;
else if (cpuaddr[8:0] == {1'b0, IOADDR_HLPEN} )
data_to_cpu = lpen;
else if (cpuaddr[8:0] == {1'b1, IOADDR_HLPEN} )
data_to_cpu = hpen;
else if (cpuaddr[7:0]>=8'd224 && cpuaddr[7:0]<=8'd231) begin
disc1_n = 1'b0;
data_enable_n = 1'b1;

View File

@ -0,0 +1,473 @@
#include <stdio.h>
#include <stdlib.h>
typedef unsigned char BYTE;
/*
12 12 3 3 2
AAAA DDDDDDDD AAAA DDDDDDDD MRN MMM XX
AAAA = semifila del teclado a modificar | esta información está
DDDDDDDD = dato (AND negado con lo que haya) de esa semifila | repetida para dos teclas
MRN = Master reset, Reset de usuario, NMI
MMM = la tecla es un modificador
XX = Reservado para uso futuro
Ej: en la dirección de memoria correspondiente al código de la tecla ESC,
que correspondería la tecla ESC del SAM, pondríamos:
1000 00100000 0000 00000000 000 000 00
En la dirección de memoria correspondiente al código de la tecla < que se
corresponde con la pulsación SYMBOL+Q pondríamos:
0111 00000010 0010 00000001 000 000 00
256 codigos + E0 = 512 codigos
SHIFT, CTRL, ALT = 8 combinaciones
512*8=4096 direcciones x 32 bits = 16384 bytes
En el core se dispondrá como una memoria de 16384x8 bits
Cada tecla ocupará cuatro direcciones consecutivas según el esquema anterior.
*/
// You shouldn't have to touch these defs unless your Spectrum has a different keyboard
// layout (because, for example, you are using a different ROM
// CCCC BBBBAAAA -- hex digits for coding
#define SAM_1 0x301 // 0011 00000001
#define SAM_2 0x302 // 0011 00000010
#define SAM_3 0x304 // 0011 00000100
#define SAM_4 0x308 // 0011 00001000
#define SAM_5 0x310 // 0011 00010000
#define SAM_ESC 0x320 // 0011 00100000
#define SAM_TAB 0x340 // 0011 01000000
#define SAM_CAPS 0x380 // 0011 10000000
#define SAM_0 0x401 // 0100 00000001
#define SAM_9 0x402 // 0100 00000010
#define SAM_8 0x404 // 0100 00000100
#define SAM_7 0x408 // 0100 00001000
#define SAM_6 0x410 // 0100 00010000
#define SAM_MINUS 0x420 // 0100 00100000
#define SAM_PLUS 0x440 // 0100 01000000
#define SAM_DELETE 0x480 // 0100 10000000
#define SAM_Q 0x201 // 0010 00000001
#define SAM_W 0x202 // 0010 00000010
#define SAM_E 0x204 // 0010 00000100
#define SAM_R 0x208 // 0010 00001000
#define SAM_T 0x210 // 0010 00010000
#define SAM_F7 0x220 // 0010 00100000
#define SAM_F8 0x240 // 0010 01000000
#define SAM_F9 0x280 // 0010 10000000
#define SAM_P 0x501 // 0101 00000001
#define SAM_O 0x502 // 0101 00000010
#define SAM_I 0x504 // 0101 00000100
#define SAM_U 0x508 // 0101 00001000
#define SAM_Y 0x510 // 0101 00010000
#define SAM_EQUAL 0x520 // 0101 00100000
#define SAM_QUOTE 0x540 // 0101 01000000
#define SAM_F0 0x580 // 0101 10000000
#define SAM_A 0x101 // 0001 00000001
#define SAM_S 0x102 // 0001 00000010
#define SAM_D 0x104 // 0001 00000100
#define SAM_F 0x108 // 0001 00001000
#define SAM_G 0x110 // 0001 00010000
#define SAM_F4 0x120 // 0001 00100000
#define SAM_F5 0x140 // 0001 01000000
#define SAM_F6 0x180 // 0001 10000000
#define SAM_RETURN 0x601 // 0110 00000001
#define SAM_L 0x602 // 0110 00000010
#define SAM_K 0x604 // 0110 00000100
#define SAM_J 0x608 // 0110 00001000
#define SAM_H 0x610 // 0110 00010000
#define SAM_SEMICOL 0x620 //0110 00100000
#define SAM_COLON 0x640 // 0110 01000000
#define SAM_EDIT 0x680 // 0110 10000000
#define SAM_SHIFT 0x001 // 0000 00000001
#define SAM_Z 0x002 // 0000 00000010
#define SAM_X 0x004 // 0000 00000100
#define SAM_C 0x008 // 0000 00001000
#define SAM_V 0x010 // 0000 00010000
#define SAM_F1 0x020 // 0000 00100000
#define SAM_F2 0x040 // 0000 01000000
#define SAM_F3 0x080 // 0000 10000000
#define SAM_SPACE 0x701 // 0111 00000001
#define SAM_SYMBOL 0x702 // 0111 00000010
#define SAM_M 0x704 // 0111 00000100
#define SAM_N 0x708 // 0111 00001000
#define SAM_B 0x710 // 0111 00010000
#define SAM_COMMA 0x720 // 0111 00100000
#define SAM_DOT 0x740 // 0111 01000000
#define SAM_INV 0x780 // 0111 10000000
#define SAM_CTRL 0x801 // 1000 00000001
#define SAM_UP 0x802 // 1000 00000010
#define SAM_DOWN 0x804 // 1000 00000100
#define SAM_LEFT 0x808 // 1000 00001000
#define SAM_RIGHT 0x810 // 1000 00010000
#define SAM_BANG ((SAM_SHIFT<<12) | SAM_1)
#define SAM_AT ((SAM_SHIFT<<12) | SAM_2)
#define SAM_HASH ((SAM_SHIFT<<12) | SAM_3)
#define SAM_DOLLAR ((SAM_SHIFT<<12) | SAM_4)
#define SAM_PERCEN ((SAM_SHIFT<<12) | SAM_5)
#define SAM_AMP ((SAM_SHIFT<<12) | SAM_6)
#define SAM_APOSTRO ((SAM_SHIFT<<12) | SAM_7)
#define SAM_PAROPEN ((SAM_SHIFT<<12) | SAM_8)
#define SAM_PARCLOS ((SAM_SHIFT<<12) | SAM_9)
#define SAM_TILDE ((SAM_SHIFT<<12) | SAM_0)
#define SAM_SLASH ((SAM_SHIFT<<12) | SAM_MINUS)
#define SAM_STAR ((SAM_SHIFT<<12) | SAM_PLUS)
#define SAM_LESS ((SAM_SYMBOL<<12) | SAM_Q)
#define SAM_GREATER ((SAM_SYMBOL<<12) | SAM_W)
#define SAM_BRAOPEN ((SAM_SYMBOL<<12) | SAM_R)
#define SAM_BRACLOS ((SAM_SYMBOL<<12) | SAM_T)
#define SAM_UNDERSC ((SAM_SHIFT<<12) | SAM_EQUAL)
#define SAM_COPY ((SAM_SHIFT<<12) | SAM_QUOTE)
#define SAM_PIPE ((SAM_SYMBOL<<12) | SAM_9)
#define SAM_BACKSLA ((SAM_SYMBOL<<12) | SAM_INV)
#define SAM_CUROPEN ((SAM_SYMBOL<<12) | SAM_F)
#define SAM_CURCLOS ((SAM_SYMBOL<<12) | SAM_G)
#define SAM_CARET ((SAM_SYMBOL<<12) | SAM_H)
#define SAM_POUND ((SAM_SYMBOL<<12) | SAM_L)
#define SAM_QUEST ((SAM_SYMBOL<<12) | SAM_X)
// END of SAM Coupé key definitions
// Definitions for additional signals generated by the keyboard core
// AAAADDDDDDDD AAAADDDDDDDD MRN MMM XX
#define MODIFIER1 0x04
#define MODIFIER2 0x08
#define MODIFIER3 0x10
#define MRESET 0x80
#define URESET 0x40
#define NMI 0x20
#define USER2 0x02
#define USER1 0x01
// End of additional signals
// A key can be pressed with up to three key modifiers
// which generates 8 combinations for each key
#define EXT 0x100
#define MD1 0x200
#define MD2 0x400
#define MD3 0x800
// Scan code 2 list. First, non localized keys
#define PC_A 0x1C
#define PC_B 0x32
#define PC_C 0x21
#define PC_D 0x23
#define PC_E 0x24
#define PC_F 0x2B
#define PC_G 0x34
#define PC_H 0x33
#define PC_I 0x43
#define PC_J 0x3B
#define PC_K 0x42
#define PC_L 0x4B
#define PC_M 0x3A
#define PC_N 0x31
#define PC_O 0x44
#define PC_P 0x4D
#define PC_Q 0x15
#define PC_R 0x2D
#define PC_S 0x1B
#define PC_T 0x2C
#define PC_U 0x3C
#define PC_V 0x2A
#define PC_W 0x1D
#define PC_X 0x22
#define PC_Y 0x35
#define PC_Z 0x1A
#define PC_0 0x45
#define PC_1 0x16
#define PC_2 0x1E
#define PC_3 0x26
#define PC_4 0x25
#define PC_5 0x2E
#define PC_6 0x36
#define PC_7 0x3D
#define PC_8 0x3E
#define PC_9 0x46
#define PC_F1 0x05
#define PC_F2 0x06
#define PC_F3 0x04
#define PC_F4 0x0C
#define PC_F5 0x03
#define PC_F6 0x0B
#define PC_F7 0x83
#define PC_F8 0x0A
#define PC_F9 0x01
#define PC_F10 0x09
#define PC_F11 0x78
#define PC_F12 0x07
#define PC_ESC 0x76
#define PC_SPACE 0x29
#define PC_LCTRL 0x14
#define PC_RCTRL 0x14 | EXT
#define PC_LSHIFT 0x12
#define PC_RSHIFT 0x59
#define PC_LALT 0x11
#define PC_RALT 0x11 | EXT
#define PC_LWIN 0x1F | EXT
#define PC_RWIN 0x27 | EXT
#define PC_APPS 0x2F | EXT
#define PC_TAB 0x0D
#define PC_CPSLOCK 0x58
#define PC_SCRLOCK 0x7E
#define PC_INSERT 0x70 | EXT
#define PC_DELETE 0x71 | EXT
#define PC_HOME 0x6C | EXT
#define PC_END 0x69 | EXT
#define PC_PGUP 0x7D | EXT
#define PC_PGDOWN 0x7A | EXT
#define PC_BKSPACE 0x66
#define PC_ENTER 0x5A
#define PC_UP 0x75 | EXT
#define PC_DOWN 0x72 | EXT
#define PC_LEFT 0x6B | EXT
#define PC_RIGHT 0x74 | EXT
#define PC_NUMLOCK 0x77
#define PC_KP_DIVIS 0x4A | EXT
#define PC_KP_MULT 0x7C
#define PC_KP_MINUS 0x7B
#define PC_KP_PLUS 0x79
#define PC_KP_ENTER 0x5A | EXT
#define PC_KP_DOT 0x71
#define PC_KP_0 0x70
#define PC_KP_1 0x69
#define PC_KP_2 0x72
#define PC_KP_3 0x7A
#define PC_KP_4 0x6B
#define PC_KP_5 0x73
#define PC_KP_6 0x74
#define PC_KP_7 0x6C
#define PC_KP_8 0x75
#define PC_KP_9 0x7D
// Localized keyboards start to differenciate from here
// Localized keyboard ES (Spain)
#define PC_BACKSLA 0x0E
#define PC_APOSTRO 0x4E
#define PC_OPNBANG 0x55
#define PC_GRAVEAC 0x54
#define PC_PLUS 0x5B
#define PC_EGNE 0x4C
#define PC_ACUTEAC 0x52
#define PC_CEDILLA 0x5D
#define PC_LESS 0x61
#define PC_COMMA 0x41
#define PC_DOT 0x49
#define PC_MINUS 0x4A
#define MAP(pc,sam,rmu) { \
rom[(pc)*4] = (((sam)>>16)&0xFF); \
rom[(pc)*4+1] = (((sam)>>8)&0xFF); \
rom[(pc)*4+2] = (((sam))&0xFF); \
rom[(pc)*4+3] = (rmu); \
}
#define MAPANY(pc,sam,rmu) { \
MAP(pc,sam,rmu); \
MAP(MD1|pc,sam,rmu); \
MAP(MD2|pc,sam,rmu); \
MAP(MD3|pc,sam,rmu); \
MAP(MD1|MD2|pc,sam,rmu); \
MAP(MD1|MD3|pc,sam,rmu); \
MAP(MD2|MD3|pc,sam,rmu); \
MAP(MD1|MD2|MD3|pc,sam,rmu); \
}
#define CLEANMAP { \
int i; \
for (i=0;i<(sizeof(rom)/sizeof(rom[0]));i++) \
rom[i] = 0; \
}
#define SAVEMAPHEX(name) { \
FILE *f; \
int i; \
f=fopen(name,"w"); \
for(i=0;i<(sizeof(rom)/sizeof(rom[0]));i++) \
fprintf(f,"%.2X\n",rom[i]); \
fclose(f); \
}
#define SAVEMAPBIN(name) { \
FILE *f; \
int i; \
f=fopen(name,"wb"); \
fwrite (rom, 1, sizeof(rom), f); \
fclose(f); \
}
int main()
{
BYTE rom[16384];
CLEANMAP;
MAPANY(PC_LSHIFT,0,MODIFIER1); // MD1 is SHIFT
MAPANY(PC_RSHIFT,0,MODIFIER1); // MD1 is SHIFT
MAPANY(PC_LCTRL,SAM_CTRL,MODIFIER2); // MD2 is CTRL
MAPANY(PC_RCTRL,SAM_CTRL,MODIFIER2); // MD2 is CTRL
MAPANY(PC_LALT,SAM_SHIFT,MODIFIER3); // MD3 is ALT.
MAPANY(PC_RALT,SAM_SYMBOL,MODIFIER3); // MD3 is ALT.
MAPANY(PC_RWIN,SAM_EDIT,0); // EDIT key
// Basic mapping: each key from PC is mapped to a key in the SAM
MAP(PC_1,SAM_1,0);
MAP(PC_2,SAM_2,0);
MAP(PC_3,SAM_3,0);
MAP(PC_4,SAM_4,0);
MAP(PC_5,SAM_5,0);
MAP(PC_6,SAM_6,0);
MAP(PC_7,SAM_7,0);
MAP(PC_8,SAM_8,0);
MAP(PC_9,SAM_9,0);
MAP(PC_0,SAM_0,0);
MAP(PC_Q,SAM_Q,0);
MAP(PC_W,SAM_W,0);
MAP(PC_E,SAM_E,0);
MAP(PC_R,SAM_R,0);
MAP(PC_T,SAM_T,0);
MAP(PC_Y,SAM_Y,0);
MAP(PC_U,SAM_U,0);
MAP(PC_I,SAM_I,0);
MAP(PC_O,SAM_O,0);
MAP(PC_P,SAM_P,0);
MAP(PC_A,SAM_A,0);
MAP(PC_S,SAM_S,0);
MAP(PC_D,SAM_D,0);
MAP(PC_F,SAM_F,0);
MAP(PC_G,SAM_G,0);
MAP(PC_H,SAM_H,0);
MAP(PC_J,SAM_J,0);
MAP(PC_K,SAM_K,0);
MAP(PC_L,SAM_L,0);
MAP(PC_Z,SAM_Z,0);
MAP(PC_X,SAM_X,0);
MAP(PC_C,SAM_C,0);
MAP(PC_V,SAM_V,0);
MAP(PC_B,SAM_B,0);
MAP(PC_N,SAM_N,0);
MAP(PC_M,SAM_M,0);
MAP(MD1|PC_Q,SAM_SHIFT<<12|SAM_Q,0);
MAP(MD1|PC_W,SAM_SHIFT<<12|SAM_W,0);
MAP(MD1|PC_E,SAM_SHIFT<<12|SAM_E,0);
MAP(MD1|PC_R,SAM_SHIFT<<12|SAM_R,0);
MAP(MD1|PC_T,SAM_SHIFT<<12|SAM_T,0);
MAP(MD1|PC_Y,SAM_SHIFT<<12|SAM_Y,0);
MAP(MD1|PC_U,SAM_SHIFT<<12|SAM_U,0);
MAP(MD1|PC_I,SAM_SHIFT<<12|SAM_I,0);
MAP(MD1|PC_O,SAM_SHIFT<<12|SAM_O,0);
MAP(MD1|PC_P,SAM_SHIFT<<12|SAM_P,0);
MAP(MD1|PC_A,SAM_SHIFT<<12|SAM_A,0);
MAP(MD1|PC_S,SAM_SHIFT<<12|SAM_S,0);
MAP(MD1|PC_D,SAM_SHIFT<<12|SAM_D,0);
MAP(MD1|PC_F,SAM_SHIFT<<12|SAM_F,0);
MAP(MD1|PC_G,SAM_SHIFT<<12|SAM_G,0);
MAP(MD1|PC_H,SAM_SHIFT<<12|SAM_H,0);
MAP(MD1|PC_J,SAM_SHIFT<<12|SAM_J,0);
MAP(MD1|PC_K,SAM_SHIFT<<12|SAM_K,0);
MAP(MD1|PC_L,SAM_SHIFT<<12|SAM_L,0);
MAP(MD1|PC_Z,SAM_SHIFT<<12|SAM_Z,0);
MAP(MD1|PC_X,SAM_SHIFT<<12|SAM_X,0);
MAP(MD1|PC_C,SAM_SHIFT<<12|SAM_C,0);
MAP(MD1|PC_V,SAM_SHIFT<<12|SAM_V,0);
MAP(MD1|PC_B,SAM_SHIFT<<12|SAM_B,0);
MAP(MD1|PC_N,SAM_SHIFT<<12|SAM_N,0);
MAP(MD1|PC_M,SAM_SHIFT<<12|SAM_M,0);
MAPANY(PC_SPACE,SAM_SPACE,0);
MAPANY(PC_ENTER,SAM_RETURN,0);
//Complex mapping. This is for the spanish keyboard although many
//combos can be used with any other PC keyboard
MAPANY(PC_ESC,SAM_ESC,0);
MAPANY(PC_CPSLOCK,SAM_CAPS,0);
MAPANY(PC_TAB,SAM_TAB,0);
MAP(PC_BKSPACE,SAM_DELETE,0);
MAPANY(PC_UP,SAM_UP,0);
MAPANY(PC_DOWN,SAM_DOWN,0);
MAPANY(PC_LEFT,SAM_LEFT,0);
MAPANY(PC_RIGHT,SAM_RIGHT,0);
MAP(PC_F5|MD2|MD3,0,NMI); // Ctrl-Alt-F5 for NMI
MAP(PC_DELETE|MD2|MD3,0,URESET); //
MAP(PC_KP_DOT|MD2|MD3,0,URESET); // Ctrl-Alt-Del for user reset
MAP(PC_BKSPACE|MD2|MD3,0,MRESET); // Ctrl-Alt-BkSpace for master reset
//keypad
MAPANY(PC_KP_DIVIS,SAM_SLASH,0);
MAPANY(PC_KP_MULT,SAM_STAR,0);
MAPANY(PC_KP_MINUS,SAM_MINUS,0);
MAPANY(PC_KP_PLUS,SAM_PLUS,0);
MAPANY(PC_KP_ENTER,SAM_RETURN,0);
MAPANY(PC_KP_0,SAM_F0,0);
MAPANY(PC_KP_1,SAM_F1,0);
MAPANY(PC_KP_2,SAM_F2,0);
MAPANY(PC_KP_3,SAM_F3,0);
MAPANY(PC_KP_4,SAM_F4,0);
MAPANY(PC_KP_5,SAM_F5,0);
MAPANY(PC_KP_6,SAM_F6,0);
MAPANY(PC_KP_7,SAM_F7,0);
MAPANY(PC_KP_8,SAM_F8,0);
MAPANY(PC_KP_9,SAM_F9,0);
//Some shift+key mappings for the ES keyboard
MAP(MD1|PC_1,SAM_BANG,0);
MAP(MD1|PC_2,SAM_QUOTE,0);
MAP(MD1|PC_3,SAM_HASH,0);
MAP(MD1|PC_4,SAM_DOLLAR,0);
MAP(MD1|PC_5,SAM_PERCEN,0);
MAP(MD1|PC_6,SAM_AMP,0);
MAP(MD1|PC_7,SAM_SLASH,0);
MAP(MD1|PC_8,SAM_PAROPEN,0);
MAP(MD1|PC_9,SAM_PARCLOS,0);
MAP(MD1|PC_0,SAM_EQUAL,0);
MAP(PC_APOSTRO,SAM_APOSTRO,0);
MAP(MD1|PC_APOSTRO,SAM_QUEST,0);
MAP(PC_GRAVEAC,SAM_POUND,0);
MAP(MD1|PC_GRAVEAC,SAM_CARET,0);
MAP(PC_PLUS,SAM_PLUS,0);
MAP(MD1|PC_PLUS,SAM_STAR,0);
MAP(PC_ACUTEAC,SAM_CUROPEN,0);
MAP(MD1|PC_ACUTEAC,SAM_CUROPEN,0);
MAP(PC_ACUTEAC,SAM_CUROPEN,0);
MAP(MD1|PC_ACUTEAC,SAM_CUROPEN,0);
MAP(PC_CEDILLA,SAM_CURCLOS,0);
MAP(MD1|PC_CEDILLA,SAM_COPY,0);
MAP(PC_COMMA,SAM_COMMA,0);
MAP(MD1|PC_COMMA,SAM_SEMICOL,0);
MAP(PC_DOT,SAM_DOT,0);
MAP(MD1|PC_DOT,SAM_COLON,0);
MAP(PC_MINUS,SAM_MINUS,0);
MAP(MD1|PC_MINUS,SAM_UNDERSC,0);
MAP(PC_BACKSLA,SAM_BACKSLA,0);
MAP(MD1|PC_BACKSLA,SAM_BACKSLA,0);
MAP(PC_EGNE,SAM_TILDE,0);
MAP(PC_LESS,SAM_LESS,0);
MAP(MD1|PC_LESS,SAM_GREATER,0);
// End of mapping. Save .HEX file for Verilog
SAVEMAPHEX("keyb_es_hex.txt");
}

16384
cores/SamCoupe/keyb_es_hex.txt Normal file

File diff suppressed because it is too large Load Diff

126
cores/SamCoupe/ps2_keyb.v Normal file
View File

@ -0,0 +1,126 @@
`timescale 1ns / 1ps
`default_nettype none
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 15:18:53 06/03/2015
// Design Name:
// Module Name: ps2_keyb
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module ps2_keyb(
input wire clk,
inout wire clkps2,
inout wire dataps2,
//---------------------------------
input wire [8:0] rows,
output wire [7:0] cols,
output wire rst_out_n,
output wire nmi_out_n,
output wire mrst_out_n,
output wire [1:0] user_toggles,
//---------------------------------
input wire [7:0] zxuno_addr,
input wire zxuno_regrd,
input wire zxuno_regwr,
input wire regaddr_changed,
input wire [7:0] din,
output wire [7:0] keymap_dout,
output wire oe_n_keymap,
output wire [7:0] scancode_dout,
output wire oe_n_scancode,
output reg [7:0] kbstatus_dout,
output wire oe_n_kbstatus
);
parameter SCANCODE = 8'h04;
parameter KBSTATUS = 8'h05;
parameter KEYMAP = 8'h07;
wire master_reset, user_reset, user_nmi;
assign mrst_out_n = ~master_reset;
assign rst_out_n = ~user_reset;
assign nmi_out_n = ~user_nmi;
assign oe_n_keymap = ~(zxuno_addr == KEYMAP && zxuno_regrd == 1'b1);
assign oe_n_scancode = ~(zxuno_addr == SCANCODE && zxuno_regrd == 1'b1);
assign oe_n_kbstatus = ~(zxuno_addr == KBSTATUS && zxuno_regrd == 1'b1);
wire [7:0] kbcode;
wire ps2busy;
wire kberror;
wire nueva_tecla;
wire extended;
wire released;
assign scancode_dout = kbcode;
/*
| BSY | x | x | x | ERR | RLS | EXT | PEN |
*/
reg reading_kbstatus = 1'b0;
always @(posedge clk) begin
kbstatus_dout[7:1] <= {ps2busy, 3'b000, kberror, released, extended};
if (nueva_tecla == 1'b1)
kbstatus_dout[0] <= 1'b1;
if (oe_n_kbstatus == 1'b0)
reading_kbstatus <= 1'b1;
else if (reading_kbstatus == 1'b1) begin
kbstatus_dout[0] <= 1'b0;
reading_kbstatus <= 1'b0;
end
end
ps2_port lectura_de_teclado (
.clk(clk),
.enable_rcv(~ps2busy),
.kb_or_mouse(1'b0),
.ps2clk_ext(clkps2),
.ps2data_ext(dataps2),
.kb_interrupt(nueva_tecla),
.scancode(kbcode),
.released(released),
.extended(extended)
);
scancode_to_sam traductor (
.clk(clk),
.rst(1'b0),
.scan_received(nueva_tecla),
.scan(kbcode),
.extended(extended),
.released(released),
.sam_row(rows),
.sam_col(cols),
.master_reset(master_reset),
.user_reset(user_reset),
.user_nmi(user_nmi),
.user_toggles(user_toggles),
.din(din),
.dout(keymap_dout),
.cpuwrite(zxuno_addr == KEYMAP && zxuno_regwr == 1'b1),
.cpuread(zxuno_addr == KEYMAP && zxuno_regrd == 1'b1),
.rewind(regaddr_changed == 1'b1 && zxuno_addr == KEYMAP)
);
ps2_host_to_kb escritura_a_teclado (
.clk(clk),
.ps2clk_ext(clkps2),
.ps2data_ext(dataps2),
.data(din),
.dataload(zxuno_addr == SCANCODE && zxuno_regwr== 1'b1),
.ps2busy(ps2busy),
.ps2error(kberror)
);
endmodule

275
cores/SamCoupe/ps2_port.v Normal file
View File

@ -0,0 +1,275 @@
`timescale 1ns / 1ps
`default_nettype none
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 20:16:31 12/26/2014
// Design Name:
// Module Name: ps2_port
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module ps2_port (
input wire clk, // se recomienda 1 MHz <= clk <= 600 MHz
input wire enable_rcv, // habilitar la maquina de estados de recepcion
input wire kb_or_mouse, // 0: kb, 1: mouse
input wire ps2clk_ext,
input wire ps2data_ext,
output wire kb_interrupt, // a 1 durante 1 clk para indicar nueva tecla recibida
output reg [7:0] scancode, // make o breakcode de la tecla
output wire released, // soltada=1, pulsada=0
output wire extended // extendida=1, no extendida=0
);
`define RCVSTART 2'b00
`define RCVDATA 2'b01
`define RCVPARITY 2'b10
`define RCVSTOP 2'b11
reg [7:0] key = 8'h00;
// Fase de sincronizacion de señales externas con el reloj del sistema
reg [1:0] ps2clk_synchr;
reg [1:0] ps2dat_synchr;
wire ps2clk = ps2clk_synchr[1];
wire ps2data = ps2dat_synchr[1];
always @(posedge clk) begin
ps2clk_synchr[0] <= ps2clk_ext;
ps2clk_synchr[1] <= ps2clk_synchr[0];
ps2dat_synchr[0] <= ps2data_ext;
ps2dat_synchr[1] <= ps2dat_synchr[0];
end
// De-glitcher. Sólo detecto flanco de bajada
reg [15:0] negedgedetect = 16'h0000;
always @(posedge clk) begin
negedgedetect <= {negedgedetect[14:0], ps2clk};
end
wire ps2clkedge = (negedgedetect == 16'hF000)? 1'b1 : 1'b0;
// Paridad instantánea de los bits recibidos
wire paritycalculated = ^key;
// Contador de time-out. Al llegar a 65536 ciclos sin que ocurra
// un flanco de bajada en PS2CLK, volvemos al estado inicial
reg [15:0] timeoutcnt = 16'h0000;
reg [1:0] state = `RCVSTART;
reg [1:0] regextended = 2'b00;
reg [1:0] regreleased = 2'b00;
reg rkb_interrupt = 1'b0;
assign released = regreleased[1];
assign extended = regextended[1];
assign kb_interrupt = rkb_interrupt;
always @(posedge clk) begin
if (rkb_interrupt == 1'b1) begin
rkb_interrupt <= 1'b0;
end
if (ps2clkedge && enable_rcv) begin
timeoutcnt <= 16'h0000;
case (state)
`RCVSTART: begin
if (ps2data == 1'b0) begin
state <= `RCVDATA;
key <= 8'h80;
end
end
`RCVDATA: begin
key <= {ps2data, key[7:1]};
if (key[0] == 1'b1) begin
state <= `RCVPARITY;
end
end
`RCVPARITY: begin
if (ps2data^paritycalculated == 1'b1) begin
state <= `RCVSTOP;
end
else begin
state <= `RCVSTART;
end
end
`RCVSTOP: begin
state <= `RCVSTART;
if (ps2data == 1'b1) begin
scancode <= key;
if (kb_or_mouse == 1'b1) begin
rkb_interrupt <= 1'b1; // no se requiere mirar E0 o F0
end
else begin
if (key == 8'hE0) begin
regextended <= 2'b01;
end
else if (key == 8'hF0) begin
regreleased <= 2'b01;
end
else begin
regextended <= {regextended[0], 1'b0};
regreleased <= {regreleased[0], 1'b0};
rkb_interrupt <= 1'b1;
end
end
end
end
default: state <= `RCVSTART;
endcase
end
else begin
timeoutcnt <= timeoutcnt + 1;
if (timeoutcnt == 16'hFFFF) begin
state <= `RCVSTART;
end
end
end
endmodule
module ps2_host_to_kb (
input wire clk, // se recomienda 1 MHz <= clk <= 600 MHz
inout wire ps2clk_ext,
inout wire ps2data_ext,
input wire [7:0] data,
input wire dataload,
output wire ps2busy,
output wire ps2error
);
`define PULLCLKLOW 3'b000
`define PULLDATALOW 3'b001
`define SENDDATA 3'b010
`define SENDPARITY 3'b011
`define RCVACK 3'b100
`define RCVIDLE 3'b101
`define SENDFINISHED 3'b110
reg busy = 1'b0;
reg error = 1'b0;
assign ps2busy = busy;
assign ps2error = error;
// Fase de sincronizacion de señales externas con el reloj del sistema
reg [1:0] ps2clk_synchr;
reg [1:0] ps2dat_synchr;
wire ps2clk = ps2clk_synchr[1];
wire ps2data_in = ps2dat_synchr[1];
always @(posedge clk) begin
ps2clk_synchr[0] <= ps2clk_ext;
ps2clk_synchr[1] <= ps2clk_synchr[0];
ps2dat_synchr[0] <= ps2data_ext;
ps2dat_synchr[1] <= ps2dat_synchr[0];
end
// De-glitcher. Sólo detecto flanco de bajada
reg [15:0] edgedetect = 16'h0000;
always @(posedge clk) begin
edgedetect <= {edgedetect[14:0], ps2clk};
end
wire ps2clknedge = (edgedetect == 16'hF000)? 1'b1 : 1'b0;
wire ps2clkpedge = (edgedetect == 16'h0FFF)? 1'b1 : 1'b0;
// Contador de time-out. Al llegar a 65536 ciclos sin que ocurra
// un flanco de bajada en PS2CLK, volvemos al estado inicial
reg [15:0] timeoutcnt = 16'h0000;
reg [2:0] state = `SENDFINISHED;
reg [7:0] shiftreg = 8'h00;
reg [2:0] cntbits = 3'd0;
// Dato a enviar se guarda en rdata
reg [7:0] rdata = 8'h00;
// Paridad instantánea de los bits a enviar
wire paritycalculated = ~(^rdata);
always @(posedge clk) begin
// Carga de rdata desde el exterior
if (dataload) begin
rdata <= data;
busy <= 1'b1;
error <= 1'b0;
timeoutcnt <= 16'h0000;
state <= `PULLCLKLOW;
end
if (!ps2clknedge) begin
timeoutcnt <= timeoutcnt + 1;
if (timeoutcnt == 16'hFFFF && state != `SENDFINISHED) begin
error <= 1'b1;
state <= `SENDFINISHED;
end
end
case (state)
`PULLCLKLOW: begin // 40000 cuentas es poco más de 10ms
if (timeoutcnt >= 16'd40000) begin
state <= `PULLDATALOW;
shiftreg <= rdata;
cntbits <= 3'd0;
timeoutcnt <= 16'h0000;
end
end
`PULLDATALOW: begin
if (ps2clknedge) begin
state <= `SENDDATA;
timeoutcnt <= 16'h0000;
end
end
`SENDDATA: begin
if (ps2clknedge) begin
timeoutcnt <= 16'h0000;
shiftreg <= {1'b0, shiftreg[7:1]};
cntbits <= cntbits + 1;
if (cntbits == 3'd7)
state <= `SENDPARITY;
end
end
`SENDPARITY: begin
if (ps2clknedge) begin
state <= `RCVIDLE;
timeoutcnt <= 16'h0000;
end
end
`RCVIDLE: begin
if (ps2clknedge) begin
state <= `RCVACK;
timeoutcnt <= 16'h0000;
end
end
`RCVACK: begin
if (ps2clknedge) begin
state <= `SENDFINISHED;
timeoutcnt <= 16'h0000;
end
end
`SENDFINISHED: begin
busy <= 1'b0;
timeoutcnt <= 16'h0000;
end
default: begin
timeoutcnt <= timeoutcnt + 1;
if (timeoutcnt == 16'hFFFF && state != `SENDFINISHED) begin
error <= 1'b1;
state <= `SENDFINISHED;
end
end
endcase
end
assign ps2data_ext = (state == `PULLCLKLOW || state == `PULLDATALOW) ? 1'b0 :
(state == `SENDDATA && shiftreg[0] == 1'b0) ? 1'b0 :
(state == `SENDPARITY && paritycalculated == 1'b0) ? 1'b0 : // si lo que se va a enviar es un 1
1'bZ; // no se manda, sino que se pone la línea a alta impedancia
assign ps2clk_ext = (state == `PULLCLKLOW) ? 1'b0 :
1'bZ;
endmodule

View File

@ -140,9 +140,9 @@ module ram_dual_port (
sram_we_n = 1'b1;
end
else begin
sram_a = cpuramaddr;
sram_a = cpuramaddr;
data_to_cpu = sram_d;
if (state == CPU5 || state == CPU6)
if (state == CPU6 || state == CPU5)
sram_we_n = 1'b0;
else
sram_we_n = 1'b1;

View File

@ -36,8 +36,8 @@ module samcoupe (
output wire audio_out_left,
output wire audio_out_right,
// PS/2 keyoard interface
input wire clkps2,
input wire dataps2,
inout wire clkps2,
inout wire dataps2,
// SRAM interface
output wire [18:0] sram_addr,
inout wire [7:0] sram_data,
@ -82,7 +82,7 @@ module samcoupe (
// Audio signals
wire mic, beep;
assign audio_out_left = mic;
assign audio_out_left = ear;
assign audio_out_right = beep;
// MUX from memory/devices to Z80 data bus
@ -138,7 +138,7 @@ module samcoupe (
.mic(mic),
.beep(beep),
// keyboard I/O
.keyboard({3'b111,kbcolumns[4:0]}),
.keyboard(kbcolumns),
.rdmsel(rdmsel),
// disk I/O
.disc1_n(),
@ -191,17 +191,41 @@ module samcoupe (
.sram_d(sram_data)
);
ps2k el_teclado (
.clk(clk6),
.ps2clk(clkps2),
.ps2data(dataps2),
.rows(kbrows[7:0]),
.cols(kbcolumns[4:0]),
.joy(), // Implementación joystick kempston en teclado numerico
.scancode(), // El scancode original desde el teclado
.rst(kb_rst_n), // esto son salidas, no entradas
.nmi(kb_nmi_n), // Señales de reset y NMI
.mrst() // generadas por pulsaciones especiales del teclado
);
// ps2k el_teclado (
// .clk(clk6),
// .ps2clk(clkps2),
// .ps2data(dataps2),
// .rows(kbrows[7:0]),
// .cols(kbcolumns[4:0]),
// .joy(), // Implementación joystick kempston en teclado numerico
// .scancode(), // El scancode original desde el teclado
// .rst(kb_rst_n), // esto son salidas, no entradas
// .nmi(kb_nmi_n), // Señales de reset y NMI
// .mrst() // generadas por pulsaciones especiales del teclado
// );
ps2_keyb el_teclado (
.clk(clk6),
.clkps2(clkps2),
.dataps2(dataps2),
//---------------------------------
.rows(kbrows),
.cols(kbcolumns),
.rst_out_n(kb_rst_n),
.nmi_out_n(kb_nmi_n),
.mrst_out_n(),
.user_toggles(),
//---------------------------------
.zxuno_addr(8'h00),
.zxuno_regrd(1'b0),
.zxuno_regwr(1'b0),
.regaddr_changed(1'b0),
.din(data_from_cpu),
.keymap_dout(),
.oe_n_keymap(),
.scancode_dout(),
.oe_n_scancode(),
.kbstatus_dout(),
.oe_n_kbstatus()
);
endmodule

View File

@ -43,14 +43,6 @@
<file xil_pn:name="pines_zxuno.ucf" xil_pn:type="FILE_UCF">
<association xil_pn:name="Implementation"/>
</file>
<file xil_pn:name="mapa_teclado_es.vhd" xil_pn:type="FILE_VHDL">
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="Implementation"/>
</file>
<file xil_pn:name="ps2k.vhd" xil_pn:type="FILE_VHDL">
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="Implementation"/>
</file>
<file xil_pn:name="relojes.v" xil_pn:type="FILE_VERILOG">
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="Implementation"/>
@ -81,6 +73,18 @@
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="Implementation"/>
</file>
<file xil_pn:name="ps2_keyb.v" xil_pn:type="FILE_VERILOG">
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="Implementation"/>
</file>
<file xil_pn:name="ps2_port.v" xil_pn:type="FILE_VERILOG">
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="Implementation"/>
</file>
<file xil_pn:name="scancode_to_speccy.v" xil_pn:type="FILE_VERILOG">
<association xil_pn:name="BehavioralSimulation"/>
<association xil_pn:name="Implementation"/>
</file>
</files>
<properties>
@ -107,7 +111,7 @@
<property xil_pn:name="Change Device Speed To" xil_pn:value="-2" xil_pn:valueState="default"/>
<property xil_pn:name="Change Device Speed To Post Trace" xil_pn:value="-2" xil_pn:valueState="default"/>
<property xil_pn:name="Combinatorial Logic Optimization" xil_pn:value="false" xil_pn:valueState="default"/>
<property xil_pn:name="Compile EDK Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Compile EDK Simulation Library" xil_pn:value="true" xil_pn:valueState="non-default"/>
<property xil_pn:name="Compile SIMPRIM (Timing) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Compile UNISIM (Functional) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
<property xil_pn:name="Compile XilinxCoreLib (CORE Generator) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>

View File

@ -0,0 +1,269 @@
`timescale 1ns / 1ps
`default_nettype none
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 17:42:40 06/01/2015
// Design Name:
// Module Name: scancode_to_speccy
// Project Name:
// Target Devices:
// Tool versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//////////////////////////////////////////////////////////////////////////////////
module scancode_to_sam (
input wire clk, // el mismo clk de ps/2
input wire rst,
input wire scan_received,
input wire [7:0] scan,
input wire extended,
input wire released,
//------------------------
input wire [8:0] sam_row,
output wire [7:0] sam_col,
output wire user_reset,
output wire master_reset,
output wire user_nmi,
output wire [1:0] user_toggles,
//------------------------
input wire [7:0] din,
output reg [7:0] dout,
input wire cpuwrite,
input wire cpuread,
input wire rewind
);
// las teclas del SAM. Se inicializan a "no pulsadas".
reg [7:0] row[0:8];
initial begin
row[0] = 8'hFF;
row[1] = 8'hFF;
row[2] = 8'hFF;
row[3] = 8'hFF;
row[4] = 8'hFF;
row[5] = 8'hFF;
row[6] = 8'hFF;
row[7] = 8'hFF;
row[8] = 8'hFF;
end
// El gran mapa de teclado y sus registros de acceso
reg [7:0] keymap[0:16383]; // 16K x 8 bits
reg [13:0] addr = 14'h0000;
reg [13:0] cpuaddr = 14'h0000; // Dirección E/S desde la CPU. Se autoincrementa en cada acceso
initial begin
$readmemh ("keyb_es_hex.txt", keymap);
end
reg [3:0] keyrow1 = 4'h0;
reg [7:0] keycol1 = 8'h00;
reg [3:0] keyrow2 = 4'h0;
reg [7:0] keycol2 = 8'h00;
reg [2:0] keymodifiers = 3'b000;
reg [2:0] signalstate = 3'b000;
reg [1:0] togglestate = 2'b00;
reg rmaster_reset = 1'b0, ruser_reset = 1'b0, ruser_nmi = 1'b0;
reg [1:0] ruser_toggles = 2'b00;
assign master_reset = rmaster_reset;
assign user_reset = ruser_reset;
assign user_nmi = ruser_nmi;
assign user_toggles = ruser_toggles;
// Asi funciona la matriz de teclado cuando se piden semifilas
// desde la CPU.
// Un always @* hubiera quedado más claro en la descripción
// pero por algun motivo, el XST no lo ha admitido en este caso
assign sam_col = ((sam_row[0] == 1'b0)? row[0] : 8'hFF) &
((sam_row[1] == 1'b0)? row[1] : 8'hFF) &
((sam_row[2] == 1'b0)? row[2] : 8'hFF) &
((sam_row[3] == 1'b0)? row[3] : 8'hFF) &
((sam_row[4] == 1'b0)? row[4] : 8'hFF) &
((sam_row[5] == 1'b0)? row[5] : 8'hFF) &
((sam_row[6] == 1'b0)? row[6] : 8'hFF) &
((sam_row[7] == 1'b0)? row[7] : 8'hFF) &
((sam_row[8] == 1'b0)? row[8] : 8'hFF);
reg [2:0] modifiers = 3'b000;
reg [3:0] keycount = 4'b0000;
parameter
CLEANMATRIX = 4'd0,
IDLE = 4'd1,
ADDR0PUT = 4'd2,
ADDR1PUT = 4'd3,
ADDR2PUT = 4'd4,
ADDR3PUT = 4'd5,
TRANSLATE1 = 4'd6,
TRANSLATE2 = 4'd7,
TRANSLATE3 = 4'd8,
CPUTIME = 4'd9,
CPUREAD = 4'd10,
CPUWRITE = 4'd11,
CPUINCADD = 4'd12,
UPDCOUNTERS1= 4'd13,
UPDCOUNTERS2= 4'd14;
reg [3:0] state = CLEANMATRIX;
reg key_is_pending = 1'b0;
always @(posedge clk) begin
if (scan_received == 1'b1)
key_is_pending <= 1'b1;
if (rst == 1'b1)
state <= CLEANMATRIX;
else begin
case (state)
CLEANMATRIX: begin
modifiers <= 3'b000;
keycount <= 4'b0000;
row[0] <= 8'hFF;
row[1] <= 8'hFF;
row[2] <= 8'hFF;
row[3] <= 8'hFF;
row[4] <= 8'hFF;
row[5] <= 8'hFF;
row[6] <= 8'hFF;
row[7] <= 8'hFF;
row[8] <= 8'hFF;
state <= IDLE;
end
IDLE: begin
if (key_is_pending == 1'b1) begin
addr <= {modifiers, extended, scan, 2'b00}; // 1 scan tiene 8 bits + 1 bit para indicar scan extendido + 3 bits para el modificador usado
state <= ADDR0PUT;
key_is_pending <= 1'b0;
end
else if (cpuread == 1'b1 || cpuwrite == 1'b1 || rewind == 1'b1)
state <= CPUTIME;
end
ADDR0PUT: begin
{keyrow1,keycol1[7:4]} <= keymap[addr];
addr <= {modifiers, extended, scan, 2'b01};
state <= ADDR1PUT;
end
ADDR1PUT: begin
{keycol1[3:0],keyrow2} <= keymap[addr];
addr <= {modifiers, extended, scan, 2'b10};
state <= ADDR2PUT;
end
ADDR2PUT: begin
{keycol2} <= keymap[addr];
addr <= {modifiers, extended, scan, 2'b11};
state <= ADDR3PUT;
end
ADDR3PUT: begin
{signalstate,keymodifiers,togglestate} <= keymap[addr];
state <= TRANSLATE1;
end
TRANSLATE1: begin
// Actualiza las 8 semifilas del teclado con la primera tecla
if (~released) begin
if (keyrow1[3] == 1'b1)
row[8] <= row[8] & ~keycol1;
else
row[keyrow1[2:0]] <= row[keyrow1[2:0]] & ~keycol1;
end
else begin
if (keyrow1[3] == 1'b1)
row[8] <= row[8] | keycol1;
else
row[keyrow1[2:0]] <= row[keyrow1[2:0]] | keycol1;
end
state <= TRANSLATE2;
end
TRANSLATE2: begin
// Actualiza las 8 semifilas del teclado con la segunda tecla
if (~released) begin
if (keyrow2[3] == 1'b1)
row[8] <= row[8] & ~keycol2;
else
row[keyrow2[2:0]] <= row[keyrow2[2:0]] & ~keycol2;
end
else begin
if (keyrow2[3] == 1'b1)
row[8] <= row[8] | keycol2;
else
row[keyrow2[2:0]] <= row[keyrow2[2:0]] | keycol2;
end
state <= TRANSLATE3;
end
TRANSLATE3: begin
// Actualiza modificadores
if (~released)
modifiers <= modifiers | keymodifiers;
else
modifiers <= modifiers & ~keymodifiers;
// Y de la misma forma tendria que actualizar resets y los user_toogles
if (~released)
{rmaster_reset,ruser_reset,ruser_nmi} <= {rmaster_reset,ruser_reset,ruser_nmi} | signalstate;
else
{rmaster_reset,ruser_reset,ruser_nmi} <= {rmaster_reset,ruser_reset,ruser_nmi} & ~signalstate;
if (~released)
ruser_toggles <= ruser_toggles | togglestate;
else
ruser_toggles <= ruser_toggles & ~togglestate;
//state <= UPDCOUNTERS1;
state <= IDLE;
end
CPUTIME: begin
if (rewind == 1'b1) begin
cpuaddr = 14'h0000;
state <= IDLE;
end
else if (cpuread == 1'b1) begin
addr <= cpuaddr;
state <= CPUREAD;
end
else if (cpuwrite == 1'b1) begin
addr <= cpuaddr;
state <= CPUWRITE;
end
else
state <= IDLE;
end
CPUREAD: begin // CPU wants to read from keymap
dout <= keymap[addr];
state <= CPUINCADD;
end
CPUWRITE: begin
keymap[addr] <= din;
state <= CPUINCADD;
end
CPUINCADD: begin
if (cpuread == 1'b0 && cpuwrite == 1'b0) begin
cpuaddr <= cpuaddr + 1;
state <= IDLE;
end
end
// else if (state == UPDCOUNTERS1) begin
// if (~released)
// keycount <= keycount + 4'b0001; // suma 1 al contador de pulsaciones
// else if (released && keycount != 4'b0000)
// keycount <= keycount + 4'b1111; // o le resta 1 al contador de pulsaciones, pero sin bajar de 0
// state <= UPDCOUNTERS2;
// end
// else if (state == UPDCOUNTERS2) begin
// if (keycount == 4'b0000) // si es la última tecla soltada, limpia la matriz de teclado del Spectrum
// state <= CLEANMATRIX;
// else
// state <= IDLE;
// end
default: begin
state <= IDLE;
end
endcase
end
end
endmodule

View File

@ -38,14 +38,10 @@ module tld_sam (
inout wire [7:0] sram_data,
output wire sram_we_n,
// PS/2 keyoard interface
input wire clkps2,
input wire dataps2
inout wire clkps2,
inout wire dataps2
);
// Interface with ROM
wire [14:0] romaddr;
wire [7:0] data_from_rom;
// Interface with RAM
wire [18:0] ramaddr;
wire [7:0] data_from_ram;

View File

@ -22,6 +22,8 @@
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
`define TV80_REFRESH
module tv80_core (/*AUTOARG*/
// Outputs
m1_n, iorq, no_read, write, rfsh_n, halt_n, busak_n, A, dout, mc,