Skip to content

Commit 78ce635

Browse files
committed
add support for SWI
1 parent bb97ae5 commit 78ce635

File tree

11 files changed

+259
-77
lines changed

11 files changed

+259
-77
lines changed

.github/workflows/gba.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ jobs:
7575
- arm_ldrh_strh
7676
- arm_ldrsb_ldrsh
7777
- arm_b_bl
78+
- arm_swi
7879

7980
steps:
8081
- uses: actions/checkout@v4
Binary file not shown.
13.2 KB
Binary file not shown.

cores/gba/rtl/cpu/CPU.sv

Lines changed: 52 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ module CPU (
1212
Bus_if.Master_side bus
1313
);
1414

15-
/// TODO: Remove
1615
control_t control_signals;
1716

1817
word_t IR;
@@ -31,26 +30,40 @@ module CPU (
3130
word_t read_data;
3231

3332
always_comb begin
34-
unique casez (regs.CPSR[4:0])
35-
36-
5'b0??00: cpu_mode = MODE_USR; // Old User
37-
5'b0??01: cpu_mode = MODE_FIQ; // Old FIQ
38-
5'b0??10: cpu_mode = MODE_IRQ; // Old IRQ
39-
5'b0??11: cpu_mode = MODE_SVC; // Old Supervisor
40-
41-
5'b10000: cpu_mode = MODE_USR; // User
42-
5'b10001: cpu_mode = MODE_FIQ; // FIQ
43-
5'b10010: cpu_mode = MODE_IRQ; // IRQ
44-
5'b10011: cpu_mode = MODE_SVC; // Supervisor
45-
5'b10111: cpu_mode = MODE_ABT; // Abort
46-
5'b11011: cpu_mode = MODE_UND; // Undefined
47-
5'b11111: cpu_mode = MODE_SYS; // System
48-
49-
default: begin
50-
cpu_mode = MODE_USR;
51-
$warning("Illegal CPSR mode encoding: %b", regs.CPSR[4:0]);
52-
end
53-
endcase
33+
if (control_signals.exception != EXCEPTION_NONE) begin
34+
// TODO: think about combining with `update_cspr_mode`
35+
unique case (control_signals.exception)
36+
EXCEPTION_NONE: cpu_mode = CPU_MODE_USR; // Impossible to reach
37+
EXCEPTION_RESET: cpu_mode = CPU_MODE_USR; // TODO;
38+
EXCEPTION_UNDEFINED: cpu_mode = CPU_MODE_UND;
39+
EXCEPTION_SWI: cpu_mode = CPU_MODE_SVC;
40+
EXCEPTION_PABT: cpu_mode = CPU_MODE_ABT;
41+
EXCEPTION_DABT: cpu_mode = CPU_MODE_ABT;
42+
EXCEPTION_IRQ: cpu_mode = CPU_MODE_IRQ;
43+
EXCEPTION_FIQ: cpu_mode = CPU_MODE_FIQ;
44+
endcase
45+
end else begin
46+
unique casez (regs.CPSR[4:0])
47+
48+
5'b0??00: cpu_mode = CPU_MODE_USR; // Old User
49+
5'b0??01: cpu_mode = CPU_MODE_FIQ; // Old FIQ
50+
5'b0??10: cpu_mode = CPU_MODE_IRQ; // Old IRQ
51+
5'b0??11: cpu_mode = CPU_MODE_SVC; // Old Supervisor
52+
53+
5'b10000: cpu_mode = CPU_MODE_USR; // User
54+
5'b10001: cpu_mode = CPU_MODE_FIQ; // FIQ
55+
5'b10010: cpu_mode = CPU_MODE_IRQ; // IRQ
56+
5'b10011: cpu_mode = CPU_MODE_SVC; // Supervisor
57+
5'b10111: cpu_mode = CPU_MODE_ABT; // Abort
58+
5'b11011: cpu_mode = CPU_MODE_UND; // Undefined
59+
5'b11111: cpu_mode = CPU_MODE_SYS; // System
60+
61+
default: begin
62+
cpu_mode = CPU_MODE_USR;
63+
$warning("Illegal CPSR mode encoding: %b", regs.CPSR[4:0]);
64+
end
65+
endcase
66+
end
5467
end
5568

5669
Decoder_if decoder_bus (
@@ -195,7 +208,7 @@ module CPU (
195208
B_BUS_SRC_REG_RP: begin
196209
$display("Driving B bus with value from Rp (R%0d): %0d", control_signals.Rp_imm, read_reg(
197210
regs, cpu_mode, control_signals.Rp_imm));
198-
B_bus = read_reg(regs, control_signals.force_user_mode ? MODE_USR : cpu_mode,
211+
B_bus = read_reg(regs, control_signals.force_user_mode ? CPU_MODE_USR : cpu_mode,
199212
control_signals.Rp_imm);
200213
end
201214
endcase
@@ -365,6 +378,21 @@ module CPU (
365378
end
366379
end
367380

381+
if (control_signals.exception != EXCEPTION_NONE) begin
382+
`WRITE_SPSR(regs, cpu_mode, regs.CPSR)
383+
384+
regs.user.r15 <= VECTOR_TABLE[control_signals.exception];
385+
386+
regs.CPSR[7] <= 1'b1; // Disable IRQ
387+
388+
regs.CPSR[4:0] <= update_cspr_mode(control_signals.exception);
389+
390+
flush_req <= 1'b1;
391+
392+
$display("Performing CPU exception handling from %0d to %0d", cpu_mode,
393+
control_signals.exception);
394+
end
395+
368396
unique case (control_signals.ALU_writeback)
369397
ALU_WB_NONE: ;
370398
ALU_WB_REG_RD: begin
@@ -374,12 +402,12 @@ module CPU (
374402
ALU_WB_REG_RS: `WRITE_REG(regs, cpu_mode, decoder_bus.word.Rs, alu_bus.result)
375403
ALU_WB_REG_RN: begin
376404
$display("Writing back ALU result %0d to Rn (R%d)", alu_bus.result, decoder_bus.word.Rn);
377-
`WRITE_REG(regs, control_signals.force_user_mode ? MODE_USR : cpu_mode,
405+
`WRITE_REG(regs, control_signals.force_user_mode ? CPU_MODE_USR : cpu_mode,
378406
decoder_bus.word.Rn, alu_bus.result)
379407
end
380408
ALU_WB_REG_14: `WRITE_REG(regs, cpu_mode, 14, alu_bus.result)
381409
ALU_WB_REG_RP: begin
382-
`WRITE_REG(regs, control_signals.force_user_mode ? MODE_USR : cpu_mode,
410+
`WRITE_REG(regs, control_signals.force_user_mode ? CPU_MODE_USR : cpu_mode,
383411
control_signals.Rp_imm, alu_bus.result)
384412
end
385413
endcase

cores/gba/rtl/cpu/ControlUnit.sv

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -894,15 +894,16 @@ module ControlUnit (
894894
ARM_INSTR_BRANCH_LINK: begin
895895
if (cycle == 8'd0) begin
896896
// Rd should be R14 (LR)
897-
control_signals.ALU_writeback = ALU_WB_REG_14;
897+
control_signals.ALU_writeback = ALU_WB_REG_RD;
898898

899899
control_signals.ALU_op = ALU_OP_SUB;
900900
control_signals.A_bus_source = A_BUS_SRC_RN;
901901

902902
control_signals.B_bus_source = B_BUS_SRC_IMM;
903903
control_signals.B_bus_imm = 24'd4;
904904

905-
$display("[ControlUnit] Branch with Link instruction, writing return address to R14");
905+
$display("[ControlUnit] Branch with Link instruction, writing return address to R%0d",
906+
decoder_bus.word.Rd);
906907
end
907908

908909
if (cycle == 8'd1) begin
@@ -923,6 +924,27 @@ module ControlUnit (
923924
control_signals.pipeline_advance = 1'b1;
924925
end
925926
end
927+
928+
ARM_INSTR_SWI: begin
929+
if (cycle == 8'd0) begin
930+
// Rd should be R14 (LR)
931+
control_signals.ALU_writeback = ALU_WB_REG_RD;
932+
933+
control_signals.ALU_op = ALU_OP_SUB;
934+
control_signals.A_bus_source = A_BUS_SRC_RN;
935+
936+
control_signals.B_bus_source = B_BUS_SRC_IMM;
937+
control_signals.B_bus_imm = 24'd4;
938+
939+
control_signals.exception = EXCEPTION_SWI;
940+
941+
$display(
942+
"[ControlUnit] Software Interrupt instruction, writing return address to R%0d and preparing for exception handling",
943+
decoder_bus.word.Rd);
944+
945+
control_signals.pipeline_advance = 1'b1;
946+
end
947+
end
926948
default: ;
927949
endcase
928950
end

cores/gba/rtl/cpu/Decoder.sv

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,14 @@ module Decoder (
9090

9191
/// Software Interrupt
9292
32'b????_1111_????_????_????_????_????_????: begin
93+
// TODO: Decode comments from ARM SWI IR.
94+
95+
bus.word.instr_type = ARM_INSTR_SWI;
96+
97+
// Overwrite Rn and Rd
98+
bus.word.Rn = 4'd15;
99+
bus.word.Rd = 4'd14;
100+
93101
$display("[Decoder] Detected SWI instruction with IR=0x%08x", IR);
94102
end
95103

cores/gba/rtl/cpu/control_types.sv

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,11 @@ package control_types_pkg;
110110
/// TODO: Refactor
111111
logic restore_cpsr_from_spsr;
112112

113+
// TODO: Refactor
114+
set_cpu_mode_t set_mode;
115+
116+
exception_t exception;
117+
113118
// ======================================================
114119
// Shift Bus
115120
// ======================================================

cores/gba/rtl/cpu/types.sv

Lines changed: 88 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ package cpu_types_pkg;
8888
/**
8989
From: https://mgba-emu.github.io/gbatek/#current-program-status-register-cpsr
9090
91+
```plain
9192
Bit Expl.
9293
31 N - Sign Flag (0=Not Signed, 1=Signed) ;\
9394
30 Z - Zero Flag (0=Not Zero, 1=Zero) ; Condition
@@ -99,6 +100,7 @@ package cpu_types_pkg;
99100
6 F - FIQ disable (0=Enable, 1=Disable) ; Control
100101
5 T - State Bit (0=ARM, 1=THUMB) - Do not change manually!; Bits
101102
4-0 M4-M0 - Mode Bits (See below)
103+
```
102104
*/
103105
word_t CPSR;
104106

@@ -112,14 +114,92 @@ package cpu_types_pkg;
112114

113115
} cpu_regs_t;
114116

115-
typedef enum logic [3:0] {
116-
MODE_USR = 4'b0000,
117-
MODE_FIQ = 4'b0001,
118-
MODE_IRQ = 4'b0010,
119-
MODE_SVC = 4'b0011,
120-
MODE_ABT = 4'b0111,
121-
MODE_UND = 4'b1011,
122-
MODE_SYS = 4'b1111
117+
// TODO: figure out priority
118+
typedef enum logic [2:0] {
119+
/// No exception
120+
EXCEPTION_NONE = 3'd0,
121+
122+
/// Reset
123+
EXCEPTION_RESET = 3'd1,
124+
125+
/// Undefined instruction (attempting to execute an undefined / illegal instruction)
126+
EXCEPTION_UNDEFINED = 3'd2,
127+
128+
/// Software Interrupt (SWI)
129+
EXCEPTION_SWI = 3'd3,
130+
131+
/// Prefetch abort (fetching instruction from memory failed)
132+
EXCEPTION_PABT = 3'd4,
133+
134+
/// Data abort (data access from memory failed)
135+
EXCEPTION_DABT = 3'd5,
136+
137+
/// Interrupt Request (IRQ)
138+
EXCEPTION_IRQ = 3'd6,
139+
140+
/// Fast Interrupt Request (FIQ)
141+
EXCEPTION_FIQ = 3'd7
142+
} exception_t;
143+
144+
localparam logic [31:0] VECTOR_TABLE[0:7] = '{
145+
32'hXXXX_XXXX, // NONE (illegal / unused)
146+
32'h0000_0000, // RESET
147+
32'h0000_0004, // UNDEFINED
148+
32'h0000_0008, // SWI
149+
32'h0000_000C, // PREFETCH_ABORT
150+
32'h0000_0010, // DATA_ABORT
151+
32'h0000_0018, // IRQ
152+
32'h0000_001C // FIQ
153+
};
154+
155+
typedef enum logic [2:0] {
156+
157+
SET_CPU_MODE_NONE = 3'b000,
158+
159+
/// User mode (USR)
160+
SET_CPU_MODE_USR,
161+
162+
/// Fast Interrupt Request mode (FIQ)
163+
SET_CPU_MODE_FIQ,
164+
165+
/// Interrupt Request mode (IRQ)
166+
SET_CPU_MODE_IRQ,
167+
168+
/// Supervisor mode (SVC)
169+
SET_CPU_MODE_SVC,
170+
171+
/// Abort mode (ABT)
172+
SET_CPU_MODE_ABT,
173+
174+
/// Undefined mode (UND)
175+
SET_CPU_MODE_UND,
176+
177+
/// System mode (SYS)
178+
SET_CPU_MODE_SYS
179+
} set_cpu_mode_t;
180+
181+
typedef enum logic [2:0] {
182+
183+
/// User mode (USR)
184+
CPU_MODE_USR,
185+
186+
/// Fast Interrupt Request mode (FIQ)
187+
CPU_MODE_FIQ,
188+
189+
/// Interrupt Request mode (IRQ)
190+
CPU_MODE_IRQ,
191+
192+
/// Supervisor mode (SVC)
193+
CPU_MODE_SVC,
194+
195+
/// Abort mode (ABT)
196+
CPU_MODE_ABT,
197+
198+
/// Undefined mode (UND)
199+
CPU_MODE_UND,
200+
201+
/// System mode (SYS)
202+
CPU_MODE_SYS
123203
} cpu_mode_t;
124204

125205
typedef enum logic [1:0] {

0 commit comments

Comments
 (0)