1
0
mirror of https://github.com/hsoft/collapseos.git synced 2024-11-02 16:30:57 +11:00

Compare commits

...

4 Commits

Author SHA1 Message Date
Virgil Dupras
2652c81519 avra: make CLR work properly 2019-12-15 16:43:32 -05:00
Virgil Dupras
20861767e6 avra: generalize arg swapping behavior 2019-12-15 16:36:43 -05:00
Virgil Dupras
14fbfa2967 avra: small _parseArgs refactoring
Take argspec pairs directly as an argument instead of taking a
pointer to an argspec pair.
2019-12-15 16:25:16 -05:00
Virgil Dupras
62eb5589c3 avra: refactor instruction tbl
The instruction table is now beefier and has redundant data, but
this simplifies processing. This should simplify upcoming work.
2019-12-15 15:53:28 -05:00
3 changed files with 166 additions and 149 deletions

View File

@ -31,7 +31,7 @@ instrNames:
.equ I_BRBS 16 .equ I_BRBS 16
.db "BRBS", 0 .db "BRBS", 0
.db "BRBC", 0 .db "BRBC", 0
; Rd(5) + Rr(5) (from here, instrUpMasks1) ; Rd(5) + Rr(5) (from here, instrTbl8)
.equ I_ADC 18 .equ I_ADC 18
.db "ADC", 0 .db "ADC", 0
.db "ADD", 0 .db "ADD", 0
@ -66,7 +66,7 @@ instrNames:
.db "IN", 0 .db "IN", 0
.equ I_OUT 45 .equ I_OUT 45
.db "OUT", 0 .db "OUT", 0
; no arg (from here, instrUpMasks2) ; no arg (from here, instrTbl16)
.equ I_BREAK 46 .equ I_BREAK 46
.db "BREAK", 0 .db "BREAK", 0
.db "CLC", 0 .db "CLC", 0
@ -112,90 +112,104 @@ instrNames:
.db "XCH", 0 .db "XCH", 0
.db 0xff .db 0xff
; Instruction table
;
; A table row starts with the "argspecs+flags" byte, followed by two upcode
; bytes.
;
; The argspecs+flags byte is separated in two nibbles: Low nibble is a 4bit
; index (1-based, 0 means no arg) in the argSpecs table. High nibble is for
; flags. Meaning:
;
; Bit 7: Arguments swapped. For example, if we have this bit set on the argspec
; row 'A', 'R', then what will actually be read is 'R', 'A'. The
; arguments destination will be, hum, de-swapped, that is, 'A' is going
; in H and 'R' is going in L. This is used, for example, with IN and OUT.
; IN has a Rd(5), A(6) signature. OUT could have the same signature, but
; AVR's mnemonics has those args reversed for more consistency
; (destination is always the first arg). The goal of this flag is to
; allow this kind of syntactic sugar with minimal complexity.
;
; Bit 6: Second arg is a copy of the first
; 8-bit constant masks associated with each instruction. In the same order as ; In the same order as in instrNames
; in instrNames instrTbl:
instrUpMasks1:
; Rd(5) + Rd(5): XXXXXXrd ddddrrrr ; Rd(5) + Rd(5): XXXXXXrd ddddrrrr
.db 0b00011100 ; ADC .db 0x02, 0b00011100, 0x00 ; ADC
.db 0b00001100 ; ADD .db 0x02, 0b00001100, 0x00 ; ADD
.db 0b00100000 ; AND .db 0x02, 0b00100000, 0x00 ; AND
.db 0b00100100 ; CLR .db 0x41, 0b00100100, 0x00 ; CLR (Rr copies Rd)
.db 0b00010100 ; CP .db 0x02, 0b00010100, 0x00 ; CP
.db 0b00000100 ; CPC .db 0x02, 0b00000100, 0x00 ; CPC
.db 0b00010000 ; CPSE .db 0x02, 0b00010000, 0x00 ; CPSE
.db 0b00100100 ; EOR .db 0x02, 0b00100100, 0x00 ; EOR
.db 0b00101100 ; MOV .db 0x02, 0b00101100, 0x00 ; MOV
.db 0b10011100 ; MUL .db 0x02, 0b10011100, 0x00 ; MUL
.db 0b00101000 ; OR .db 0x02, 0b00101000, 0x00 ; OR
.db 0b00001000 ; SBC .db 0x02, 0b00001000, 0x00 ; SBC
.db 0b00011000 ; SUB .db 0x02, 0b00011000, 0x00 ; SUB
; Rd(4) + K(8): XXXXKKKK ddddKKKK ; Rd(4) + K(8): XXXXKKKK ddddKKKK
.db 0b01110000 ; ANDI .db 0x04, 0b01110000, 0x00 ; ANDI
.db 0b00110000 ; CPI .db 0x04, 0b00110000, 0x00 ; CPI
.db 0b11100000 ; LDI .db 0x04, 0b11100000, 0x00 ; LDI
.db 0b01100000 ; ORI .db 0x04, 0b01100000, 0x00 ; ORI
.db 0b01000000 ; SBCI .db 0x04, 0b01000000, 0x00 ; SBCI
.db 0b01100000 ; SBR .db 0x04, 0b01100000, 0x00 ; SBR
.db 0b01010000 ; SUBI .db 0x04, 0b01010000, 0x00 ; SUBI
; Rd(5) + bit: XXXXXXXd ddddXbbb: lonely bit in LSB is 0 in all cases, so we ; Rd(5) + bit: XXXXXXXd ddddXbbb: lonely bit in LSB is 0 in all cases, so we
; ignore it. ; ignore it.
.db 0b11111000 ; BLD .db 0x05, 0b11111000, 0x00 ; BLD
.db 0b11111010 ; BST .db 0x05, 0b11111010, 0x00 ; BST
.db 0b11111100 ; SBRC .db 0x05, 0b11111100, 0x00 ; SBRC
.db 0b11111110 ; SBRS .db 0x05, 0b11111110, 0x00 ; SBRS
; k(12): XXXXkkkk kkkkkkkk ; k(12): XXXXkkkk kkkkkkkk
.db 0b11010000 ; RCALL .db 0x00, 0b11010000, 0x00 ; RCALL
.db 0b11000000 ; RJMP .db 0x00, 0b11000000, 0x00 ; RJMP
; IN and OUT ; IN and OUT
.db 0b10110000 ; IN .db 0x07, 0b10110000, 0x00 ; IN
.db 0b10111000 ; OUT .db 0x87, 0b10111000, 0x00 ; OUT (args reversed)
; 16-bit constant masks associated with each instruction. In the same order as
; in instrNames
instrUpMasks2:
; no arg ; no arg
.db 0b10010101, 0b10011000 ; BREAK .db 0x00, 0b10010101, 0b10011000 ; BREAK
.db 0b10010100, 0b10001000 ; CLC .db 0x00, 0b10010100, 0b10001000 ; CLC
.db 0b10010100, 0b11011000 ; CLH .db 0x00, 0b10010100, 0b11011000 ; CLH
.db 0b10010100, 0b11111000 ; CLI .db 0x00, 0b10010100, 0b11111000 ; CLI
.db 0b10010100, 0b10101000 ; CLN .db 0x00, 0b10010100, 0b10101000 ; CLN
.db 0b10010100, 0b11001000 ; CLS .db 0x00, 0b10010100, 0b11001000 ; CLS
.db 0b10010100, 0b11101000 ; CLT .db 0x00, 0b10010100, 0b11101000 ; CLT
.db 0b10010100, 0b10111000 ; CLV .db 0x00, 0b10010100, 0b10111000 ; CLV
.db 0b10010100, 0b10011000 ; CLZ .db 0x00, 0b10010100, 0b10011000 ; CLZ
.db 0b10010101, 0b00011001 ; EICALL .db 0x00, 0b10010101, 0b00011001 ; EICALL
.db 0b10010100, 0b00011001 ; EIJMP .db 0x00, 0b10010100, 0b00011001 ; EIJMP
.db 0b10010101, 0b00001001 ; ICALL .db 0x00, 0b10010101, 0b00001001 ; ICALL
.db 0b10010100, 0b00001001 ; IJMP .db 0x00, 0b10010100, 0b00001001 ; IJMP
.db 0b00000000, 0b00000000 ; NOP .db 0x00, 0b00000000, 0b00000000 ; NOP
.db 0b10010101, 0b00001000 ; RET .db 0x00, 0b10010101, 0b00001000 ; RET
.db 0b10010101, 0b00011000 ; RETI .db 0x00, 0b10010101, 0b00011000 ; RETI
.db 0b10010100, 0b00001000 ; SEC .db 0x00, 0b10010100, 0b00001000 ; SEC
.db 0b10010100, 0b01011000 ; SEH .db 0x00, 0b10010100, 0b01011000 ; SEH
.db 0b10010100, 0b01111000 ; SEI .db 0x00, 0b10010100, 0b01111000 ; SEI
.db 0b10010100, 0b00101000 ; SEN .db 0x00, 0b10010100, 0b00101000 ; SEN
.db 0b10010100, 0b01001000 ; SES .db 0x00, 0b10010100, 0b01001000 ; SES
.db 0b10010100, 0b01101000 ; SET .db 0x00, 0b10010100, 0b01101000 ; SET
.db 0b10010100, 0b00111000 ; SEV .db 0x00, 0b10010100, 0b00111000 ; SEV
.db 0b10010100, 0b00011000 ; SEZ .db 0x00, 0b10010100, 0b00011000 ; SEZ
.db 0b10010101, 0b10001000 ; SLEEP .db 0x00, 0b10010101, 0b10001000 ; SLEEP
.db 0b10010101, 0b10101000 ; WDR .db 0x00, 0b10010101, 0b10101000 ; WDR
; Rd(5): XXXXXXXd ddddXXXX ; Rd(5): XXXXXXXd ddddXXXX
.db 0b10010100, 0b00000101 ; ASR .db 0x01, 0b10010100, 0b00000101 ; ASR
.db 0b10010100, 0b00000000 ; COM .db 0x01, 0b10010100, 0b00000000 ; COM
.db 0b10010100, 0b00001010 ; DEC .db 0x01, 0b10010100, 0b00001010 ; DEC
.db 0b10010100, 0b00000011 ; INC .db 0x01, 0b10010100, 0b00000011 ; INC
.db 0b10010010, 0b00000110 ; LAC .db 0x01, 0b10010010, 0b00000110 ; LAC
.db 0b10010010, 0b00000101 ; LAS .db 0x01, 0b10010010, 0b00000101 ; LAS
.db 0b10010010, 0b00000111 ; LAT .db 0x01, 0b10010010, 0b00000111 ; LAT
.db 0b10010100, 0b00000110 ; LSR .db 0x01, 0b10010100, 0b00000110 ; LSR
.db 0b10010100, 0b00000001 ; NEG .db 0x01, 0b10010100, 0b00000001 ; NEG
.db 0b10010000, 0b00001111 ; POP .db 0x01, 0b10010000, 0b00001111 ; POP
.db 0b10010010, 0b00001111 ; PUSH .db 0x01, 0b10010010, 0b00001111 ; PUSH
.db 0b10010100, 0b00000111 ; ROR .db 0x01, 0b10010100, 0b00000111 ; ROR
.db 0b10010100, 0b00000010 ; SWAP .db 0x01, 0b10010100, 0b00000010 ; SWAP
.db 0b10010010, 0b00000100 ; XCH .db 0x01, 0b10010010, 0b00000100 ; XCH
; Same signature as getInstID in instr.asm ; Same signature as getInstID in instr.asm
; Reads string in (HL) and returns the corresponding ID (I_*) in A. Sets Z if ; Reads string in (HL) and returns the corresponding ID (I_*) in A. Sets Z if
@ -233,13 +247,55 @@ getInstID:
; resulting opcode(s) in I/O. ; resulting opcode(s) in I/O.
; Sets Z on success. On error, A contains an error code (ERR_*) ; Sets Z on success. On error, A contains an error code (ERR_*)
parseInstruction: parseInstruction:
; BC, during .spit, is ORred to the spitted opcode. ; *** Step 1: initialization
; Except setting up our registers, we also check if our index < I_ADC.
; If we are, we skip regular processing for the .BR processing, which
; is a bit special.
; During this processing, BC is used as the "upcode WIP" register. It's
; there that we send our partial values until they're ready to spit to
; I/O.
ld bc, 0 ld bc, 0
; Save Instr ID in D, which is less volatile than A. In almost all ld e, a ; Let's keep that instrID somewhere safe
; cases, we fetch the opcode constant at the end of the processing. ; First, let's fetch our table row
ld d, a
cp I_ADC cp I_ADC
jp c, .BR jp c, .BR ; BR is special, no table row
; *** Step 2: parse arguments
sub I_ADC ; Adjust index for table
; Our row is at instrTbl + (A * 3)
ld hl, instrTbl
call addHL
sla a ; A * 2
call addHL ; (HL) is our row
ld a, (hl)
push hl \ pop ix ; IX is now our tblrow
ld hl, 0
or a
jr z, .noarg
and 0xf ; lower nibble
dec a ; argspec index is 1-based
ld hl, argSpecs
sla a ; A * 2
call addHL ; (HL) is argspec row
ld d, (hl)
inc hl
ld a, (hl)
ld h, d
ld l, a ; H and L contain specs now
bit 7, (ix)
call nz, .swapHL ; Bit 7 set, swap H and L
call _parseArgs
ret nz
.noarg:
; *** Step 3: place arguments in binary upcode and spit.
; (IX) is table row
; Parse arg values now in H and L
; InstrID is E
bit 7, (ix)
call nz, .swapHL ; Bit 7 set, swap H and L again!
bit 6, (ix)
call nz, .cpHintoL ; Bit 6 set, copy H into L
ld a, e ; InstrID
cp I_ANDI cp I_ANDI
jr c, .spitRd5Rr5 jr c, .spitRd5Rr5
cp I_BLD cp I_BLD
@ -248,25 +304,15 @@ parseInstruction:
jr c, .spitRdBit jr c, .spitRdBit
cp I_IN cp I_IN
jr c, .spitK12 jr c, .spitK12
jp z, .spitIN cp I_BREAK
cp I_OUT jp c, .spitINOUT
jp z, .spitOUT
cp I_ASR cp I_ASR
jr c, .spitNoArg jp c, .spit ; no arg
; spitRd5 ; spitRd5
ld ix, argSpecs ; 'R', 0
call _parseArgs
ld a, h ld a, h
call .placeRd call .placeRd
; continue to .spitNoArg
.spitNoArg:
call .getUp2
jp .spit jp .spit
.spitRd5Rr5: .spitRd5Rr5:
ld ix, argSpecs+2 ; 'R', 'R'
call _parseArgs
ret nz
ld a, h ld a, h
call .placeRd call .placeRd
ld a, l ld a, l
@ -281,14 +327,9 @@ parseInstruction:
rra \ rra \ rra rra \ rra \ rra
or b or b
ld b, a ld b, a
call .getUp1
; now that's our MSB
jp .spitMSB jp .spitMSB
.spitRdK8: .spitRdK8:
ld ix, argSpecs+6 ; 'r', 8
call _parseArgs
ret nz
ld a, h ; Rd ld a, h ; Rd
call .placeRd call .placeRd
ld a, l ; K ld a, l ; K
@ -302,25 +343,19 @@ parseInstruction:
and 0xf0 and 0xf0
rra \ rra \ rra \ rra rra \ rra \ rra \ rra
ld b, a ld b, a
call .getUp1
jp .spitMSB jp .spitMSB
.spitRdBit: .spitRdBit:
ld ix, argSpecs+8 ; 'R', 'b'
call _parseArgs
ret nz
ld a, h ld a, h
call .placeRd call .placeRd
or l or l
; LSB is in A and is ready to go ; LSB is in A and is ready to go
call ioPutB call ioPutB
call .getUp1
jr .spitMSB jr .spitMSB
.spitK12: .spitK12:
; Let's deal with the upcode constant before we destroy DE below ; Let's deal with the upcode constant before we destroy IX below
call .getUp1 ld b, (ix+1)
ld b, (hl)
call readWord call readWord
call parseExpr call parseExpr
ret nz ret nz
@ -347,18 +382,6 @@ parseInstruction:
or b or b
jp ioPutB jp ioPutB
.spitOUT:
ld ix, argSpecs+12 ; 'A', 'R'
call _parseArgs
ret nz
ld a, h
ld h, l
ld l, a
jr .spitINOUT
.spitIN:
ld ix, argSpecs+14 ; 'R', 'A'
call _parseArgs
ret nz
.spitINOUT: .spitINOUT:
; Rd in H, A in L ; Rd in H, A in L
ld a, h ld a, h
@ -374,18 +397,14 @@ parseInstruction:
and 0b110 and 0b110
or b or b
ld b, a ld b, a
; MSB is almost ready
call .getUp1
jr .spitMSB jr .spitMSB
.spit: .spit:
; LSB is spit *before* MSB ; LSB is spit *before* MSB
inc hl ld a, (ix+2)
ld a, (hl)
or c or c
call ioPutB call ioPutB
dec hl
.spitMSB: .spitMSB:
ld a, (hl) ld a, (ix+1)
or b or b
call ioPutB call ioPutB
xor a ; ensure Z, set success xor a ; ensure Z, set success
@ -410,7 +429,8 @@ parseInstruction:
.skip1: .skip1:
and 0b111 and 0b111
ld c, a ; can't store in H now, (HL) is used ld c, a ; can't store in H now, (HL) is used
ld ix, argSpecs+4 ; 7, 0 ld h, 7
ld l, 0
call _parseArgs call _parseArgs
ret nz ret nz
; ok, now we can ; ok, now we can
@ -436,7 +456,8 @@ parseInstruction:
; upcode becomes 0b111101 ; upcode becomes 0b111101
inc b inc b
.rdBRBS: .rdBRBS:
ld ix, argSpecs+10 ; bit + k(7) ld h, 'b'
ld l, 7
call _parseArgs call _parseArgs
ret nz ret nz
; bit in H, k in L. ; bit in H, k in L.
@ -451,20 +472,15 @@ parseInstruction:
ld c, a ld c, a
ret ret
; Fetch a 8-bit upcode specified by instr index in D and set that upcode in HL .swapHL:
.getUp1: ld a, h
ld a, d ld h, l
sub I_ADC ld l, a
ld hl, instrUpMasks1 ret
jp addHL
; Fetch a 16-bit upcode specified by instr index in D and set that upcode in HL .cpHintoL:
.getUp2: ld l, h
ld a, d ret
sub I_BREAK
sla a ; A * 2
ld hl, instrUpMasks2
jp addHL
; Argspecs: two bytes describing the arguments that are accepted. Possible ; Argspecs: two bytes describing the arguments that are accepted. Possible
; values: ; values:
@ -489,11 +505,11 @@ argSpecs:
.db 'r', 8 ; Rd(4) + K(8) .db 'r', 8 ; Rd(4) + K(8)
.db 'R', 'b' ; Rd(5) + bit .db 'R', 'b' ; Rd(5) + bit
.db 'b', 7 ; bit + k(7) .db 'b', 7 ; bit + k(7)
.db 'A', 'R' ; A(6) + Rr(5)
.db 'R', 'A' ; Rd(5) + A(6) .db 'R', 'A' ; Rd(5) + A(6)
; Parse arguments in (HL) according to specs in IX ; Parse arguments from I/O according to specs in HL
; Puts the results in HL (which is not needed anymore after the parsing). ; H for first spec, L for second spec
; Puts the results in HL
; First arg in H, second in L. ; First arg in H, second in L.
; This routine is not used in all cases, some ops don't fit this pattern well ; This routine is not used in all cases, some ops don't fit this pattern well
; and thus parse their args themselves. ; and thus parse their args themselves.
@ -502,20 +518,21 @@ _parseArgs:
; For the duration of the routine, our final value will be in DE, and ; For the duration of the routine, our final value will be in DE, and
; then placed in HL at the end. ; then placed in HL at the end.
push de push de
ex de, hl ; argspecs now in DE
call readWord call readWord
jr nz, .end jr nz, .end
ld a, (ix) ld a, d
call .parse call .parse
jr nz, .end jr nz, .end
ld d, a ld d, a
ld a, (ix+1) ld a, e
or a or a
jr z, .end ; no arg jr z, .end ; no arg
call readComma call readComma
jr nz, .end jr nz, .end
call readWord call readWord
jr nz, .end jr nz, .end
ld a, (ix+1) ld a, e
call .parse call .parse
jr nz, .end jr nz, .end
; we're done with (HL) now ; we're done with (HL) now

View File

@ -25,7 +25,7 @@ main:
ori r16, 0x05 ; CS00 + CS02 = 1024 prescaler ori r16, 0x05 ; CS00 + CS02 = 1024 prescaler
out TCCR0B, r16 out TCCR0B, r16
;clr r1 clr r1
loop: loop:
in r16, TIFR ; TIFR0 in r16, TIFR ; TIFR0

View File

@ -1 +1 @@
å ¿à¿·`¿·ýÐüÏà¿þ å ¿à¿·`¿$·ýÐüÏà¿þ