mirror of
https://github.com/mattrberry/crab.git
synced 2025-01-15 03:40:56 +01:00
arm / thumb software interrupts, register banking
This commit is contained in:
parent
49f6d39e84
commit
b401524ea5
5 changed files with 66 additions and 2 deletions
|
@ -21,7 +21,7 @@ module ARM
|
||||||
lut = Slice(Proc(Word, Nil)).new 4096, ->arm_unimplemented(Word)
|
lut = Slice(Proc(Word, Nil)).new 4096, ->arm_unimplemented(Word)
|
||||||
4096.times do |idx|
|
4096.times do |idx|
|
||||||
if idx & 0b111100000000 == 0b111100000000
|
if idx & 0b111100000000 == 0b111100000000
|
||||||
# software interrupt
|
lut[idx] = ->arm_software_interrupt(Word)
|
||||||
elsif idx & 0b111100000001 == 0b111000000001
|
elsif idx & 0b111100000001 == 0b111000000001
|
||||||
# coprocessor register transfer
|
# coprocessor register transfer
|
||||||
elsif idx & 0b111100000001 == 0b111000000001
|
elsif idx & 0b111100000001 == 0b111000000001
|
||||||
|
|
10
src/crab/arm/software_interrupt.cr
Normal file
10
src/crab/arm/software_interrupt.cr
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
module ARM
|
||||||
|
def arm_software_interrupt(instr : Word) : Nil
|
||||||
|
lr = @r[15] - 4
|
||||||
|
switch_mode CPU::Mode::SVC
|
||||||
|
@r[14] = lr
|
||||||
|
@cpsr.irq_disable = true
|
||||||
|
@r[15] = 0x08
|
||||||
|
clear_pipeline
|
||||||
|
end
|
||||||
|
end
|
|
@ -6,6 +6,27 @@ class CPU
|
||||||
include ARM
|
include ARM
|
||||||
include THUMB
|
include THUMB
|
||||||
|
|
||||||
|
enum Mode
|
||||||
|
USR = 0b10000
|
||||||
|
FIQ = 0b10001
|
||||||
|
IRQ = 0b10010
|
||||||
|
SVC = 0b10011
|
||||||
|
ABT = 0b10111
|
||||||
|
UND = 0b11011
|
||||||
|
SYS = 0b11111
|
||||||
|
|
||||||
|
def bank : Int
|
||||||
|
case self
|
||||||
|
in Mode::USR, Mode::SYS then 0 # todo maybe some cpsr bits can't be changed in user mode?
|
||||||
|
in Mode::FIQ then 1
|
||||||
|
in Mode::IRQ then 2
|
||||||
|
in Mode::SVC then 3
|
||||||
|
in Mode::ABT then 4
|
||||||
|
in Mode::UND then 5
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
class PSR < BitField(UInt32)
|
class PSR < BitField(UInt32)
|
||||||
bool negative
|
bool negative
|
||||||
bool zero
|
bool zero
|
||||||
|
@ -23,6 +44,7 @@ class CPU
|
||||||
@pipeline = Pipeline.new
|
@pipeline = Pipeline.new
|
||||||
getter lut : Slice(Proc(Word, Nil)) { fill_lut }
|
getter lut : Slice(Proc(Word, Nil)) { fill_lut }
|
||||||
getter thumb_lut : Slice(Proc(Word, Nil)) { fill_thumb_lut }
|
getter thumb_lut : Slice(Proc(Word, Nil)) { fill_thumb_lut }
|
||||||
|
@reg_banks = Array(Array(Word)).new 6 { Array(Word).new 8, 0 }
|
||||||
|
|
||||||
def initialize(@gba : GBA)
|
def initialize(@gba : GBA)
|
||||||
@r[0] = 0x08000000
|
@r[0] = 0x08000000
|
||||||
|
@ -32,6 +54,27 @@ class CPU
|
||||||
@cpsr = PSR.new 0x6000001F
|
@cpsr = PSR.new 0x6000001F
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def switch_mode(new_mode : Mode) : Nil
|
||||||
|
old_mode = Mode.from_value @cpsr.mode
|
||||||
|
return if new_mode == old_mode
|
||||||
|
new_bank = new_mode.bank
|
||||||
|
old_bank = old_mode.bank
|
||||||
|
if new_mode == Mode::FIQ || old_mode == Mode::FIQ
|
||||||
|
5.times do |idx|
|
||||||
|
@reg_banks[old_bank][idx] = @r[8 + idx]
|
||||||
|
@r[8 + idx] = @reg_banks[new_bank][idx]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
# store old regs
|
||||||
|
@reg_banks[old_bank][5] = @r[13]
|
||||||
|
@reg_banks[old_bank][6] = @r[14]
|
||||||
|
@reg_banks[old_bank][7] = @cpsr.value
|
||||||
|
# load new regs
|
||||||
|
@r[13] = @reg_banks[new_bank][5]
|
||||||
|
@r[14] = @reg_banks[new_bank][6]
|
||||||
|
@cpsr.value = @reg_banks[new_bank][7]
|
||||||
|
end
|
||||||
|
|
||||||
def fill_pipeline : Nil
|
def fill_pipeline : Nil
|
||||||
while @pipeline.size < 2
|
while @pipeline.size < 2
|
||||||
if @cpsr.thumb
|
if @cpsr.thumb
|
||||||
|
|
11
src/crab/thumb/software_interrupt.cr
Normal file
11
src/crab/thumb/software_interrupt.cr
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
module THUMB
|
||||||
|
def thumb_software_interrupt(instr : Word) : Nil
|
||||||
|
lr = @r[15] - 4
|
||||||
|
switch_mode CPU::Mode::SVC
|
||||||
|
@r[14] = lr
|
||||||
|
@cpsr.irq_disable = true
|
||||||
|
@cpsr.thumb = false
|
||||||
|
@r[15] = 0x08
|
||||||
|
clear_pipeline
|
||||||
|
end
|
||||||
|
end
|
|
@ -11,7 +11,7 @@ module THUMB
|
||||||
elsif idx & 0b11111000 == 0b11100000
|
elsif idx & 0b11111000 == 0b11100000
|
||||||
lut[idx] = ->thumb_unconditional_branch(Word)
|
lut[idx] = ->thumb_unconditional_branch(Word)
|
||||||
elsif idx & 0b11111111 == 0b11011111
|
elsif idx & 0b11111111 == 0b11011111
|
||||||
# software interrupt
|
lut[idx] = ->thumb_software_interrupt(Word)
|
||||||
elsif idx & 0b11110000 == 0b11010000
|
elsif idx & 0b11110000 == 0b11010000
|
||||||
lut[idx] = ->thumb_conditional_branch(Word)
|
lut[idx] = ->thumb_conditional_branch(Word)
|
||||||
elsif idx & 0b11110000 == 0b11000000
|
elsif idx & 0b11110000 == 0b11000000
|
||||||
|
|
Loading…
Reference in a new issue