]> git.sesse.net Git - pistorm/blob - rtl/pistorm.v
0b26ffdbf0981b218a18ef949956e40e397480ad
[pistorm] / rtl / pistorm.v
1 /*
2  * Copyright 2020 Claude Schwarz
3  * Copyright 2020 Niklas Ekström - rewrite in Verilog
4  */
5 module pistorm(
6     output reg      PI_TXN_IN_PROGRESS, // GPIO0
7     output reg      PI_IPL_ZERO,        // GPIO1
8     input   [1:0]   PI_A,       // GPIO[3..2]
9     input           PI_CLK,     // GPIO4
10     output reg      PI_RESET,   // GPIO5
11     input           PI_RD,      // GPIO6
12     input           PI_WR,      // GPIO7
13     inout   [15:0]  PI_D,       // GPIO[23..8]
14
15     output reg      LTCH_A_0,
16     output reg      LTCH_A_8,
17     output reg      LTCH_A_16,
18     output reg      LTCH_A_24,
19     output reg      LTCH_A_OE_n,
20     output reg      LTCH_D_RD_U,
21     output reg      LTCH_D_RD_L,
22     output reg      LTCH_D_RD_OE_n,
23     output reg      LTCH_D_WR_U,
24     output reg      LTCH_D_WR_L,
25     output reg      LTCH_D_WR_OE_n,
26
27     input           M68K_CLK,
28     output  reg [2:0] M68K_FC,
29
30     output reg      M68K_AS_n,
31     output reg      M68K_UDS_n,
32     output reg      M68K_LDS_n,
33     output reg      M68K_RW,
34
35     input           M68K_DTACK_n,
36     input           M68K_BERR_n,
37
38     input           M68K_VPA_n,
39     output reg      M68K_E,
40     output reg      M68K_VMA_n,
41
42     input   [2:0]   M68K_IPL_n,
43
44     inout           M68K_RESET_n,
45     inout           M68K_HALT_n,
46
47     input           M68K_BR_n,
48     output reg      M68K_BG_n,
49     input           M68K_BGACK_n
50   );
51
52   wire c200m = PI_CLK;
53   wire c7m = M68K_CLK;
54
55   localparam REG_DATA = 2'd0;
56   localparam REG_ADDR_LO = 2'd1;
57   localparam REG_ADDR_HI = 2'd2;
58   localparam REG_STATUS = 2'd3;
59
60   initial begin
61     PI_TXN_IN_PROGRESS <= 1'b0;
62     PI_IPL_ZERO <= 1'b0;
63
64     PI_RESET <= 1'b0;
65
66     M68K_FC <= 3'd0;
67
68     M68K_RW <= 1'b1;
69
70     M68K_E <= 1'b0;
71     M68K_VMA_n <= 1'b1;
72
73     M68K_BG_n <= 1'b1;
74   end
75
76   reg [1:0] rd_sync;
77   reg [1:0] wr_sync;
78
79   always @(posedge c200m) begin
80     rd_sync <= {rd_sync[0], PI_RD};
81     wr_sync <= {wr_sync[0], PI_WR};
82   end
83
84   wire rd_rising = !rd_sync[1] && rd_sync[0];
85   wire wr_rising = !wr_sync[1] && wr_sync[0];
86
87   reg [15:0] data_out;
88   assign PI_D = PI_A == REG_STATUS && PI_RD ? data_out : 16'bz;
89
90   always @(posedge c200m) begin
91     if (rd_rising && PI_A == REG_STATUS) begin
92       data_out <= {ipl, 13'd0};
93     end
94   end
95
96   reg [15:0] status;
97   wire reset_out = !status[1];
98
99   assign M68K_RESET_n = reset_out ? 1'b0 : 1'bz;
100   assign M68K_HALT_n = reset_out ? 1'b0 : 1'bz;
101
102   reg op_req = 1'b0;
103   reg op_rw = 1'b1;
104   reg op_uds_n = 1'b1;
105   reg op_lds_n = 1'b1;
106
107   always @(*) begin
108     LTCH_D_WR_U <= PI_A == REG_DATA && PI_WR;
109     LTCH_D_WR_L <= PI_A == REG_DATA && PI_WR;
110
111     LTCH_A_0 <= PI_A == REG_ADDR_LO && PI_WR;
112     LTCH_A_8 <= PI_A == REG_ADDR_LO && PI_WR;
113
114     LTCH_A_16 <= PI_A == REG_ADDR_HI && PI_WR;
115     LTCH_A_24 <= PI_A == REG_ADDR_HI && PI_WR;
116
117     LTCH_D_RD_OE_n <= !(PI_A == REG_DATA && PI_RD);
118   end
119
120   reg [2:0] s1_sync;
121   reg [2:0] s7_sync;
122
123   always @(posedge c200m) begin
124     s1_sync <= {s1_sync[1:0], S1};
125     s7_sync <= {s7_sync[1:0], S7};
126   end
127
128   wire rising_s1 = !s1_sync[2] && s1_sync[1];
129   wire rising_s7 = !s7_sync[2] && s7_sync[1];
130
131   reg a0;
132
133   always @(posedge c200m) begin
134     if (rising_s1)
135       op_req <= 1'b0;
136
137     if (rising_s7)
138       PI_TXN_IN_PROGRESS <= 1'b0;
139
140     if (wr_rising) begin
141       case (PI_A)
142         REG_ADDR_LO: begin
143           a0 <= PI_D[0];
144           PI_TXN_IN_PROGRESS <= 1'b1;
145         end
146         REG_ADDR_HI: begin
147           op_req <= 1'b1;
148           op_rw <= PI_D[9];
149           op_uds_n <= PI_D[8] ? a0 : 1'b0;
150           op_lds_n <= PI_D[8] ? !a0 : 1'b0;
151         end
152         REG_STATUS: begin
153           status <= PI_D;
154         end
155       endcase
156     end
157   end
158
159   reg [2:0] c7m_sync;
160
161   always @(posedge c200m) begin
162     c7m_sync <= {c7m_sync[1:0], M68K_CLK};
163   end
164
165   wire c7m_rising = !c7m_sync[2] && c7m_sync[1];
166   wire c7m_falling = c7m_sync[2] && !c7m_sync[1];
167
168   reg [2:0] ipl;
169   reg [2:0] ipl_1;
170   reg [2:0] ipl_2;
171
172   always @(posedge c200m) begin
173     if (c7m_falling) begin
174       ipl_1 <= ~M68K_IPL_n;
175       ipl_2 <= ipl_1;
176     end
177
178     if (ipl_2 == ipl_1)
179       ipl <= ipl_2;
180
181     PI_IPL_ZERO <= ipl == 3'd0;
182   end
183
184   always @(posedge c200m) begin
185     PI_RESET <= reset_out ? 1'b1 : M68K_RESET_n;
186   end
187
188   reg [3:0] e_counter = 4'd0;
189
190   always @(negedge c7m) begin
191     if (e_counter == 4'd9)
192       e_counter <= 4'd0;
193     else
194       e_counter <= e_counter + 4'd1;
195   end
196
197   always @(negedge c7m) begin
198     if (e_counter == 4'd9)
199       M68K_E <= 1'b0;
200     else if (e_counter == 4'd5)
201       M68K_E <= 1'b1;
202   end
203
204   reg [1:0] state = 2'd0;
205   reg wait_req = 1'b1;
206   reg wait_dtack = 1'b0;
207
208   wire S0 = state == 2'd0 && c7m && !wait_req;
209   wire Sr = state == 2'd0 && wait_req;
210   wire S1 = state == 2'd1 && !c7m;
211   wire S2 = state == 2'd1 && c7m;
212   wire S3 = state == 2'd2 && !c7m && !wait_dtack;
213   wire S4 = state == 2'd2 && c7m && !wait_dtack;
214   wire Sw = state == 2'd2 && wait_dtack;
215   wire S5 = state == 2'd3 && !c7m;
216   wire S6 = state == 2'd3 && c7m;
217   wire S7 = state == 2'd0 && !c7m && !wait_req;
218
219   always @(*) begin
220     LTCH_A_OE_n <= !(S1 || S2 || S3 || S4 || Sw || S5 || S6 || S7);
221     LTCH_D_WR_OE_n <= !(!op_rw && (S3 || S4 || Sw || S5 || S6 || S7));
222
223     LTCH_D_RD_U <= S7;
224     LTCH_D_RD_L <= S7;
225
226     M68K_AS_n <= !(S2 || S3 || S4 || Sw || S5 || S6);
227     M68K_UDS_n <= (op_rw && (S2 || S3)) || (S4 || Sw || S5 || S6) ? op_uds_n : 1'b1;
228     M68K_LDS_n <= (op_rw && (S2 || S3)) || (S4 || Sw || S5 || S6) ? op_lds_n : 1'b1;
229   end
230
231   always @(negedge c7m) begin
232     case (state)
233       2'd0: begin // S0|Sr -> S1|Sr
234         if (op_req_sync) begin
235           wait_req <= 1'b0;
236           state <= state + 2'd1;
237         end
238         else begin
239           wait_req <= 1'b1;
240         end
241       end
242
243       2'd1: begin // S2 -> S3
244         state <= state + 2'd1;
245       end
246
247       2'd2: begin // S4|Sw -> S5|Sw
248         if (!M68K_DTACK_n || (!M68K_VMA_n && e_counter == 4'd8)) begin
249           wait_dtack <= 1'b0;
250           state <= state + 2'd1;
251         end
252         else begin
253           if (!M68K_VPA_n && e_counter == 4'd2) begin
254             M68K_VMA_n <= 1'b0;
255           end
256           wait_dtack <= 1'b1;
257         end
258       end
259
260       2'd3: begin // S6 -> S7
261         M68K_VMA_n <= 1'b1;
262         state <= state + 2'd1;
263       end
264     endcase
265   end
266
267   reg op_req_sync;
268
269   always @(posedge c7m) begin
270     op_req_sync <= op_req;
271
272     case (state)
273       2'd0: M68K_RW <= 1'b1; // S7 -> S0
274       2'd1: M68K_RW <= op_rw; // S1 -> S2
275     endcase
276   end
277
278 endmodule