| /* ssem_cpu.c: SSEM (Small Scale Experimental Machine) CPU simulator |
| |
| Based on the SIMH package written by Robert M Supnik |
| |
| Copyright (c) 2006-2013, Gerardo Ospina |
| |
| Permission is hereby granted, free of charge, to any person obtaining a |
| copy of this software and associated documentation files (the "Software"), |
| to deal in the Software without restriction, including without limitation |
| the rights to use, copy, modify, merge, publish, distribute, sublicense, |
| and/or sell copies of the Software, and to permit persons to whom the |
| Software is furnished to do so, subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be included in |
| all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
| THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
| |
| Except as contained in this notice, the name of the author shall not be |
| used in advertising or otherwise to promote the sale, use or other dealings |
| in this Software without prior written authorization from the author. |
| |
| This is not a supported product, but the author welcomes bug reports and fixes. |
| Mail to ngospina@gmail.com |
| |
| cpu SSEM CPU |
| |
| The system state for the SSEM is: |
| |
| A[0]<0:31> accumulator |
| C[0]<0:31> current instruction |
| C[1]<0:31> present instruction |
| |
| The SSEM has just one instruction format: |
| |
| 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 |
| 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| | |inst | |address | |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| |
| SSEM instructions: |
| |
| <13:15> operation |
| |
| 000 0 C[0] <- S[n] |
| 001 1 C[0] <- C[0] + S[n] |
| 010 2 A[0] <- -S[n] |
| 011 3 S[n] <- A[0] |
| 100 4 A[0] <- A[0] - S[n] |
| 110 6 C[0] <- C[0] + 1 if (A[0] < 0) |
| 111 7 Stop the machine |
| |
| The SSEM has 32 32b words of memory. |
| |
| This routine is the instruction decode routine for the SSEM. |
| It is called from the simulator control program to execute |
| instructions in simulated memory, starting at the simulated |
| CI. It runs until 'reason' is set non-zero. |
| |
| General notes: |
| |
| 1. Reasons to stop. The simulator can be stopped by: |
| |
| Stop instruction |
| breakpoint encountered |
| |
| 2. Interrupts. There are no interrupts. |
| |
| 3. Non-existent memory. All of memory always exists. |
| |
| 4. Adding I/O devices. The SSEM could not support additional |
| I/O devices. |
| */ |
| |
| #include "ssem_defs.h" |
| |
| uint32 S[MEMSIZE] = { 0 }; /* storage (memory) */ |
| |
| int32 A[MEMSIZE] = { 0 }; /* A[0] accumulator */ |
| uint32 C[MEMSIZE] = { 0, 0 }; /* C[0] current instruction */ |
| /* C[1] present instruction */ |
| uint32 Staticisor = 0; |
| |
| extern int32 sim_interval; |
| extern uint32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ |
| extern int32 sim_step; |
| |
| t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); |
| t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); |
| t_stat cpu_reset (DEVICE *dptr); |
| t_stat cpu_one_inst (uint32 opc, uint32 ir); |
| |
| /* CPU data structures |
| |
| cpu_dev CPU device descriptor |
| cpu_unit CPU unit descriptor |
| cpu_reg CPU register list |
| cpu_mod CPU modifiers list |
| */ |
| |
| UNIT cpu_unit = { UDATA (NULL, UNIT_FIX, MEMSIZE) }; |
| |
| REG cpu_reg[] = { |
| { DRDATA (CI, C[0], 5), REG_VMAD }, |
| { HRDATA (A, A[0], 32), REG_VMIO }, |
| { HRDATA (PI, C[1], 32), REG_VMIO + REG_HRO }, |
| { HRDATA (LF, Staticisor, 32), REG_VMIO + REG_HRO }, |
| { NULL } |
| }; |
| |
| MTAB cpu_mod[] = { |
| { UNIT_SSEM, 0, "Manchester SSEM (Small Scale Experimental Machine)", "SSEM" }, |
| { 0 } |
| }; |
| |
| DEVICE cpu_dev = { |
| "CPU", &cpu_unit, cpu_reg, cpu_mod, |
| 1, 10, 5, 1, 16, 32, |
| &cpu_ex, &cpu_dep, &cpu_reset, |
| NULL, NULL, NULL |
| }; |
| |
| t_stat sim_instr (void) |
| { |
| t_stat reason = 0; |
| |
| sim_cancel_step (); /* defang SCP step */ |
| |
| /* Main instruction fetch/decode loop */ |
| do { |
| |
| if (sim_interval <= 0) { /* check clock queue */ |
| #if !UNIX_PLATFORM |
| if ((reason = sim_poll_kbd()) == SCPE_STOP) { /* poll on platforms without reliable signalling */ |
| break; |
| } |
| #endif |
| if (reason = sim_process_event ()) break; |
| } |
| |
| if (sim_brk_summ && /* breakpoint? */ |
| sim_brk_test (*C, SWMASK ('E'))) { |
| reason = STOP_IBKPT; /* stop simulation */ |
| break; |
| } |
| |
| /* Increment current instruction */ |
| *C = (*C + 1) & AMASK; |
| |
| /* Get present instruction */ |
| C[1] = Read (*C); |
| |
| Staticisor = C[1] & IMASK; /* get instruction */ |
| sim_interval = sim_interval - 1; |
| |
| if (reason = cpu_one_inst (*C, Staticisor)) { /* one instr; error? */ |
| break; |
| } |
| |
| if (sim_step && (--sim_step <= 0)) /* do step count */ |
| reason = SCPE_STOP; |
| |
| } while (reason == 0); /* loop until halted */ |
| |
| return reason; |
| } |
| |
| t_stat cpu_reset (DEVICE *dptr) |
| { |
| sim_brk_types = sim_brk_dflt = SWMASK ('E'); |
| return SCPE_OK; |
| } |
| |
| /* Memory examine */ |
| |
| t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) |
| { |
| if (addr >= MEMSIZE) return SCPE_NXM; |
| if (vptr != NULL) *vptr = Read (addr); |
| return SCPE_OK; |
| } |
| |
| /* Memory deposit */ |
| |
| t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) |
| { |
| if (addr >= MEMSIZE) return SCPE_NXM; |
| Write (addr, val); |
| return SCPE_OK; |
| } |
| |
| /* Execute one instruction */ |
| |
| t_stat cpu_one_inst (uint32 opc, uint32 ir) |
| { |
| uint32 ea, op; |
| t_stat reason = 0; |
| |
| op = I_GETOP (ir); /* opcode */ |
| switch (op) { /* case on opcode */ |
| |
| case OP_JUMP_INDIRECT: /* C[0] <- S[ea] */ |
| ea = I_GETEA (ir); /* address */ |
| *C = Read(ea); |
| break; |
| |
| case OP_JUMP_INDIRECT_RELATIVE: /* C[0] <- C[0] + S[ea] */ |
| ea = I_GETEA (ir); /* address */ |
| *C += Read(ea); |
| break; |
| |
| case OP_LOAD_NEGATED: /* A[0] <- -S[ea] */ |
| ea = I_GETEA (ir); /* address */ |
| *A = -((int32)Read(ea)); |
| break; |
| |
| case OP_STORE: /* S[ea] <- A[0] */ |
| ea = I_GETEA (ir); /* address */ |
| Write(ea, (uint32) *A); |
| break; |
| |
| case OP_SUBSTRACT: /* A[0] <- A[0] - S[ea] */ |
| case OP_UNDOCUMENTED: |
| ea = I_GETEA (ir); /* address */ |
| *A -= ((int32) Read(ea)); |
| break; |
| |
| case OP_TEST: /* C[0] <- C[0] + 1 if (A[0] < 0) */ |
| if (*A < 0){ |
| *C += 1; |
| } |
| break; |
| |
| case OP_STOP: /* Stop the machine */ |
| reason = STOP_STOP; /* stop simulation */ |
| break; |
| } /* end switch */ |
| |
| return reason; |
| } |
| |
| /* Support routines */ |
| |
| uint32 Read (uint32 ea) |
| { |
| return S[ea] & MMASK; |
| } |
| |
| void Write (uint32 ea, uint32 dat) |
| { |
| S[ea] = dat & MMASK; |
| return; |
| } |