Skip to content

Commit

Permalink
5th iteration of Z80 to Caravel mapping.
Browse files Browse the repository at this point in the history
  • Loading branch information
rejunity committed Jun 5, 2024
1 parent bcd2685 commit a31522c
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 98 deletions.
170 changes: 122 additions & 48 deletions src/ci2406_z80.v
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,13 @@ module ci2406_z80(
// Z80) starting roughly from a bottom left corner, pin 18 (/HALT).
// CI) starting from a bottom right corner, pin 31 (mprj_io[0]).
// Also:
// 1) need to use CI mprj_io[0..2] pins as output and preferrably for rarely used HALT, BUSAK, M1 signals
// 2) Z80 data bus pin order is "scrambled"
// 1) caravel mprj_io[0] is reset, mprj_io[3] can not be used, mprj_io[0..1] must be output
// 2) Z80 data bus order is "scrambled"

// CI Caravel mprj_io mapping to multiplxer's "design" ports io_in/out/oebp[]:
// assign io_out = {design_out[35:2], wb_counter[25], design_out[1:0], 1'b0};
// assign io_oeb = {design_oeb[35:2], 1'b0, design_oeb[1:0], 1'b1};


// Z80 CPU
// 1st attempt:
Expand Down Expand Up @@ -111,79 +116,148 @@ module ci2406_z80(
// <-- /MREQ |19 - io[34] 13 * 36 io[5] - 22| /WR -->
// <-- /IORQ |20 - io[35] 14 * 35 io[4] - 21| /RD -->
// `-------------------------------------'
//
// 4th revision:
// c[] - caravel mprj_io[] pin
// io[] - multiplexer's io_in/out/oebp[] port
// ,----------------.___.----------------.
// <-- A11 1 |io[17] c[19] 57 55 c[18] io[16]|40 A10 -->
// <-- A12 2 |io[18] c[20] 58 54 c[17] io[15]|39 A9 -->
// <-- A13 3 |io[29] c[21] 59 53 c[16] io[14]|38 A8 -->
// <-- A14 4 |io[20] c[22] 60 51 c[15] io[13]|37 A7 -->
// <-- A15 5 |io[21] c[23] 61 50 c[14] io[12]|36 A6 -->
// --> CLK 6 |------ ocs_o 22 48 c[13] io[11]|35 A5 -->
// <-> D4 7 |io[22] c[24] 62 42 c[ 8] io[ 6]|34 A4 -->
// <-> D3 8 |io[23] c[25] 2 43 c[ 9] io[ 7]|33 A3 -->
// <-> D5 9 |io[24] c[26] 3 44 c[10] io[ 8]|32 A2 -->
// <-> D6 10|io[25] c[27] 4 46 c[12] io[10]|31 A1 -->
// VCC_5V0 11| 45 c[11] io[ 9]|30 A0 -->
// <-> D2 12|io[26] c[28] 5 |29 GND
// <-> D7 13|io[27] c[29] 6 41 c[ 7] io[ 5]|28 /RFSH -->
// <-> D0 14|io[29] c[31] 8 33 c[ 2] io[*1]|27 /M1 -->
// <-> D1 15|io[28] c[30] 7 *- * 31 c[ 0] ------|26 /RESET <--
// --> /INT 16|io[31] c[33] 12 * 16 c[37] io[35]|25 /BUSRQ <--
// --> /NMI 17|io[30] c[32] 11 *- 37 c[ 6] io[ 4]|24 /WAIT <--
// <-- /HALT 18|io[34] c[36] 15 * 32 c[ 1] io[*0]|23 /BUSAK -->
// <-- /MREQ 19|io[32] c[34] 13 36 c[ 5] io[ 3]|22 /WR -->
// <-- /IORQ 20|io[33] c[35] 14 35 c[ 4] io[ 2]|21 /RD -->
// `-------------------------------------'
// /BUSAK, /M1 --- io[cl-1]
// * --- io[cl-2]

// output --- io[0..3, 5..21, 32..34]
// input --- io[4,30,31,35] (/WAIT, /NMI, /INT, /BUSRQ)
// bidir --- io[22,23,24,25,26,27,28,29]

// 5th revision:
// c[] - caravel mprj_io[] pin
// io[] - multiplexer's io_in/out/oebp[] port
// ,----------------.___.----------------.
// <-- A11 1 |io[17] c[19] 57 55 c[18] io[16]|40 A10 -->
// <-- A12 2 |io[18] c[20] 58 54 c[17] io[15]|39 A9 -->
// <-- A13 3 |io[29] c[21] 59 53 c[16] io[14]|38 A8 -->
// <-- A14 4 |io[20] c[22] 60 51 c[15] io[13]|37 A7 -->
// <-- A15 5 |io[21] c[23] 61 50 c[14] io[12]|36 A6 -->
// --> CLK 6 |------ ocs_o 22 48 c[13] io[11]|35 A5 -->
// <-> D4 7 |io[22] c[24] 62 42 c[ 8] io[ 6]|34 A4 -->
// <-> D3 8 |io[23] c[25] 2 43 c[ 9] io[ 7]|33 A3 -->
// <-> D5 9 |io[24] c[26] 3 44 c[10] io[ 8]|32 A2 -->
// <-> D6 10|io[25] c[27] 4 46 c[12] io[10]|31 A1 -->
// VCC_5V0 11| 45 c[11] io[ 9]|30 A0 -->
// <-> D2 12|io[26] c[28] 5 |29 GND
// <-> D7 13|io[27] c[29] 6 41 c[ 7] io[ 5]|28 /RFSH -->
// <-> D0 14|io[29] c[31] 8 33 c[ 2] io[*1]|27 /M1 -->
// <-> D1 15|io[28] c[30] 7 31 c[ 0] ------|26 /RESET <--
// --> /INT 16|io[31] c[33] 12 16 c[37] io[35]|25 /BUSRQ <--
// --> /NMI 17|io[30] c[32] 11 37 c[ 6] io[ 4]|24 /WAIT <--
// <-- /HALT 18|io[32] c[34] 13 * 32 c[ 1] io[*0]|23 /BUSAK -->
// <-- /MREQ 19|io[33] c[35] 14 * 36 c[ 5] io[ 3]|22 /WR -->
// <-- /IORQ 20|io[34] c[36] 15 * 35 c[ 4] io[ 2]|21 /RD -->
// `-------------------------------------'
// /BUSAK, /M1 --- io[cl-1]
// * --- io[cl-2]

// output --- io[0..3, 5, 32..34] (/BUSAK, /M1, /RD, /WR, /RFSH, /HALT, /MREQ, /IORQ)
// output A --- io[6..21]
// input --- io[4,30,31,35] (/WAIT, /NMI, /INT, /BUSRQ)
// bidir --- io[22,23,24,25,26,27,28,29]

// GND 29 --- vss* [56,52,38,39,29,23,20,10,1]
// (GND?) 29 --- vdda1, vdda2 [47,40,30,9]
// VCC_5V0 11 --- vddio [64,17]
// VCC_3V3 xx --- vdda1, vdda2 [47,40,30,9]
// VCC_1V8 xx --- vccd, vccd1, vccd2 [63,49,18]
// VCC_1V8_R xx --- io_3_csb [34]



// @TODO: float A, D on reset
// @TODO: float A, D, MREQ, RD, WR, IORQ pins on BUSAK (Figure 10 BUS Request/Acknowledge Cycle)

// 8 output control pins
assign {io_oeb[35:34], io_oeb[7], io_oeb[5:4], io_oeb[2:0]}
assign {io_oeb[34:32], io_oeb[5], io_oeb[3:0]}
= { 8{1'b0}}; // 0 = Output

// 16 output address bus pins
assign io_oeb[23:8] = {16{1'b0}}; // 0 = Output
assign io_oeb[21:6] = {16{1'b0}}; // 0 = Output

// 8 bidirectional data bus pins
assign io_oeb[31:24] = {8{~data_oe}};// 0 = Output | 1 = Input
assign io_oeb[29:22] = {8{~data_oe}};// 0 = Output | 1 = Input

// 4 input control pins
assign {io_oeb[33:32], io_oeb[6], io_oeb[3]} = {4{1'b1}}; // 1 = Input
assign {io_out[33:32], io_out[6], io_out[3]} = {4{1'b0}}; // Initialize otherwise undriven pins to 0
assign {io_oeb[35], io_oeb[31:30], io_oeb[4]} = {4{1'b1}}; // 1 = Input
assign {io_oeb[35], io_out[31:30], io_out[4]} = {4{1'b0}}; // Initialize otherwise undriven pins to 0

wire data_oe;
z80 z80 (
.clk (z80_clk),
.cen (ena),
.reset_n (rst_n),
.wait_n (io_in [ 6]),
.int_n (io_in [33]),
.nmi_n (io_in [32]),
.busrq_n (io_in [ 3]),
.wait_n (io_in [ 4]),
.int_n (io_in [31]),
.nmi_n (io_in [30]),
.busrq_n (io_in [35]),
// Z80 has peculiar data bus pin order, keep it to minimize wire crossing on the DIP40 PCB
// Also see: http://www.righto.com/2014/09/why-z-80s-data-pins-are-scrambled.html
// D7 - io[29]
// D6 - io[27]
// D5 - io[26]
// D4 - io[24]
// D3 - io[25]
// D2 - io[28]
// D1 - io[30]
// D0 - io[31]
.di ({io_in [29], io_in [27], io_in [26], io_in [24], io_in [25], io_in [28], io_in [30], io_in [31]}),
.dout ({io_out[29], io_out[27], io_out[26], io_out[24], io_out[25], io_out[28], io_out[30], io_out[31]}),

// D7 io[27]
// D6 io[25]
// D5 io[24]
// D4 io[22]
// D3 io[23]
// D2 io[26]
// D1 io[28]
// D0 io[29]
.di ({io_in [27], io_in [25], io_in [24], io_in [22], io_in [23], io_in [26], io_in [28], io_in [29]}),
.dout ({io_out[27], io_out[25], io_out[24], io_out[22], io_out[23], io_out[26], io_out[28], io_out[29]}),
.doe (data_oe),

// io[23] - A15
// io[21] - A15
// ...
// io[13] - A5
// io[8] - A4
// io[9] - A3
// io[10] - A2
// io[12] - A1
// io[11] - A0

.A ({io_out[23:13], io_out[8], io_out[9], io_out[10], io_out[12], io_out[11]}),

// 41 io[7] - 28| /RFSH -->
// 33 io[2] - 27| /M1 -->
// ...
// <-- /HALT |18 - io[0] io[1] - 23| /BUSAK -->
// <-- /MREQ |19 - io[34] io[5] - 22| /WR -->
// <-- /IORQ |20 - io[35] io[4] - 21| /RD -->
// `-------------------------------------'

.halt_n (io_out[ 0]),
.busak_n (io_out[ 1]),
.m1_n (io_out[ 2]),
.mreq_n (io_out[34]),
.iorq_n (io_out[35]),
.rd_n (io_out[ 4]),
.wr_n (io_out[ 5]),
.rfsh_n (io_out[ 7])
// io[11] - A5
// io[6] - A4
// io[7] - A3
// io[8] - A2
// io[10] - A1
// io[9] - A0

.A ({io_out[21:11], io_out[6], io_out[7], io_out[8], io_out[10], io_out[9]}),

io[ 5]| /RFSH -->
io[*1]| /M1 -->
...
<-- /HALT |io[32] io[*0]| /BUSAK -->
<-- /MREQ |io[33] io[ 3]| /WR -->
<-- /IORQ |io[34] io[ 2]| /RD -->
`-------------------------------------'

.halt_n (io_out[32]),
.busak_n (io_out[ 0]),
.m1_n (io_out[ 1]),
.mreq_n (io_out[33]),
.iorq_n (io_out[34]),
.rd_n (io_out[ 2]),
.wr_n (io_out[ 3]),
.rfsh_n (io_out[ 5])
);
endmodule

Expand Down
72 changes: 36 additions & 36 deletions test_chipignite/tb.v
Original file line number Diff line number Diff line change
Expand Up @@ -20,52 +20,52 @@ module tb ();
wire [35:0] io_oeb;

wire [3:0] controls_in;
wire [7:0] controls_out = {io_out[35:34], io_out[7], io_out[5:4], io_out[2:0]};
wire [15:0] addr = {io_out[23:13], io_out[8], io_out[9], io_out[10], io_out[12], io_out[11]};
wire [7:0] controls_out = {io_out[34:32], io_out[5], io_out[3:0]};
wire [15:0] addr = {io_out[21:11], io_out[6], io_out[7], io_out[8], io_out[10], io_out[9]};

assign {io_in[33:32], io_in[6], io_in[3]} = controls_in;
assign {io_in[35], io_in[31:30], io_in[4]} = controls_in;

// Z80 has a peculiar order of the pins for the data bus
// <-> D4 | io[24]
// <-> D3 | io[25]
// <-> D5 | io[26]
// <-> D6 | io[27]
// VCC_5V0 |
// <-> D2 | io[28]
// <-> D7 | io[29]
// <-> D0 | io[31]
// <-> D1 | io[30]
// <-> D4 7 |io[22]
// <-> D3 8 |io[23]
// <-> D5 9 |io[24]
// <-> D6 10|io[25]
// VCC_5V0 11|
// <-> D2 12|io[26]
// <-> D7 13|io[27]
// <-> D0 14|io[29]
// <-> D1 15|io[28]

wire [7:0] data_in;
wire [7:0] data_out;
wire [7:0] data_oe;

assign io_in [24] = data_in[4];
assign io_in [25] = data_in[3];
assign io_in [26] = data_in[5];
assign io_in [27] = data_in[6];
assign io_in [28] = data_in[2];
assign io_in [29] = data_in[7];
assign io_in [31] = data_in[0];
assign io_in [30] = data_in[1];
assign io_in [22] = data_in[4];
assign io_in [23] = data_in[3];
assign io_in [24] = data_in[5];
assign io_in [25] = data_in[6];
assign io_in [26] = data_in[2];
assign io_in [27] = data_in[7];
assign io_in [29] = data_in[0];
assign io_in [28] = data_in[1];

assign data_out[4] = io_out[24];
assign data_out[3] = io_out[25];
assign data_out[5] = io_out[26];
assign data_out[6] = io_out[27];
assign data_out[2] = io_out[28];
assign data_out[7] = io_out[29];
assign data_out[0] = io_out[31];
assign data_out[1] = io_out[30];
assign data_out[4] = io_out[22];
assign data_out[3] = io_out[23];
assign data_out[5] = io_out[24];
assign data_out[6] = io_out[25];
assign data_out[2] = io_out[26];
assign data_out[7] = io_out[27];
assign data_out[0] = io_out[29];
assign data_out[1] = io_out[28];

assign data_oe [4] = ~io_oeb[24];
assign data_oe [3] = ~io_oeb[25];
assign data_oe [5] = ~io_oeb[26];
assign data_oe [6] = ~io_oeb[27];
assign data_oe [2] = ~io_oeb[28];
assign data_oe [7] = ~io_oeb[29];
assign data_oe [0] = ~io_oeb[31];
assign data_oe [1] = ~io_oeb[30];
assign data_oe [4] = ~io_oeb[22];
assign data_oe [3] = ~io_oeb[23];
assign data_oe [5] = ~io_oeb[24];
assign data_oe [6] = ~io_oeb[25];
assign data_oe [2] = ~io_oeb[26];
assign data_oe [7] = ~io_oeb[27];
assign data_oe [0] = ~io_oeb[29];
assign data_oe [1] = ~io_oeb[28];

// Replace tt_um_example with your module name:
ci2406_z80 user_project (
Expand Down
28 changes: 14 additions & 14 deletions test_chipignite/test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
from cocotb.clock import Clock
from cocotb.triggers import ClockCycles, FallingEdge, RisingEdge

# io[3] io[6] io[32] io[33]
BUS_READY = 0b1111 # not BUSRQ, not WAIT, not INT, not NMI
# io[4] io[30] io[31] io[35]
BUS_READY = 0b1111 # not WAIT, not NMI, not INT, not BUSRQ
OPCODE_NOP = 0x00
OPCODE_LDHL = 0x21
OPCODE_LDNNA = 0x32
Expand Down Expand Up @@ -151,18 +151,18 @@ async def start_and_reset(dut):
async def z80_step(z80, cycle, verbose=False):
def read_controls():
controls = [bit_n(z80.controls_out, n) for n in range(8)]
# | io[7] - 28| /RFSH -->
# | io[2] - 27| /M1 -->
# | |
# | |
# | |
# <-- /HALT |18 - io[0] io[1] - 23| /BUSAK -->
# <-- /MREQ |19 - io[34] io[5] - 22| /WR -->
# <-- /IORQ |20 - io[35] io[4] - 21| /RD -->
# `-------------------------------------'
#
# io[0] io[1] io[2] io[4] io[5] io[7] io[34] io[35]
return dict(zip(['halt', 'busak', 'm1', 'rd', 'wr', 'rfsh', 'mreq', 'ioreq'], controls))


# io[ 5]| /RFSH -->
# io[*1]| /M1 -->
# ...
# <-- /HALT |io[32] io[*0]| /BUSAK -->
# <-- /MREQ |io[33] io[ 3]| /WR -->
# <-- /IORQ |io[34] io[ 2]| /RD -->
# `-------------------------------------'

# io[0] io[1] io[2] io[3] io[5] io[32] io[33] io[34]
return dict(zip(['busak', 'm1', 'rd', 'wr', 'rfsh', 'halt', 'mreq', 'ioreq'], controls))

def read_data():
if z80.data_oe.value != 0b1111_1111:
Expand Down

0 comments on commit a31522c

Please sign in to comment.