OpenCores
URL https://opencores.org/ocsvn/risc16f84/risc16f84/trunk

Subversion Repositories risc16f84

[/] [risc16f84/] [web_uploads/] [risc16f84.v] - Blame information for rev 9

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 9 root
//---------------------------------------------------------------------------
2
// RISC 16F84 core
3
//
4
// This file is part of the "risc_16F84" project.
5
// http://www.opencores.org/cores/risc_16F84
6
// 
7
//
8
// Description: See description below (which suffices for IP core
9
//                                     specification document.)
10
//
11
// Copyright (C) 1999 Sumio Morioka (original VHDL design version)
12
// Copyright (C) 2001 John Clayton and OPENCORES.ORG (this Verilog version)
13
//
14
// NOTE: This source code is free for educational/hobby use only.  It cannot
15
// be used for commercial purposes without the consent of Microchip
16
// Technology incorporated.
17
//
18
// This source file may be used and distributed without restriction provided
19
// that this copyright statement is not removed from the file and that any
20
// derivative work contains the original copyright notice and the associated
21
// disclaimer.
22
//
23
// This source file is free software; you can redistribute it and/or modify
24
// it under the terms of the GNU Lesser General Public License as published
25
// by the Free Software Foundation;  either version 2.1 of the License, or
26
// (at your option) any later version.
27
//
28
// This source is distributed in the hope that it will be useful, but WITHOUT
29
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
30
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
31
// License for more details.
32
//
33
// You should have received a copy of the GNU Lesser General Public License
34
// along with this source.
35
// If not, download it from http://www.opencores.org/lgpl.shtml
36
//
37
//---------------------------------------------------------------------------
38
//
39
// Author: John Clayton
40
// Date  : January 29, 2002
41
//
42
// (NOTE: Date formatted as day/month/year.)
43
// Update: 29/01/02 copied this file from memory_sizer.v (pared down).
44
//                  Translated the module and signal declarations.
45
//                  Transformed the instruction wires to lowercase.
46
//                  Transformed the addressing wires to lowercase.
47
// Update: 31/01/02 Translated the instruction decoder.
48
// Update:  5/02/02 Determined that stack is simply a circular buffer of
49
//                  8 locations, 13 bits per location.  Started translating
50
//                  "main_efsm" process.  Added all code from piccore.vhd
51
//                  into this file for eventual translation.  Concluded that
52
//                  "stack_full_node" is not needed.
53
// Update:  6/02/02 Translated the "ram_i_node" if/else precedural assignment.
54
// Update:  7/02/02 Changed all := to <=, changed all '0' to 0 and '1' to 1.
55
//                  Replaced all " downto " with ":".
56
//                  Finished translating QRESET state.
57
// Update: 20/02/02 Replaced all instances of Qreset with QRESET_PP.  Also
58
//                  replaced other state designations with their new names.
59
//                  Finished translating Q1, Q2 states.
60
// Update: 22/02/02 Translated section 2-4-1-1 (aluout register)
61
// Update: 27/02/02 Replaced all "or" with "||" in if statements
62
//                  Replaced all "and" with "&&" in if statements.
63
//                  Replaced all "not" with "~" in if statements.
64
//                  Finished translating Q3,Q4 states.
65
//                  Translated output signal assignments at end of code.
66
//                  Translated interrupt trigger processes.
67
// Update: 28/02/02 Finished translation of WDT and TMR0 prescaler.
68
//                  Trimmed line length to 80 characters throughout.
69
//                  Prepared to attempt initial syntax checking.
70
//                  Cleaned up some naming conventions, and verified that
71
//                  all I/O pins have _i or _o appended in the body of the
72
//                  code.
73
// Update: 03/04/02 Changed "progdata_i" to "prog_dat_i" Also changed
74
//                  "progadr_o" to "prog_adr_o"
75
// Update: 04/26/02 Fixed bug in aluout_reg logic, whereby the AND/OR type
76
//                  operations were coded with logical instead of bitwise
77
//                  operators.
78
// Update: 05/01/02 Fixed another bug -- the rrf and rlf instructions were
79
//                  coded incorrectly.
80
// Update: 05/05/02 Fixed another bug -- the carry bit was incorrect (the
81
//                  problem was discovered while performing SUBWF X,W where
82
//                  W contained 0 and X contained 1. (1-0).  The logic for
83
//                  the carry bit appears to have been incorrect even in
84
//                  the original VHDL code by Sumio Morioka.
85
// Update: 10/30/02 Fixed syntax error pointed out by Cheol-Kyoo Lee, who got
86
//                  the source code from opencores.com.  Removed semicolon
87
//                  from "endcase" statements.
88
//
89
// Description
90
//---------------------------------------------------------------------------
91
// This logic module implements a small RISC microcontroller, with functions
92
// and instruction set very similar to those of the Microchip 16F84 chip.
93
// This work is a translation (from VHDL to Verilog) of the "CQPIC" design
94
// published in 1999 by Sumio Morioka of Japan, and published in the December
95
// 1999 issue of "Transistor Gijutsu Magazine."  The translation was performed
96
// by John Clayton, without the use of any translation tools.
97
//
98
// Original version used as basis for translation:  CQPIC version 1.00b
99
//                                                  (December 10, 2000)
100
//---------------------------------------------------------------------------
101
 
102
`define STATEBIT_SIZE 3      // Size of state machine register (bits)
103
 
104
 
105
module pic_16f84_core (
106
  prog_dat_i,           // [13:0] ROM read data
107
  prog_adr_o,           // [12:0] ROM address
108
  ram_dat_i,            // [7:0] RAM read data
109
  ram_dat_o,            // [7:0] RAM write data
110
  ram_adr_o,            // [8:0] RAM address; ram_adr[8:7] indicates RAM-BANK
111
  readram_o,            // RAM read strobe (H active)
112
  writeram_o,           // RAM write strobe (H active)
113
  existeeprom_i,        // Set to 1 if EEPROM is implemented.
114
  eep_dat_i,            // [7:0] EEPROM read data
115
  eep_dat_o,            // [7:0] EEPROM write data
116
  eep_adr_o,            // [7:0] EEPROM address
117
  rd_eep_req_o,         // EEPROM read request (H active)
118
  rd_eep_ack_i,         // EEPROM read acknowledge (H active)
119
  wr_eep_req_o,         // EEPROM write request (H active)
120
  wr_eep_ack_i,         // EEPROM write acknowledge (H active)
121
  porta_i,              // [4:0] PORT-A input data
122
  porta_o,              // [4:0] PORT-A output data
123
  porta_dir_o,          // [4:0] TRISA: PORT-A signal dir. (H:in, L:out)
124
  portb_i,              // [7:0] PORT-B input data
125
  portb_o,              // [7:0] PORT-B output data
126
  portb_dir_o,          // [7:0] TRISB: PORT-B signal dir. (H:in, L:out)
127
  rbpu_o,               // PORT_B pull-up enable (usually not used)
128
  int0_i,               // PORT-B(0) INT
129
  int4_i,               // PORT-B(4) INT
130
  int5_i,               // PORT-B(5) INT
131
  int6_i,               // PORT-B(6) INT
132
  int7_i,               // PORT-B(7) INT
133
  t0cki_i,              // T0CKI (PORT-A(4))
134
  wdt_ena_i,            // WDT enable (H active)
135
  wdt_clk_i,            // WDT clock
136
  wdt_full_o,           // WDT-full indicator (H active)
137
  powerdown_o,          // SLEEP-mode; if H, you can stop system clock clk_i
138
  startclk_o,           // WAKEUP; if H, turn on clk_i for leaving sleep-mode
139
  pon_rst_n_i,          // Power-on reset (L active)
140
  mclr_n_i,             // Normal reset (L active)
141
  clk_i,                // Clock input
142
  clk_o                 // Clock output (clk_i/4)
143
);
144
 
145
 
146
// You can change the following parameters as you would like
147
parameter STACK_SIZE_PP      = 8;   // Size of PC stack
148
parameter LOG2_STACK_SIZE_PP = 3;   // Log_2(stack_size)
149
parameter WDT_SIZE_PP        = 255; // Size of watch dog timer (WDT)
150
parameter WDT_BITS_PP        = 8;   // Bits needed for watch dog timer (WDT)
151
 
152
// State definitions for state machine, provided as parameters to allow
153
// for redefinition of state values by the instantiator if desired.
154
parameter QRESET_PP = 3'b100; // reset state
155
parameter Q1_PP     = 3'b000; // state Q1
156
parameter Q2_PP     = 3'b001; // state Q2
157
parameter Q3_PP     = 3'b011; // state Q3
158
parameter Q4_PP     = 3'b010; // state Q4
159
 
160
 
161
// I/O declarations
162
 
163
       // program ROM data bus/address bus
164
input  [13:0] prog_dat_i;   // ROM read data
165
output [12:0] prog_adr_o;   // ROM address
166
 
167
       // data RAM data bus/address bus/control signals
168
input  [7:0] ram_dat_i;     // RAM read data
169
output [7:0] ram_dat_o;     // RAM write data
170
output [8:0] ram_adr_o;     // RAM address; ram_adr[8:7] indicates RAM-BANK
171
output readram_o;           // RAM read  strobe (H active)
172
output writeram_o;          // RAM write strobe (H active)
173
 
174
       // EEPROM data bus/address bus
175
input  existeeprom_i;       // Set to 1 if EEPROM is implemented.
176
input  [7:0] eep_dat_i;     // EEPROM read data
177
output [7:0] eep_dat_o;     // EEPROM write data
178
output [7:0] eep_adr_o;     // EEPROM address
179
output rd_eep_req_o;        // EEPROM read request (H active)
180
input  rd_eep_ack_i;        // EEPROM read acknowledge (H active)
181
output wr_eep_req_o;        // EEPROM write request (H active)
182
input  wr_eep_ack_i;        // EEPROM write acknowledge (H active)
183
 
184
       // I/O ports
185
input  [4:0] porta_i;       // PORT-A input data
186
output [4:0] porta_o;       // PORT-A output data
187
output [4:0] porta_dir_o;   // TRISA: PORT-A signal dir. (H:input, L:output)
188
input  [7:0] portb_i;       // PORT-B input data
189
output [7:0] portb_o;       // PORT-B output data
190
output [7:0] portb_dir_o;   // TRISB: PORT-B signal dir. (H:input, L:output)
191
output rbpu_o;              // PORT_B pull-up enable (usually not used)
192
 
193
       // PORT-B interrupt input
194
input  int0_i;              // PORT-B(0) INT
195
input  int4_i;              // PORT-B(4) INT
196
input  int5_i;              // PORT-B(5) INT
197
input  int6_i;              // PORT-B(6) INT
198
input  int7_i;              // PORT-B(7) INT
199
 
200
       // TMR0 Control
201
input  t0cki_i;             // T0CKI (PORT-A(4))
202
 
203
       // Watch Dog Timer Control
204
input  wdt_ena_i;           // WDT enable (H active)
205
input  wdt_clk_i;           // WDT clock
206
output wdt_full_o;          // WDT-full indicator (H active)
207
 
208
       // CPU clock stop/start indicators
209
output powerdown_o;         // SLEEP-mode; if H, then you can
210
                            // stop the system clock clk_i
211
output startclk_o;          // WAKEUP; if H, you should turn on
212
                            // clock clk_i for waking up from sleep-mode
213
       // CPU reset
214
input  pon_rst_n_i;         // Power-on reset (LOW active)
215
input  mclr_n_i;            // Normal reset (LOW active)
216
 
217
       // CPU clock
218
input  clk_i;               // Clock input
219
output clk_o;               // Clock output (clk_i/4)
220
 
221
 
222
// Internal signal declarations
223
 
224
     // User registers
225
reg  [7:0] w_reg;            // W
226
reg  [7:0] tmr0_reg;         // TMR0
227
reg  [12:0] pc_reg;          // PCH/PCL
228
reg  [7:0] status_reg;       // STATUS
229
reg  [7:0] fsr_reg;          // FSR
230
reg  [4:0] porta_i_sync_reg; // PORTA IN (synchronizer)
231
reg  [4:0] porta_o_reg;      // PORTA OUT
232
reg  [7:0] portb_i_sync_reg; // PORTB IN (synchronizer)
233
reg  [7:0] portb_o_reg;      // PORTB OUT
234
reg  [7:0] eep_dat_reg;      // EEPROM DATA
235
reg  [7:0] eep_adr_reg;      // EEPROM ADDRESS
236
reg  [4:0] pclath_reg;       // PCLATH
237
reg  [7:0] intcon_reg;       // INTCON
238
reg  [7:0] option_reg;       // OPTION
239
reg  [4:0] trisa_reg;        // TRISA
240
reg  [7:0] trisb_reg;        // TRISB
241
reg  [4:0] eecon1_reg;       // EECON1
242
 
243
     // Internal registers for controlling instruction execution
244
reg  [13:0] inst_reg;        // Hold fetched op-code/operand
245
reg  [7:0] aluinp1_reg;      // data source (1 of 2)
246
reg  [7:0] aluinp2_reg;      // data source (2 of 2)
247
reg        c_in;             // Used with ALU data sources.
248
reg  [7:0] aluout_reg;       // result of calculation
249
reg  exec_op_reg;            // if L (i.e. GOTO instruction etc), stall exec.
250
reg  intstart_reg;           // if H (i.e. interrupt), stall instr. exec.
251
reg  sleepflag_reg;          // if H, sleeping.
252
 
253
     // Stack
254
                             // stack (array of data-registers)
255
reg  [12:0] stack_reg [STACK_SIZE_PP-1:0];
256
                             // stack pointer (binary encoded)
257
reg  [LOG2_STACK_SIZE_PP-1:0] stack_pnt_reg;
258
 
259
     // WDT register and its control
260
reg  [WDT_BITS_PP-1:0] wdt_reg;  // WDT counter
261
reg  wdt_full_reg;               // WDT->CPU; hold WDT-full signal until 
262
                                 //   CPU is reset
263
reg  wdt_full_node;
264
wire wdt_init;                   // Initialize the WDT
265
reg  [2:0] wdt_full_sync_reg;    // CPU; synchronizer for wdt_full_reg
266
reg  wdt_clr_reg;                // CPU->WDT; request to zero-clear wdt_reg
267
reg  wdt_clr_reqhold_reg;        // CPU; hold a clear-request if 
268
                                 //   previous request is still processing
269
reg  [1:0] wdt_clr_req_reg;      // WDT; synchronizer for wdt_clr_reg
270
wire wdt_clr_ack;                // WDT->CPU; ack to wdt_clr_reg 
271
                                 //   (same with wdt_clr_req_reg(1))
272
reg  wdt_clr_ack_sync_reg;       // CPU; synchronizer for wdt_clr_ack
273
reg  wdt_full_clr_reg;           // CPU->WDT; request to clear wdt_full_reg
274
reg  [1:0] wdt_fullclr_req_reg;  // WDT; synchronizer for wdt_full_clr_reg
275
 
276
     // TMR0 prescaler
277
wire ps_clk;                  // clock for prescaler
278
reg  [7:0] pscale_reg;        // prescaler (range 0 to 255)
279
reg  ps_full_reg;             // clock for TMR0, from prescaler
280
wire inc_tmr_clk;             // clock for TMR0
281
reg  inc_tmr_hold_reg;        // hold TMR0 increment request
282
reg  [7:0] rateval;           // Temporary storage value within process
283
 
284
     // Interrupt registers/nodes
285
reg  [4:0] intrise_reg;       // detect positive edge of PORT-B inputs
286
reg  [4:0] intdown_reg;       // detect negative edge of PORT-B inputs
287
                              // Interrupt triggers
288
wire rb0_int;
289
wire rb4_int;
290
wire rb5_int;
291
wire rb6_int;
292
wire rb7_int;
293
 
294
wire rbint;                   // RB4-7 interrupt trigger
295
wire inte;                    // RB0   interrupt trigger
296
reg  [4:0] intclr_reg;        // CPU; clear intrise_reg and intdown_reg
297
wire intclr0;                 // Individual wires used in sensitivity lists
298
wire intclr1;                 // since "simple variables" are OK,
299
wire intclr2;                 // but apparently intclr_reg[0] is not a
300
wire intclr3;                 // "simple variable or its negation."
301
wire intclr4;
302
 
303
     // State register
304
reg  [`STATEBIT_SIZE-1:0] state_reg;
305
 
306
     // Result of decoding instruction -- only 1 is active at a time
307
wire inst_addlw;
308
wire inst_addwf;
309
wire inst_andlw;
310
wire inst_andwf;
311
wire inst_bcf;
312
wire inst_bsf;
313
wire inst_btfsc;
314
wire inst_btfss;
315
wire inst_call;
316
wire inst_clrf;
317
wire inst_clrw;
318
wire inst_clrwdt;
319
wire inst_comf;
320
wire inst_decf;
321
wire inst_decfsz;
322
wire inst_goto;
323
wire inst_incf;
324
wire inst_incfsz;
325
wire inst_iorlw;
326
wire inst_iorwf;
327
wire inst_movlw;
328
wire inst_movf;
329
wire inst_movwf;
330
wire inst_retfie;
331
wire inst_retlw;
332
wire inst_ret;
333
wire inst_rlf;
334
wire inst_rrf;
335
wire inst_sleep;
336
wire inst_sublw;
337
wire inst_subwf;
338
wire inst_swapf;
339
wire inst_xorlw;
340
wire inst_xorwf;
341
 
342
     // Result of calculating RAM access address
343
wire [8:0] ram_adr_node;      // RAM access address
344
 
345
     // These wires indicate accesses to special registers... 
346
     // Only 1 is active at a time.
347
wire addr_tmr0;
348
wire addr_pcl;
349
wire addr_stat;
350
wire addr_fsr;
351
wire addr_porta;
352
wire addr_portb;
353
wire addr_eep_dat;
354
wire addr_eep_adr;
355
wire addr_pclath;
356
wire addr_intcon;
357
wire addr_option;
358
wire addr_trisa;
359
wire addr_trisb;
360
wire addr_eecon1;
361
wire addr_eecon2;
362
wire addr_sram;
363
 
364
     // Other output registers (for removing hazards)
365
reg  writeram_reg;      // data-sram write strobe
366
reg  [8:0] ram_adr_reg; // data-sram address
367
reg  clk_o_reg;         // clock output
368
 
369
     // Synchronizers
370
reg  inte_sync_reg;
371
reg  rbint_sync_reg;
372
reg  [1:0] inc_tmr_sync_reg;
373
reg  rd_eep_sync_reg;
374
reg  wr_eep_sync_reg;
375
reg  mclr_sync_reg;
376
reg  poweron_sync_reg;
377
 
378
     // Signals used in "main_efsm" procedure
379
     // (Intermediate nodes used for resource sharing.)
380
reg  [7:0] ram_i_node;   // result of reading RAM/Special registers
381
reg  [12:0] inc_pc_node; // value of PC + 1
382
wire [7:0] mask_node;    // bit mask for logical operations
383
reg  [8:0] add_node;     // result of 8bit addition
384
reg  [4:0] addlow_node;  // result of low-4bit addition
385
wire temp;               // Placeholder wire
386
wire dtemp;              // Placeholder wire
387
reg  aluout_zero_node;   // H if ALUOUT = 0
388
reg  writew_node;        // H if destination is W register
389
reg  writeram_node;      // H if destination is RAM/Special registers
390
reg  int_node;           // H if interrupt request comes
391
reg  wdt_rst_node;       // H if WDT-reset request comes
392
reg  reset_cond;         // H for any reset request (jump to QRESET_PP state)
393
 
394
//--------------------------------------------------------------------------
395
// Instantiations
396
//--------------------------------------------------------------------------
397
 
398
 
399
//--------------------------------------------------------------------------
400
// Functions & Tasks
401
//--------------------------------------------------------------------------
402
 
403
//--------------------------------------------------------------------------
404
// Module code
405
//--------------------------------------------------------------------------
406
 
407
 
408
// CPU synchronizers
409
always @(posedge clk_i)
410
begin
411
  inte_sync_reg          <= inte;
412
  rbint_sync_reg         <= rbint;
413
  wdt_clr_ack_sync_reg   <= wdt_clr_ack;
414
  mclr_sync_reg          <= mclr_n_i;
415
  poweron_sync_reg       <= pon_rst_n_i;
416
  rd_eep_sync_reg        <= rd_eep_ack_i;
417
  wr_eep_sync_reg        <= wr_eep_ack_i;
418
  inc_tmr_sync_reg[0]    <= inc_tmr_clk;
419
  inc_tmr_sync_reg[1]    <= inc_tmr_sync_reg[0];
420
  if (~poweron_sync_reg || ~mclr_sync_reg)
421
    wdt_full_sync_reg    <= 3'b0;
422
  else
423
  begin
424
    wdt_full_sync_reg[0] <= wdt_full_reg;
425
    wdt_full_sync_reg[1] <= wdt_full_sync_reg[0]; // (remove meta-stability)
426
    wdt_full_sync_reg[2] <= wdt_full_sync_reg[1]; // (detect positive edge)
427
  end
428
end
429
 
430
 
431
// Decode OPcode    (see pp.54 of PIC16F84 data sheet)
432
// only 1 signal of the following signals will be '1'
433
assign inst_call     = (inst_reg[13:11] ==  3'b100           );
434
assign inst_goto     = (inst_reg[13:11] ==  3'b101           );
435
assign inst_bcf      = (inst_reg[13:10] ==  4'b0100          );
436
assign inst_bsf      = (inst_reg[13:10] ==  4'b0101          );
437
assign inst_btfsc    = (inst_reg[13:10] ==  4'b0110          );
438
assign inst_btfss    = (inst_reg[13:10] ==  4'b0111          );
439
assign inst_movlw    = (inst_reg[13:10] ==  4'b1100          );
440
assign inst_retlw    = (inst_reg[13:10] ==  4'b1101          );
441
assign inst_sublw    = (inst_reg[13:9]  ==  5'b11110         );
442
assign inst_addlw    = (inst_reg[13:9]  ==  5'b11111         );
443
assign inst_iorlw    = (inst_reg[13:8]  ==  6'b111000        );
444
assign inst_andlw    = (inst_reg[13:8]  ==  6'b111001        );
445
assign inst_xorlw    = (inst_reg[13:8]  ==  6'b111010        );
446
assign inst_subwf    = (inst_reg[13:8]  ==  6'b000010        );
447
assign inst_decf     = (inst_reg[13:8]  ==  6'b000011        );
448
assign inst_iorwf    = (inst_reg[13:8]  ==  6'b000100        );
449
assign inst_andwf    = (inst_reg[13:8]  ==  6'b000101        );
450
assign inst_xorwf    = (inst_reg[13:8]  ==  6'b000110        );
451
assign inst_addwf    = (inst_reg[13:8]  ==  6'b000111        );
452
assign inst_movf     = (inst_reg[13:8]  ==  6'b001000        );
453
assign inst_comf     = (inst_reg[13:8]  ==  6'b001001        );
454
assign inst_incf     = (inst_reg[13:8]  ==  6'b001010        );
455
assign inst_decfsz   = (inst_reg[13:8]  ==  6'b001011        );
456
assign inst_rrf      = (inst_reg[13:8]  ==  6'b001100        );
457
assign inst_rlf      = (inst_reg[13:8]  ==  6'b001101        );
458
assign inst_swapf    = (inst_reg[13:8]  ==  6'b001110        );
459
assign inst_incfsz   = (inst_reg[13:8]  ==  6'b001111        );
460
assign inst_movwf    = (inst_reg[13:7]  ==  7'b0000001       );
461
assign inst_clrw     = (inst_reg[13:7]  ==  7'b0000010       );
462
assign inst_clrf     = (inst_reg[13:7]  ==  7'b0000011       );
463
assign inst_ret      = (inst_reg[13:0]  == 14'b00000000001000);
464
assign inst_retfie   = (inst_reg[13:0]  == 14'b00000000001001);
465
assign inst_sleep    = (inst_reg[13:0]  == 14'b00000001100011);
466
assign inst_clrwdt   = (inst_reg[13:0]  == 14'b00000001100100);
467
 
468
 
469
// Calculate RAM access address (see pp.19 of PIC16F84 data sheet)
470
 
471
    // if "d"=0, indirect addressing is used, so RAM address is BANK+FSR
472
    // otherwise, RAM address is BANK+"d"
473
    // (see pp.19 of PIC16F84 data sheet)
474
assign ram_adr_node = (inst_reg[6:0]==0)?{status_reg[7],fsr_reg[7:0]}:
475
                               {status_reg[6:5],inst_reg[6:0]};
476
 
477
    // check if this is an access to external RAM or not
478
assign addr_sram   = (ram_adr_node[6:0] > 7'b0001011); //0CH-7FH,8CH-FFH
479
 
480
    // check if this is an access to special register or not
481
    // only 1 signal of the following signals will be '1'
482
assign addr_tmr0    = (ram_adr_node[7:0] == 8'b00000001); // 01H
483
assign addr_pcl     = (ram_adr_node[6:0] ==  7'b0000010); // 02H, 82H
484
assign addr_stat    = (ram_adr_node[6:0] ==  7'b0000011); // 03H, 83H
485
assign addr_fsr     = (ram_adr_node[6:0] ==  7'b0000100); // 04H, 84H
486
assign addr_porta   = (ram_adr_node[7:0] == 8'b00000101); // 05H
487
assign addr_portb   = (ram_adr_node[7:0] == 8'b00000110); // 06H
488
assign addr_eep_dat = (ram_adr_node[7:0] == 8'b00001000); // 08H
489
assign addr_eep_adr = (ram_adr_node[7:0] == 8'b00001001); // 09H
490
assign addr_pclath  = (ram_adr_node[6:0] ==  7'b0001010); // 0AH, 8AH
491
assign addr_intcon  = (ram_adr_node[6:0] ==  7'b0001011); // 0BH, 8BH
492
assign addr_option  = (ram_adr_node[7:0] == 8'b10000001); // 81H
493
assign addr_trisa   = (ram_adr_node[7:0] == 8'b10000101); // 85H
494
assign addr_trisb   = (ram_adr_node[7:0] == 8'b10000110); // 86H
495
assign addr_eecon1  = (ram_adr_node[7:0] == 8'b10001000); // 88H
496
assign addr_eecon2  = (ram_adr_node[7:0] == 8'b10001001); // 89H
497
 
498
// construct bit-mask for logical operations and bit tests
499
assign mask_node = 1 << inst_reg[9:7];
500
 
501
// MAIN EFSM: description of register value changes in each clock cycle
502
always @(posedge clk_i)
503
begin
504
  // 1. Intermediate nodes for resource sharing
505
 
506
  // This is a long if/else chain.  Consider pulling in the decoded signals
507
  // addr_tmr0 etc., and using a case statement instead?
508
  // 1-1. Reading RAM/data sources  (see pp.13 of PIC16F84 data sheet)
509
  if (addr_sram)         ram_i_node <= ram_dat_i;   // data from ext. SRAM
510
  else if (addr_eep_dat) ram_i_node <= eep_dat_reg; // data from ext. PROM
511
  else if (addr_tmr0)    ram_i_node <= tmr0_reg;    // data from tmr0
512
  else if (addr_pcl)     ram_i_node <= pc_reg[7:0]; // data from pcl
513
  else if (addr_stat)    ram_i_node <= status_reg;  // data from status
514
  else if (addr_fsr)     ram_i_node <= fsr_reg;     // data from fsr
515
  else if (addr_porta)
516
  begin
517
    // Logic implements a 2:1 mux for each bit [4:0] of ram_i_node
518
    ram_i_node[4:0] <= (
519
                           (~trisa_reg[4:0] & porta_o_reg[4:0])
520
                        || ( trisa_reg[4:0] & porta_i_sync_reg[4:0])
521
                        );
522
    ram_i_node[7:5] <= 3'b0;
523
  end
524
  else if (addr_portb)
525
  begin
526
    // Logic implements a 2:1 mux for each bit [7:0] of ram_i_node
527
    ram_i_node[7:0] <= (
528
                           (~trisb_reg[7:0] & portb_o_reg[7:0])
529
                        || ( trisb_reg[7:0] & portb_i_sync_reg[7:0])
530
                        );
531
  end
532
  else if (addr_eep_adr) ram_i_node <= eep_adr_reg;       // from eeprom
533
  else if (addr_pclath)  ram_i_node <= {3'b0,pclath_reg}; // pclath (5bit)
534
  else if (addr_intcon)  ram_i_node <= intcon_reg;        // data from intcon
535
  else if (addr_option)  ram_i_node <= option_reg;        // data from option
536
  else if (addr_trisa)   ram_i_node <= {3'b0,trisa_reg};  // trisa (5bit)
537
  else if (addr_trisb)   ram_i_node <= trisb_reg;         // data from trisb
538
  else if (addr_eecon1)  ram_i_node <= {3'b0,eecon1_reg}; // eecon1 (5bit)
539
  else ram_i_node <= 0;
540
 
541
 
542
  // 1-2. PC + 1
543
  inc_pc_node  <= pc_reg + 1;
544
 
545
 
546
  // 1-3. Adder (ALU)
547
  // full 8bit-addition, with carry in/out.
548
  {add_node,temp}     <=    {1'b0,aluinp1_reg,1'b1}
549
                          + {1'b0,aluinp2_reg,c_in};
550
  // lower 4bit-addition
551
  {addlow_node,dtemp} <=    {1'b0,aluinp1_reg[3:0],1'b1}
552
                          + {1'b0,aluinp2_reg[3:0],c_in};
553
 
554
  // 1-4. Test if aluout = 0
555
  aluout_zero_node <= (aluout_reg == 0)?1:0;
556
 
557
  // 1-5. Determine destination
558
  if (intstart_reg)
559
  begin
560
    writew_node     <= 0;
561
    writeram_node   <= 0;
562
  end
563
  else if (inst_movwf || inst_bcf || inst_bsf || inst_clrf)
564
  begin
565
    writew_node     <= 0;
566
    writeram_node   <= 1;
567
  end
568
  else if (   inst_movlw || inst_addlw || inst_sublw || inst_andlw
569
           || inst_iorlw || inst_xorlw || inst_retlw || inst_clrw)
570
  begin
571
    writew_node     <= 1;
572
    writeram_node   <= 0;
573
  end
574
  else if (   inst_movf   || inst_swapf || inst_addwf || inst_subwf
575
           || inst_andwf  || inst_iorwf || inst_xorwf || inst_decf
576
           || inst_incf   || inst_rlf   || inst_rrf   || inst_decfsz
577
           || inst_incfsz || inst_comf)
578
  begin
579
    writew_node     <= ~inst_reg[7];  // ("d" field of fetched instruction)
580
    writeram_node   <=  inst_reg[7];  // ("d" field of fetched instruction)
581
  end
582
  else
583
  begin
584
    writew_node     <= 0;
585
    writeram_node   <= 0;
586
  end
587
 
588
  // 1-6. Interrupt request   (see pp.17 of PIC16F84 data sheet)
589
  int_node <= intcon_reg[7]        // GIE
590
              && (
591
                     (intcon_reg[3] && intcon_reg[0]) // RBIE,RBIF
592
                  || (intcon_reg[4] && intcon_reg[1]) // INTE,INTF
593
                  || (intcon_reg[5] && intcon_reg[2]) // T0IE,T0IF
594
                  || (intcon_reg[6] && eecon1_reg[4]) // EEIE,EEIF(EECON1)
595
                  );
596
 
597
  // 1-7. Reset conditions
598
  wdt_rst_node <= wdt_full_sync_reg[1] && ~wdt_full_sync_reg[2];  // WDT
599
 
600
  // (all of reset triggers)
601
  if (~poweron_sync_reg || ~mclr_sync_reg || wdt_rst_node) reset_cond  <= 1;
602
  else reset_cond  <= 0;
603
 
604
  // 2. EFSM body
605
  case (state_reg)
606
 
607
    // 2-1. Reset state (see pp.14 and pp.42 of PIC16F84 data sheet)
608
    QRESET_PP :
609
    begin
610
      pc_reg          <= 0;     // 0
611
      status_reg[7:5] <= 3'b0;
612
      pclath_reg      <= 0;     // 0
613
      intcon_reg[7:1] <= 7'b0;
614
      option_reg      <= -1;    // Set to all ones, like vhdl (others => 1)
615
      trisa_reg       <= -1;    // Set to all ones, like vhdl (others => 1)
616
      trisb_reg       <= -1;    // Set to all ones, like vhdl (others => 1)
617
      tmr0_reg        <= 0;     // (specification: don't care)
618
      exec_op_reg     <= 0;
619
      intclr_reg      <= -1;    // clear int
620
      intstart_reg    <= 0;
621
      writeram_reg    <= 0;
622
      sleepflag_reg   <= 0;
623
 
624
      // (set /T0 and /PD properly; see pp.42 and pp.46 of data sheet)
625
      // NOTE: Do NOT clear stack pointer for MCLR reset or WDT reset 
626
      if (~poweron_sync_reg)      // Power-on Reset
627
      begin
628
        status_reg[4] <= 1;       // /T0 = 1
629
        status_reg[3] <= 1;       // /PD = 1
630
        stack_pnt_reg <= 0;       // Reset stack pointer
631
      end
632
      else if (~mclr_sync_reg)    // MCLR reset/MCLR wake up from sleep
633
      begin
634
        status_reg[4]       <= 1;                  // /T0 = 1
635
        // /PD = 1 if normal reset, /PD = 0 if wake up
636
        status_reg[3]       <= ~sleepflag_reg;
637
      end
638
      else if (wdt_rst_node)    // WDT reset/WDT wake up from sleep
639
      begin
640
        status_reg[4]       <= 0;                  // /T0 = 0
641
        // /PD = 1 if normal reset, /PD = 0 if wake up
642
        status_reg[3]       <= ~sleepflag_reg;
643
      end
644
 
645
      // Most bits of eecon1 are set to zero.
646
      eecon1_reg[4]    <= 0;
647
      eecon1_reg[2:0]  <= 3'b0;
648
      // Except...
649
      // (set WRERR bit in EECON1 properly; 
650
      //  see pp.33 and pp.34 of data sheet)
651
      if (~poweron_sync_reg) eecon1_reg[3] <= 0; // clear WRERR
652
      else eecon1_reg[3] <= eecon1_reg[1];       // substitute WR into WRERR
653
 
654
      // go to Q1 state if reset signal is de-asserted
655
      if (~reset_cond) state_reg <= Q1_PP;
656
 
657
    end  // End of QRESET_PP state
658
 
659
 
660
    // 2-2. Q1 cycle
661
    Q1_PP :
662
    begin
663
      // 2-2-1. Clear external interrupt registers if GIE=0
664
      if (intcon_reg[7]) intclr_reg <= 0;
665
      else intclr_reg <= 1;     // clear interrupt
666
 
667
      // 2-2-2. Read I/O port
668
      porta_i_sync_reg    <= porta_i;
669
      portb_i_sync_reg    <= portb_i;
670
 
671
      // 2-2-3. Read/Write EEPROM, if necessary
672
      if (~intstart_reg)
673
      begin
674
        if (eecon1_reg[0] && rd_eep_sync_reg) // EEPROM read complete
675
        begin
676
          eep_dat_reg    <= eep_dat_i;
677
          eecon1_reg[0] <= 0;                 // clear EECON1_RD
678
        end
679
        if (eecon1_reg[1] && wr_eep_sync_reg) // writing EEPROM complete
680
        begin
681
          if (intcon_reg[7] && intcon_reg[6])
682
            eecon1_reg[4] <= 1;         // INT (EE write complete)
683
          eecon1_reg[1]   <= 0;         // clear EECON1_WR
684
        end
685
        if (exec_op_reg) ram_adr_reg <= ram_adr_node; // RAM read address
686
      end
687
 
688
      // 2-2-4. Check increment-TMR0 request
689
      if (inc_tmr_sync_reg == 2'b01) inc_tmr_hold_reg <= 1;
690
 
691
 
692
      // 2-2-5. Goto next cycle
693
      if (reset_cond) state_reg <= QRESET_PP;
694
      else
695
        // if in the sleep mode, wait until wake-up trigger comes
696
        if (sleepflag_reg && ~intstart_reg)
697
        begin
698
          if (inte_sync_reg || rbint_sync_reg)
699
          begin
700
          // if PORT-B interrupts come, then resume execution
701
          // otherwise, if WDT reset/MCLR reset comes, then goto QRESET_PP
702
            sleepflag_reg <= 0;
703
            state_reg     <= Q2_PP;
704
          end
705
        end
706
        // if not in sleep mode, or if stalled, continue execution
707
        else state_reg   <= Q2_PP;
708
 
709
    end   // End of Q1 state
710
 
711
    // 2-3. Q2 cycle
712
    Q2_PP :
713
    begin
714
      // 2-3-1. Read data-RAM and substitute source values to alu-input regs
715
      if (exec_op_reg && ~intstart_reg)  // if NOT STALLED
716
      begin
717
        // 2-3-1-1. Set aluinp1 register (source #1)
718
        if (   inst_movf   || inst_swapf || inst_addwf || inst_subwf
719
            || inst_andwf  || inst_iorwf || inst_xorwf || inst_decf
720
            || inst_incf   || inst_rlf   || inst_rrf   || inst_bcf
721
            || inst_bsf    || inst_btfsc || inst_btfss || inst_decfsz
722
            || inst_incfsz || inst_comf)
723
 
724
            aluinp1_reg <= ram_i_node;       // RAM/Special registers
725
        else
726
        if (   inst_movlw || inst_addlw || inst_sublw || inst_andlw
727
            || inst_iorlw || inst_xorlw || inst_retlw)
728
 
729
            aluinp1_reg <= inst_reg[7:0];    // Immediate value ("k")
730
        else
731
        if (   inst_clrf  || inst_clrw) aluinp1_reg <= 0; // 0
732
        else aluinp1_reg <= w_reg;                        // W register
733
 
734
        // 2-3-1-2. Set aluinp2 register (source #2)
735
        if      (inst_decf || inst_decfsz) aluinp2_reg <= -1; // for decr.
736
        else if (inst_incf || inst_incfsz) aluinp2_reg <=  1; // for incr.
737
                // -1 * W register (for subtract)
738
        else if (inst_sublw || inst_subwf) aluinp2_reg <= ~w_reg + 1;
739
                // operation of BCF: AND with inverted mask ("1..101..1")
740
                // mask for BCF: value of only one position is 0
741
        else if (inst_bcf) aluinp2_reg <= ~mask_node;
742
                // operation of BSF: OR with mask_node ("0..010..0")
743
                // operation of FSC and FSS: AND with mask_node, compare to 0
744
        else if (inst_btfsc || inst_btfss || inst_bsf)
745
                                      aluinp2_reg <= mask_node;
746
        else aluinp2_reg <= w_reg; // W register
747
 
748
        // 2-3-1-3. Set stack pointer register (pop stack)
749
        if (inst_ret || inst_retlw || inst_retfie)
750
             stack_pnt_reg   <= stack_pnt_reg - 1; // cycles 3,2,1,0,7,6...
751
 
752
        // 2-3-1-4. Set ram_adr register (set RAM write address)
753
        ram_adr_reg  <= ram_adr_node;     // RAM write address
754
      end
755
 
756
      // 2-3-2. Change clock output
757
      clk_o_reg  <= 1;
758
 
759
      // 2-3-3. Check increment-TMR0 request
760
      if (inc_tmr_sync_reg == 2'b01) inc_tmr_hold_reg <= 1;
761
 
762
      // 2-3-4. Goto next cycle
763
      if (reset_cond) state_reg <= QRESET_PP;
764
      else state_reg <= Q3_PP;
765
    end   // End of Q2 state
766
 
767
    // 2-4. Q3 cycle
768
    Q3_PP :
769
    begin
770
      // 2-4-1. Calculation and store result into alu-output register
771
      if (exec_op_reg && ~intstart_reg) // if NOT STALLED
772
      begin
773
        // 2-4-1-1. Set aluout register
774
                // Rotate left
775
        if      (inst_rlf)
776
                aluout_reg <= {aluinp1_reg[6:0],status_reg[0]};
777
                // Rotate right
778
        else if (inst_rrf)
779
                aluout_reg  <= {status_reg[0],aluinp1_reg[7:1]};
780
                // Swap nibbles
781
        else if (inst_swapf)
782
                aluout_reg <= {aluinp1_reg[3:0],aluinp1_reg[7:4]};
783
                // Logical inversion
784
        else if (inst_comf)
785
                aluout_reg  <= ~aluinp1_reg;
786
                // Logical AND, bit clear/bit test
787
        else if (   inst_andlw || inst_andwf || inst_bcf || inst_btfsc
788
                 || inst_btfss)
789
                aluout_reg  <= (aluinp1_reg & aluinp2_reg);
790
                // Logical OR, bit set
791
        else if (inst_bsf || inst_iorlw || inst_iorwf)
792
                aluout_reg  <= (aluinp1_reg | aluinp2_reg);
793
                // Logical XOR
794
        else if (inst_xorlw || inst_xorwf)
795
                aluout_reg  <= (aluinp1_reg ^ aluinp2_reg);
796
                // Addition, Subtraction, Increment, Decrement
797
        else if (  inst_addlw || inst_addwf  || inst_sublw || inst_subwf
798
                 || inst_decf || inst_decfsz || inst_incf  || inst_incfsz)
799
                aluout_reg  <= add_node[7:0];
800
                // Pass through
801
        else aluout_reg  <= aluinp1_reg;
802
 
803
        // 2-4-1-2. Set C flag and DC flag
804
        if (inst_addlw || inst_addwf || inst_sublw || inst_subwf)
805
        begin
806
          status_reg[1]   <= addlow_node[4];          // DC flag
807
          status_reg[0]   <= add_node[8];             // C flag
808
        end
809
        else if (inst_rlf) status_reg[0] <= aluinp1_reg[7];  // C flag
810
        else if (inst_rrf) status_reg[0] <= aluinp1_reg[0];  // C flag
811
 
812
        // 2-4-1-3. Set data-SRAM write enable (hazard-free)
813
        if (writeram_node && addr_sram) writeram_reg <= 1;
814
        else writeram_reg <= 0;
815
 
816
      end
817
      else writeram_reg <= 0; // If stalled
818
 
819
      // 2-4-2. Check external interrupt and set int. flag,  Incr. TMR0
820
      if (~intstart_reg && intcon_reg[7]) // GIE
821
      begin
822
        // PORT-B0 INT
823
        if (inte_sync_reg)
824
        begin
825
          intcon_reg[1] <= 1;     // set INTF
826
          intclr_reg[0] <= 1;     // clear external int-registers 
827
                                  // (intrise_reg(0) and intdown_reg(0))
828
        end
829
        // PORT-B[4-7] INT
830
        if (rbint_sync_reg)
831
        begin
832
          intcon_reg[0]   <= 1;   // set RBIF
833
          intclr_reg[4:1] <= -1;  // clear external int-registers 
834
                                  // (intrise_reg(4-1) and intdown_reg(4-1))
835
        end
836
      end
837
 
838
      // Increment TMR0
839
      if (inc_tmr_hold_reg || (inc_tmr_sync_reg == 2'b01)) // incr. trigger
840
      begin
841
        tmr0_reg          <= tmr0_reg + 1;   // increment
842
        inc_tmr_hold_reg  <= 0;
843
 
844
        // if ~intstart and GIE and T0IE and timer full, then set T0IF
845
        if (
846
               ~intstart_reg
847
            && intcon_reg[7]
848
            && intcon_reg[5]
849
            && (tmr0_reg == -1)
850
            )
851
              intcon_reg[2] <= 1;             // set T0IF
852
      end
853
 
854
      // 2-4-3. Goto next cycle
855
      if (reset_cond) state_reg   <= QRESET_PP;
856
      else            state_reg   <= Q4_PP;
857
 
858
    end    // End of Q3 state
859
 
860
 
861
    // 2-5. Q4 cycle
862
    Q4_PP :
863
    begin
864
      // 2-5-1. Fetch next program-instruction
865
      inst_reg    <= prog_dat_i;
866
 
867
      if (~exec_op_reg && ~intstart_reg)      // if STALLED
868
      begin
869
        pc_reg          <= inc_pc_node; // increment PC
870
        exec_op_reg     <= 1;           // end of stall
871
      end
872
      else  // if NOT stalled 
873
      begin
874
        // (note: if intstart_reg, only stack/pc-operations in this 
875
        //        else-clause will be performed)
876
        // 2-5-2. Store calculation result into distination, 
877
        // set PC and flags, and determine if execute next cycle.
878
 
879
        // 2-5-2-1. Set W register, if not in stall cycle 
880
        //          (~intstart_reg) and distination is W
881
 
882
        // writew_node == 0 if intstart_reg...
883
        if (writew_node) w_reg   <= aluout_reg;    // write W reg
884
 
885
        // 2-5-2-2. Set data RAM/special registers,
886
        // if not in stall cycle (~intstart_reg)
887
        if (writeram_node)
888
        begin
889
          if (addr_stat)
890
          begin
891
            status_reg[7:5] <= aluout_reg[7:5];      // write IRP,RP1,RP0
892
            // status(4),status(3)...unwritable, see below (/PD,/T0 part)
893
            status_reg[1:0] <= aluout_reg[1:0];      // write DC,C
894
          end
895
          if (addr_fsr)         fsr_reg <= aluout_reg;      // write FSR
896
          if (addr_porta)   porta_o_reg <= aluout_reg[4:0]; // write PORT-A
897
          if (addr_portb)   portb_o_reg <= aluout_reg;      // write PORT-B
898
          if (addr_eep_dat) eep_dat_reg <= aluout_reg;      // write EEDATA
899
          if (addr_eep_adr) eep_adr_reg <= aluout_reg;      // write EEADR
900
          if (addr_pclath)   pclath_reg <= aluout_reg[4:0]; // write PCLATH
901
          if (addr_intcon) intcon_reg[6:0] <= aluout_reg[6:0];
902
                           // write INTCON (except GIE)
903
                           // intcon(7)...see below (GIE part)
904
          if (addr_option)   option_reg <= aluout_reg;      // write OPTION
905
          if (addr_trisa)     trisa_reg <= aluout_reg[4:0]; // write TRISA
906
          if (addr_trisb)     trisb_reg <= aluout_reg;      // write TRISB
907
          if (addr_tmr0)       tmr0_reg <= aluout_reg;      // write TMR0
908
          if (addr_eecon1)                                  // write EECON1
909
          begin
910
            eecon1_reg[4:3] <= aluout_reg[4:3];
911
            eecon1_reg[2]   <= aluout_reg[2] && existeeprom_i;
912
            // (WREN can be set only when EEPROM exists)
913
            if (aluout_reg[2:0] == 3'b110) eecon1_reg[1]   <= 1;
914
            // WR: only SET-operation is allowed to user
915
            // if write enabled, write bit, and no current read
916
            if (aluout_reg[1:0] == 2'b01) eecon1_reg[0]   <= 1;
917
            // RD: only SET-operation is allowed to user
918
            // if no current write, and read bit
919
          end
920
        end
921
 
922
        // 2-5-2-3. Set/clear Z flag, if not in stall cycle (~intstart_reg)
923
        if (~intstart_reg)
924
        begin
925
          if (addr_stat) status_reg[2] <= aluout_reg[2]; // (dest. is Z flag)
926
          else if (   inst_addlw || inst_addwf || inst_andlw || inst_andwf
927
                   || inst_clrf  || inst_clrw  || inst_comf  || inst_decf
928
                   || inst_incf  || inst_movf  || inst_sublw || inst_subwf
929
                   || inst_xorlw || inst_xorwf)
930
                  status_reg[2] <= aluout_zero_node; // Z=1 if result == 0
931
          else if (inst_iorlw || inst_iorwf)
932
                  // SELECT ONE OF THE FOLLOWING TWO SENTENCES
933
                                                                                // IORLW or IORWF instructions:
934
                  status_reg[2] <= ~aluout_zero_node;
935
                  // Z=1 if result != 0 (PIC16F84 data sheet pp.61-62)
936
              //  status_reg[2] <= aluout_zero_node;                
937
                  // Z=1 if result == 0 (same as the other instructions)
938
        end
939
 
940
        // 2-5-2-4. Set PC and determine whether to execute next cycle or not
941
        // After interrupt-stall cycle ends, jump to interrupt vector
942
        if (intstart_reg)
943
        begin
944
          pc_reg      <= 4;     // (interrupt vector)
945
          exec_op_reg <= 0;     // the next cycle is a stall cycle
946
        end
947
        else if (inst_ret || inst_retlw || inst_retfie) // "return" instr.
948
        begin
949
          pc_reg      <= stack_reg[stack_pnt_reg];
950
          exec_op_reg <= 0;              // the next cycle is stall cycle
951
        end
952
        else if (inst_goto || inst_call) // "goto/call" instructions
953
        begin
954
          // (see pp.18 of PIC16F84 data sheet)
955
          pc_reg      <= {pclath_reg[4:3],inst_reg[10:0]};
956
          exec_op_reg <= 0;
957
        end
958
        else if ( (   (inst_btfsc || inst_decfsz || inst_incfsz)
959
                       && aluout_zero_node)
960
                   || (inst_btfss && ~aluout_zero_node)
961
                   ) // bit_test instrcutions
962
        begin
963
          pc_reg      <= inc_pc_node;
964
          exec_op_reg <= 0;
965
          // the next cycle is stall cycle, if test conditions are met.
966
        end
967
        else if (writeram_node && addr_pcl) // PCL is data-destination
968
        begin
969
          // (see pp.18 of PIC16F84 data sheet)
970
          pc_reg      <= pclath_reg[4:0] & aluout_reg;
971
          exec_op_reg <= 0;
972
        end
973
        else
974
        begin
975
          // this check MUST be located AFTER the above if/else sentences
976
          // check if interrupt trigger comes
977
          if (~int_node) pc_reg <= inc_pc_node;
978
          // if not, the next instr. fetch/exec. will be performed normally
979
          else pc_reg <= pc_reg;
980
          // if so, value of PC must be held 
981
          //(will be pushed onto stack at the end of next instruction cycle)
982
          exec_op_reg <= 1;
983
        end
984
 
985
        // 2-5-2-5. Push current PC value into stack, if necessary
986
        if (inst_call || intstart_reg)
987
        // CALL instr. or End of interrupt-stall cycle
988
        begin
989
          stack_reg[stack_pnt_reg] <= pc_reg;  // write PC value
990
          stack_pnt_reg <= stack_pnt_reg + 1;  // increment stack pointer
991
        end
992
 
993
        // 2-5-2-6. Set GIE bit in intcon register (intcon_reg(7))
994
        if (~intstart_reg)
995
        begin
996
          if (int_node) // interrupt trigger comes
997
          begin
998
            intcon_reg[7] <= 0; // clear GIE
999
            intstart_reg  <= 1; // the next cycle is interrupt-stall cycle
1000
          end
1001
          else if (inst_retfie) // "return from interrupt" instruction
1002
          begin
1003
            intcon_reg[7] <= 1;
1004
            intstart_reg  <= 0;
1005
          end
1006
          else if (writeram_node && addr_intcon) // destination is GIE
1007
          begin
1008
            intcon_reg[7] <= aluout_reg[7];
1009
            intstart_reg  <= 0;
1010
          end
1011
          else intstart_reg <= 0;
1012
        end
1013
        else intstart_reg <= 0;
1014
 
1015
        // 2-5-2-7. Set/clear /PD and /TO flags
1016
        if (~intstart_reg)
1017
          if (    inst_clrwdt
1018
              || (inst_sleep && (~wdt_rst_node && ~intstart_reg)) )
1019
              // CLRWDT or (SLEEP and no interrupt trigger)
1020
              // see pp.46,58 and 66 of PIC16F84 data-sheet
1021
             if (inst_sleep)
1022
             begin
1023
               sleepflag_reg <= 1;
1024
               status_reg[4:3] <= 2'b10;    // SLEEP: /T0,/PD = 1,0
1025
             end
1026
             else status_reg[4:3] <= 2'b11; // CLRWDT: /T0,/PD = 1,1
1027
 
1028
      end // (if not stalled)
1029
 
1030
      // 2-5-3. Clear data-SRAM write enable (hazard-free)
1031
      writeram_reg <= 0;
1032
 
1033
      // 2-5-4. Change clock output
1034
      clk_o_reg <= 0;
1035
 
1036
      // 2-5-5. Check increment-TMR0 request
1037
      if (inc_tmr_sync_reg == 2'b01) inc_tmr_hold_reg  <= 1;
1038
 
1039
      // 2-5-6. Goto next cycle
1040
      if (reset_cond) state_reg   <= QRESET_PP;
1041
      else state_reg   <= Q1_PP;
1042
    end    // End of Q4 state
1043
 
1044
    // 2-6. Illegal states (NEVER REACHED in normal execution)
1045
    default : state_reg   <= QRESET_PP;      // goto reset state
1046
    endcase
1047
end  // End of process
1048
 
1049
 
1050
// TMR0 pre-scaler (see pp.27 of PIC16F84 data sheet)
1051
// select pre-scaler
1052
assign ps_clk = option_reg[5]?(t0cki_i ^ option_reg[4]):clk_o_reg;
1053
// option_reg(5):T0CS
1054
// option_reg(4):T0SE
1055
 
1056
// pre-scaler body
1057
always @(posedge ps_clk or negedge pon_rst_n_i)
1058
begin
1059
  if (~pon_rst_n_i)
1060
  begin
1061
    pscale_reg  <= 0;
1062
    ps_full_reg <= 0;
1063
  end
1064
  else // Must be ps_clk rising edge...
1065
  begin
1066
    case (option_reg[2:0])  // select prescaler-full value by PS2-0
1067
      3'b000 : rateval <= 1;
1068
      3'b001 : rateval <= 3;
1069
      3'b010 : rateval <= 7;
1070
      3'b011 : rateval <= 15;
1071
      3'b100 : rateval <= 31;
1072
      3'b101 : rateval <= 63;
1073
      3'b110 : rateval <= 127;
1074
      3'b111 : rateval <= 255;
1075
      default: rateval <= 1;
1076
    endcase
1077
 
1078
    if (pscale_reg >= rateval)
1079
    begin
1080
      pscale_reg  <= 0;
1081
      ps_full_reg <= 1;
1082
    end
1083
    else
1084
    begin
1085
      pscale_reg  <= pscale_reg + 1;
1086
      ps_full_reg <= 0;
1087
    end
1088
  end
1089
end //process
1090
 
1091
// select TMR0-increment trigger
1092
assign inc_tmr_clk =  option_reg[3]?ps_clk:ps_full_reg;
1093
// option_reg(3):PSA
1094
// ps_full_reg:output of pre-scaler
1095
 
1096
 
1097
assign wdt_init = ~pon_rst_n_i || ~mclr_n_i;
1098
// WDT timer body
1099
always @(posedge wdt_clk_i or posedge wdt_init)
1100
begin
1101
  if (wdt_init) // (async reset)
1102
  begin
1103
    wdt_reg              <= 0;
1104
    wdt_full_reg         <= 0;
1105
    wdt_clr_req_reg      <= 2'b0;
1106
    wdt_fullclr_req_reg  <= 2'b0;
1107
  end
1108
  else // Must be posedge wdt_clk_i at this point...
1109
  begin
1110
    // synchronizers
1111
    // WDT-clear request (CLRWDT/SLEEP instruction)
1112
    // (do not AND with sleepflag_reg, since WDT should be 
1113
    //  cleared at SLEEP instruction)
1114
    wdt_clr_req_reg[0]     <= wdt_clr_reg;
1115
    wdt_clr_req_reg[1]     <= wdt_clr_req_reg[0];
1116
    // WDT-full-clear request (after WDT reset)
1117
    wdt_fullclr_req_reg[0] <= wdt_full_clr_reg && ~sleepflag_reg;
1118
    wdt_fullclr_req_reg[1] <= wdt_fullclr_req_reg[0];
1119
 
1120
    // timer/full reg
1121
    if (wdt_reg >= WDT_SIZE_PP) wdt_full_node <= 1;  // (intermediate node)
1122
    else wdt_full_node    <= 0;     // (intermediate node)
1123
 
1124
    // wdt_reg(counter) body
1125
    if ((wdt_clr_req_reg == 2'b01) || ~wdt_ena_i) wdt_reg <= 0;
1126
    else if (wdt_full_node) wdt_reg <= 0;
1127
    else wdt_reg <= wdt_reg + 1;
1128
 
1129
    // wdt_full_reg(interrupt trigger) body
1130
    if ((wdt_fullclr_req_reg == 2'b01) || ~wdt_ena_i) wdt_full_reg <= 0;
1131
    else if (wdt_full_node) wdt_full_reg <= 1;
1132
  end
1133
end // process
1134
assign wdt_clr_ack = wdt_clr_req_reg[1]; // WDT-clear ack signal to CPU
1135
assign wdt_full_o = wdt_full_reg;        // WDT-full int. trigger to CPU
1136
 
1137
 
1138
// WDT controller in CPU-clock line 
1139
// (handshake-interface between WDT and CPU-EFSM)
1140
always @(posedge clk_i)
1141
begin
1142
  if (~poweron_sync_reg || ~mclr_sync_reg)
1143
  begin
1144
    wdt_clr_reg         <= 0; // WDT clear request register
1145
    wdt_clr_reqhold_reg <= 0; // 1 when WDT clear request comes while another
1146
                              //   clear request is still being processed.
1147
    wdt_full_clr_reg    <= 0; // WDT-full clear request register
1148
  end
1149
  else
1150
  begin
1151
    // WDT-clear/hold WDT-clear request
1152
    // (handshake)
1153
    if (wdt_clr_reg) // still processing clear-operation
1154
      // if ack comes, take down the clear request
1155
      if (wdt_clr_ack_sync_reg) wdt_clr_reg <= 0;
1156
    else if (    wdt_clr_reqhold_reg
1157
             || ( (state_reg == Q4_PP)
1158
                   && exec_op_reg && ~intstart_reg
1159
                   && (inst_clrwdt || inst_sleep)) ) // clear request comes
1160
    begin
1161
      if (~wdt_clr_ack_sync_reg) // confirm if ack is 0
1162
      begin
1163
        wdt_clr_reg         <= 1;
1164
        wdt_clr_reqhold_reg <= 0;
1165
      end
1166
        // (wait until ack becomes 0)
1167
//      else wdt_clr_reqhold_reg <= 1;  NOTE: This line is "never reached!"
1168
    end
1169
 
1170
    // clear WDT-full (CPU reset request)
1171
    // (handshake)
1172
    if (wdt_full_clr_reg) wdt_full_clr_reg <= wdt_full_sync_reg[1];
1173
  end
1174
end // process
1175
 
1176
 
1177
assign intclr0 = intclr_reg[0];
1178
assign intclr1 = intclr_reg[1];
1179
assign intclr2 = intclr_reg[2];
1180
assign intclr3 = intclr_reg[3];
1181
assign intclr4 = intclr_reg[4];
1182
 
1183
// Detect external interrupt requests
1184
// INT0 I/F
1185
always @(posedge int0_i or posedge intclr0)
1186
begin
1187
  if (intclr0) intrise_reg[0]  <= 0;
1188
  else intrise_reg[0] <= 1; // catch positive edge
1189
end // process
1190
 
1191
always @(negedge int0_i or posedge intclr0)
1192
begin
1193
  if (intclr0) intdown_reg[0] <= 0;
1194
  else intdown_reg[0]  <= 1; // catch negative edge
1195
end // process
1196
assign rb0_int = option_reg[6]?intrise_reg[0]:intdown_reg[0];
1197
 
1198
// INT4 I/F
1199
always @(posedge int4_i or posedge intclr1)
1200
begin
1201
  if (intclr1) intrise_reg[1]  <= 0;
1202
  else intrise_reg[1] <= 1; // catch positive edge
1203
end // process
1204
 
1205
always @(negedge int4_i or posedge intclr1)
1206
begin
1207
  if (intclr1) intdown_reg[1] <= 0;
1208
  else intdown_reg[1]  <= 1; // catch negative edge
1209
end // process
1210
assign rb4_int = intrise_reg[1] || intdown_reg[1];
1211
 
1212
// INT5 I/F
1213
always @(posedge int5_i or posedge intclr2)
1214
begin
1215
  if (intclr2) intrise_reg[2]  <= 0;
1216
  else intrise_reg[2] <= 1; // catch positive edge
1217
end // process
1218
 
1219
always @(negedge int5_i or posedge intclr2)
1220
begin
1221
  if (intclr2) intdown_reg[2] <= 0;
1222
  else intdown_reg[2]  <= 1; // catch negative edge
1223
end // process
1224
assign rb5_int = intrise_reg[2] || intdown_reg[2];
1225
 
1226
// INT6 I/F
1227
always @(posedge int6_i or posedge intclr3)
1228
begin
1229
  if (intclr3) intrise_reg[3]  <= 0;
1230
  else intrise_reg[3] <= 1; // catch positive edge
1231
end // process
1232
 
1233
always @(negedge int7_i or posedge intclr3)
1234
begin
1235
  if (intclr3) intdown_reg[3] <= 0;
1236
  else intdown_reg[3]  <= 1; // catch negative edge
1237
end // process
1238
assign rb6_int = intrise_reg[3] || intdown_reg[3];
1239
 
1240
// INT7 I/F
1241
always @(posedge int7_i or posedge intclr4)
1242
begin
1243
  if (intclr4) intrise_reg[4]  <= 0;
1244
  else intrise_reg[4] <= 1; // catch positive edge
1245
end // process
1246
 
1247
always @(negedge int7_i or posedge intclr4)
1248
begin
1249
  if (intclr4) intdown_reg[4] <= 0;
1250
  else intdown_reg[4]  <= 1; // catch negative edge
1251
end // process
1252
assign rb7_int = intrise_reg[4] || intdown_reg[4];
1253
 
1254
 
1255
// Decode INT triggers 
1256
// (do not AND with GIE(intcon_reg(7)), since these signals are 
1257
//  also used for waking up from SLEEP)
1258
assign inte  = intcon_reg[4] && rb0_int;                                       // G0IE and raw-trigger signal
1259
assign rbint = intcon_reg[3] && (rb4_int || rb5_int || rb6_int || rb7_int);    // RBIE and raw-trigger signal
1260
 
1261
// Circuit's output signals
1262
assign prog_adr_o   = pc_reg;        // program ROM address
1263
assign ram_adr_o    = ram_adr_reg;   // data RAM address
1264
assign ram_dat_o    = aluout_reg;    // data RAM write data
1265
assign readram_o    = (state_reg[1:0] == Q2_PP[1:0]); // data RAM read enable 
1266
                                                //(1 when state_reg = Q2_PP)
1267
assign writeram_o   = writeram_reg;  // data RAM write enable
1268
 
1269
assign eep_adr_o    = eep_adr_reg;   // EEPROM address
1270
assign eep_dat_o    = eep_dat_reg;   // EEPROM write data
1271
assign rd_eep_req_o = eecon1_reg[0]; // EEPROM read request
1272
assign wr_eep_req_o = eecon1_reg[1]; // EEPROM write request
1273
 
1274
assign porta_o      = porta_o_reg;   // PORT-A output
1275
assign porta_dir_o  = trisa_reg;     // PORT-A direction
1276
 
1277
assign portb_o      = portb_o_reg;   // PORT-B output
1278
assign portb_dir_o  = trisb_reg;     // PORT-B direction
1279
assign rbpu_o       = option_reg[7]; // RBPU: pull-up enable
1280
 
1281
assign clk_o        = clk_o_reg;     // clock (clk_i/4) output
1282
 
1283
assign powerdown_o  = sleepflag_reg;                                                       // CPU clock stop indicator
1284
assign startclk_o   = inte || rbint || wdt_full_reg
1285
                      || ~mclr_n_i || ~pon_rst_n_i;
1286
                     // CPU clock start indicator
1287
 
1288
 
1289
endmodule
1290
 
1291
 
1292
//`undef STATEBIT_SIZE

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.